From da88ce18fcda0f28a068abbf24977b6b0ae51c42 Mon Sep 17 00:00:00 2001 From: jkauttio Date: Thu, 24 Oct 2013 06:51:40 +0000 Subject: [PATCH] Add experimental support for the new solver, which can be enabled by setting an option in the preferences and reloading the experiment. It should be noted that most of the experiment framework is reworked (and refactored) to remove references to openmodelica and provide support for the new solver. This means that the new experiment framework does not yet have all the features of the old experiment framework, and some of the existing features might not work as expected if the experimental solver support is enabled in the preferences. refs #4488 git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@28109 ac1ea38d-2e2b-0410-8846-a27921b304fc --- .../org/simantics/modelica/InitWriter.java | 6 +- .../org/simantics/modelica/ModelicaKeys.java | 20 +- .../simantics/modelica/ModelicaManager.java | 1555 ++++++++--------- .../modelica/SimulationLocation.java | 121 +- .../ModelicaPreferenceInitializer.java | 58 +- .../preferences/OpenModelicaPreferences.java | 2 +- .../modelica/reader/MatFileReader.java | 82 +- .../modelica/reader/ResultFileReader.java | 19 +- org.simantics.sysdyn.feature/feature.xml | 13 +- org.simantics.sysdyn.ui/plugin.xml | 5 + .../ui/modelica/SysdynModelicaEditor.java | 18 +- .../preferences/ModelicaPreferencePage.java | 273 ++- .../ui/preferences/SolverPreferencePage.java | 37 + org.simantics.sysdyn.ui/sysdyn.product | 4 +- org.simantics.sysdyn/META-INF/MANIFEST.MF | 4 +- .../sysdyn/manager/FunctionUtils.java | 251 ++- .../sysdyn/manager/MemoryResult.java | 7 +- .../sysdyn/manager/OldSysdynExperiment.java | 874 +++++++++ .../sysdyn/manager/SaveResultJob.java | 6 +- .../sysdyn/manager/SaveResultSetJob.java | 4 +- .../sysdyn/manager/SysdynConsole.java | 7 +- .../sysdyn/manager/SysdynExperiment.java | 1280 +++++--------- .../sysdyn/manager/SysdynGameExperiment.java | 13 +- .../simantics/sysdyn/manager/SysdynModel.java | 39 +- .../sysdyn/manager/SysdynModelManager.java | 2 - .../manager/SysdynPlaybackExperiment.java | 3 +- .../SysdynSensitivityAnalysisExperiment.java | 16 +- .../sysdyn/simulation/SimulationJob.java | 10 +- .../simulation/SimulationScheduler.java | 8 +- .../org/simantics/sysdyn/solver/ISolver.java | 12 + .../sysdyn/solver/ISolverMonitor.java | 9 + .../sysdyn/solver/InternalSolver.java | 150 ++ .../sysdyn/solver/InternalSolverResult.java | 29 + .../sysdyn/solver/SimulationJob.java | 32 + .../sysdyn/solver/SolverParameters.java | 13 + .../sysdyn/solver/SolverSettings.java | 34 + 36 files changed, 2835 insertions(+), 2181 deletions(-) create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/preferences/SolverPreferencePage.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/manager/OldSysdynExperiment.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/solver/ISolver.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/solver/ISolverMonitor.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolver.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolverResult.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SimulationJob.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SolverParameters.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SolverSettings.java diff --git a/org.simantics.modelica/src/org/simantics/modelica/InitWriter.java b/org.simantics.modelica/src/org/simantics/modelica/InitWriter.java index 6b90a2f9..e7dee74d 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/InitWriter.java +++ b/org.simantics.modelica/src/org/simantics/modelica/InitWriter.java @@ -30,8 +30,8 @@ import org.xml.sax.SAXException; /** * Class to change values of parameters in modelica init.xml files + * * @author tlteemu - * */ public class InitWriter { @@ -44,9 +44,7 @@ public class InitWriter { public static boolean writeXML(String file, HashMap inits) { Document doc; try { - doc = DocumentBuilderFactory.newInstance() - .newDocumentBuilder().parse(new InputSource(file)); - + doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(file)); // Locate the node(s) XPath xpath = XPathFactory.newInstance().newXPath(); diff --git a/org.simantics.modelica/src/org/simantics/modelica/ModelicaKeys.java b/org.simantics.modelica/src/org/simantics/modelica/ModelicaKeys.java index 466f5918..d867fe83 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/ModelicaKeys.java +++ b/org.simantics.modelica/src/org/simantics/modelica/ModelicaKeys.java @@ -13,19 +13,19 @@ package org.simantics.modelica; /** * Keys used by modelica to control simulations + * * @author Teemu Lempinen - * */ public class ModelicaKeys { - public static String START_VALUE = "startTime"; - public static String STOP_VALUE = "stopTime"; - public static String OUTPUT_FORMAT = "outputFormat"; - public static String STEP_VALUE = "stepSize"; - public static String NUMBER_OF_INTERVALS = "numberOfIntervals"; - public static String METHOD = "method"; - public static String TOLERANCE = "tolerance"; - public static String VARIABLE_FILTER = "variableFilter"; - public static String OUTPUT_INTERVAL = "outputInterval"; + public static String START_VALUE = "startTime"; + public static String STOP_VALUE = "stopTime"; + public static String OUTPUT_FORMAT = "outputFormat"; + public static String STEP_VALUE = "stepSize"; + public static String NUMBER_OF_INTERVALS = "numberOfIntervals"; + public static String METHOD = "method"; + public static String TOLERANCE = "tolerance"; + public static String VARIABLE_FILTER = "variableFilter"; + public static String OUTPUT_INTERVAL = "outputInterval"; } diff --git a/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java b/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java index a9535e73..5df32f8a 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java +++ b/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java @@ -22,9 +22,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintStream; -import java.io.Reader; -import java.net.URL; -import java.net.URLDecoder; +import java.io.StringReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -47,7 +45,6 @@ import javax.xml.xpath.XPathFactory; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.preferences.ConfigurationScope; -import org.eclipse.core.runtime.preferences.IScopeContext; import org.osgi.framework.Bundle; import org.osgi.service.prefs.Preferences; import org.simantics.modelica.preferences.OpenModelicaPreferences; @@ -60,813 +57,753 @@ import org.xml.sax.SAXException; * Manager for OpenModelica compiler * * @author Teemu Lempinen - * + * @author Janne Kauttio */ public class ModelicaManager { - - private static String builtInOMVersion = "1.9.0"; - - public enum OSType { - APPLE, LINUX, SUN, WINDOWS, UNKNOWN - } - - public static String OMC_VERSION = "OMC_VERSION"; - public static String RESULT_FILE_NAME = "RESULT_FILE_NAME"; - - /** - * Get operating system type - * @return OSType - */ - public static OSType calculateOS() { - String osName = System.getProperty("os.name"); - assert osName != null; - osName = osName.toLowerCase(); - if (osName.startsWith("mac os x")) - return OSType.APPLE; - if (osName.startsWith("windows")) - return OSType.WINDOWS; - if (osName.startsWith("linux")) - return OSType.LINUX; - if (osName.startsWith("sun")) - return OSType.SUN; - return OSType.UNKNOWN; - } - - /** - * Get modelica home folder. If modelica is installed, - * modelica home is in OPENMODELICAHOME environment variable. - * Otherwise it can be obtained from a bundled plugin. - * @return - */ - public static File getModelicaHome() { - - // Try preferences - IScopeContext context = ConfigurationScope.INSTANCE; - Preferences node = context.getNode(Activator.PLUGIN_ID); - String omHomePath = node.get(OpenModelicaPreferences.OM_HOME, null); - if(omHomePath != null) { - File omHome = new File(omHomePath); - if(omHome != null && omHome.isDirectory()) - return omHome; - } - - return getDefaultModelicaHome(); - } - - public static File getDefaultModelicaHome() { - // Get operating system - OSType os = calculateOS(); - - // Try built-in OpenModelica for windows - if(os.equals(OSType.WINDOWS)) { - File builtin = getBuiltinOpenModelicaHome(); - if(builtin != null) - return builtin; - } - - // Try to find installed openModelica - File omhome = getInstalledOpenModelicaHome(); - if(omhome != null) - return omhome; - - // OS was not windows or built-in OpenModelica did not work - switch (os) { - case APPLE: - case LINUX: - case SUN: - return new File("/usr/bin/omc"); - case WINDOWS: - return new File("c:/OpenModelica" + builtInOMVersion); - default: - throw new UnsatisfiedLinkError("Unsupported operating system: " + os); - } - } - - public static File getInstalledOpenModelicaHome() { - String dir = System.getenv("OPENMODELICAHOME"); - if(dir != null) { - File omhome = new File(dir); - if(omhome.isDirectory()) - return omhome; - } - return null; - } - - public static File getBuiltinOpenModelicaHome() { - Bundle bundle = Platform.getBundle("org.simantics.openmodelica.win32"); - if (bundle != null) { - try{ - URL entry = bundle.getEntry("/"); - if(entry != null) { - URL fileURL = FileLocator.toFileURL(entry); - File root = new File( URLDecoder.decode(fileURL.getPath(), "UTF-8") ); - File f = new File(root, "OpenModelica" + builtInOMVersion); - return f; - } - } - catch (Exception e) { - e.printStackTrace(); - } - } - return null; - } - - - public static String getOMCVersion(File OMHome) throws IOException { - ArrayList parameters = new ArrayList(); - parameters.add(new File(OMHome, "/bin/omc").getAbsolutePath()); - parameters.add("++v"); - - // Create the build process - ProcessBuilder processBuilder = new ProcessBuilder(parameters) - .redirectErrorStream(true); - - Map env = processBuilder.environment(); - env.put("OPENMODELICAHOME", OMHome.getAbsolutePath()); - - // Start the building process - Process process = processBuilder.start(); - - // Print process output - String output = getProcessOutput(process); - - return output; - } - - /** - * Gets the whole process output in one string - * @param process Process - * @return process output - */ - public static String getProcessOutput(final Process process) { - try { - InputStream lsOut = process.getInputStream(); - InputStreamReader r = new InputStreamReader(lsOut); - BufferedReader in = new BufferedReader(r); - StringBuilder output = new StringBuilder(); - String line; - boolean first = true; - while ((line = in.readLine()) != null) { - if(!first) - output.append(System.getProperty("line.separator")); - first = false; - - output.append(line); - } - return output.toString(); - } catch (Exception e) { // exception thrown - System.err.println("getProcessOutput failed!"); - return null; - } - } - - - - /** - * Prints the output of an ongoing process to IModelicaMonitor. - * @param process Process - * @param monitor IModelicaMonitor - */ - public static void printProcessOutput(final Process process, final IModelicaMonitor monitor) { - Thread thread = new Thread() { - @Override - public void run() { - InputStream stream = process.getInputStream(); - StringBuilder b = new StringBuilder(); - while(true) { - try { - int c; - - c = stream.read(); - - if(c <= 0) - break; - if(monitor != null) { - if((char)c != '\n') - b.append((char)c); - else { - System.out.println("OMC output: " + b.toString()); - String message = b.toString(); - message = message.trim(); - if(message.startsWith("\"")) - message = message.substring(1); - - monitor.message(message); - b.delete(0, b.length()); - } - } - } catch (IOException e) { - System.err.println("Not able to read simulation output"); - e.printStackTrace(); - break; - } - } - } - }; - thread.run(); - - } - - /** - * Create input files for omc - * - * @param simulationDir Directory of the model - * @param modelName Model's name - * @param modelText Modelica code of the model - * @param inits Map containing initial values for omc - * @param additionalScript Additional script to be written in .mos script file - * @return SimulationLocation - * @throws IOException - */ - public static SimulationLocation createSimulationFiles(File simulationDir, String modelName, String modelText, HashMap inits, String additionalScript, boolean fmu) throws IOException { - System.out.println(simulationDir.getAbsolutePath()); - modelName = modelName.replace(" ", ""); - File modelFile = new File(simulationDir, modelName + ".mo"); - File scriptFile = new File(simulationDir, modelName + ".mos"); - File fullModelDir = new File(simulationDir, "fullModel"); - if(!fullModelDir.exists()) - fullModelDir.mkdir(); - - File fullModelScriptFile = new File(fullModelDir, modelName + "_full.mos"); - String outputFormat = inits.containsKey(ModelicaKeys.OUTPUT_FORMAT) ? inits.get(ModelicaKeys.OUTPUT_FORMAT) : "mat"; - { - PrintStream s = new PrintStream(modelFile); - s.print(modelText); - s.close(); - } - - - String suffix; - if(fmu) { - writeFMUScriptFile(scriptFile, modelName, additionalScript); - suffix = ".fmu"; - } else { - writeScriptFile(scriptFile, modelName, inits, additionalScript); - OSType os = calculateOS(); - suffix = OSType.WINDOWS.equals(os) ? ".exe" : ""; - } - - SimulationLocation location = new SimulationLocation( - simulationDir, - scriptFile, - fullModelDir, - fullModelScriptFile, - new File(simulationDir, modelName + "_res." + outputFormat), - new File(simulationDir, modelName + "_init.xml"), - new File(simulationDir, modelName + suffix) - ); - - writeFullModelScriptFile(fullModelScriptFile, modelName, location.fullModelDir, location.fullModel, additionalScript); - - return location; - } - - /** - * - * @param scriptFile - * @param modelName - * @param inits - * @param additionalScript - * @throws FileNotFoundException - */ - private static void writeScriptFile(File scriptFile, String modelName, HashMap inits, String additionalScript) throws FileNotFoundException { - String outputFormat = inits.containsKey(ModelicaKeys.OUTPUT_FORMAT) ? inits.get(ModelicaKeys.OUTPUT_FORMAT) : "mat"; - - { - PrintStream s = new PrintStream(scriptFile); - s.println("loadFile(\"" + modelName + ".mo\");"); - if(additionalScript != null) - s.println(additionalScript); - s.print("buildModel("+modelName+ - ",startTime="+inits.get(ModelicaKeys.START_VALUE)+ - ",stopTime="+inits.get(ModelicaKeys.STOP_VALUE)+ - ",method="+inits.get(ModelicaKeys.METHOD)+ - ",outputFormat=\""+ outputFormat+"\""+ - ",cflags=\"-O0\"" // Disable c-compiler optimization => faster compilation - ); - if(inits.containsKey(ModelicaKeys.TOLERANCE)) { - s.print(",tolerance="+inits.get(ModelicaKeys.TOLERANCE)); - } - if(inits.containsKey(ModelicaKeys.NUMBER_OF_INTERVALS)) { - s.print(",numberOfIntervals="+inits.get(ModelicaKeys.NUMBER_OF_INTERVALS)); - } - if(inits.containsKey(ModelicaKeys.VARIABLE_FILTER)) { - s.print(",variableFilter=\""+inits.get(ModelicaKeys.VARIABLE_FILTER)+"\""); - } - s.print(");\n"); - s.println("getErrorString();"); - s.close(); - } + + private static final String OM_BUILTIN = "OpenModelica1.9.0"; + + public enum OSType { + APPLE, LINUX, SUN, WINDOWS, UNKNOWN + } + + public static final String OMC_VERSION = "OMC_VERSION"; + public static final String RESULT_FILE_NAME = "RESULT_FILE_NAME"; + + /** + * Get operating system type + * + * @return OSType + */ + private static OSType getOSType() { + String osName = System.getProperty("os.name").toLowerCase(); + + if (osName.startsWith("mac os x")) + return OSType.APPLE; + else if (osName.startsWith("linux")) + return OSType.LINUX; + else if (osName.startsWith("sun")) + return OSType.SUN; + else if (osName.startsWith("windows")) + return OSType.WINDOWS; + + return OSType.UNKNOWN; + } + + private static boolean onWindows() { + return System.getProperty("os.name").toLowerCase().startsWith("windows"); + } + + private static File getOMCBinary(File home) { + return new File(home, "bin" + File.separator + "omc" + (onWindows() ? ".exe" : "")); + } + + private static Process runWithEnvironment(File homeDir, File workDir, File executable, String... parameters) { + // construct the command + List command = new ArrayList(); + command.add(executable.getAbsolutePath()); + // this should iterate through the parameters in order + for (String parameter : parameters) { + command.add(parameter); + } + + // create the process + ProcessBuilder builder = new ProcessBuilder(command); + builder.redirectErrorStream(true); + builder.directory(workDir); + + // set the environment + Map env = builder.environment(); + env.put("OPENMODELICAHOME", homeDir.getAbsolutePath()); + + // TODO: these are probably not needed as most of the files do not exist + File lib = new File(homeDir, "lib"); + File omlib = new File(lib, "omlibrary"); + env.put("OPENMODELICALIBRARY", omlib.getAbsolutePath()); + File bin = new File(homeDir, "bin"); + env.put("OMPATH", bin.getAbsolutePath()); + File mingw = new File(homeDir, "MinGW"); + env.put("MINGW", mingw.getAbsolutePath()); + + File mbin = new File(mingw, "bin"); + File mlib = new File(mingw, "lib"); + env.put("PATH", env.get("PATH") + File.pathSeparator + bin.getAbsolutePath() + + File.pathSeparator + mbin.getAbsolutePath() + + File.pathSeparator + mlib.getAbsolutePath()); + + env.put("MODELICAUSERCFLAGS", "-O0"); + + // run the process + Process process = null; + try { + process = builder.start(); + } + catch (Exception e) { + e.printStackTrace(); + } + + return process; + } + + private static Process runOMC(File homeDir, File workDir, String... parameters) { + return runWithEnvironment(homeDir, workDir, getOMCBinary(homeDir), parameters); + } + + public static String getOMVersion(File home) { + return getProcessOutput(runOMC(home, home, "++v")); + } + + public static String getDefaultOMVersion() { + return getOMVersion(getOMHome()); + } + + public static boolean isOldOMVersion() { + try { + double version = Double.parseDouble(getOMVersion(getOMHome()).substring(0, 3)); + return version < 1.9; + } + catch (NumberFormatException e) { + // if the version string could not be parsed, assume that the + // version sufficiently new + return false; + } + } + + /** + * Get Open Modelica home directory. + * + * @return Open Modelica home directory + */ + private static File getOMHome() { + Preferences node = ConfigurationScope.INSTANCE.getNode(Activator.PLUGIN_ID); + String omHomePath = node.get(OpenModelicaPreferences.OM_HOME, null); + if (omHomePath != null) { + File omHome = new File(omHomePath); + if (omHome.isDirectory()) + return omHome; + } + + return getDefaultOMHome(); + } + + public static File getDefaultOMHome() { + if (onWindows()) { + File builtin = getBuiltinOMHome(); + if (builtin != null) + return builtin; + } + + File installed = getInstalledOMHome(); + if (installed != null) + return installed; + + // TODO: what is the correct error to throw? + throw new Error("OpenModelica could not be found"); + } + + public static File getInstalledOMHome() { + String omHomePath = System.getenv("OPENMODELICAHOME"); + if (omHomePath != null) { + File omHome = new File(omHomePath); + if (omHome.isDirectory()) + return omHome; + } + return null; + } + + public static File getBuiltinOMHome() { + Bundle bundle = Platform.getBundle("org.simantics.openmodelica.win32"); + if (bundle != null) { + try { + File omHome = new File(FileLocator.getBundleFile(bundle), OM_BUILTIN); + if (omHome.isDirectory()) + return omHome; + } + catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + /** + * Gets the whole process output in one string + * + * @param process Process + * @return process output + */ + public static String getProcessOutput(final Process process) { + try { + BufferedReader input = new BufferedReader(new InputStreamReader(process.getInputStream())); + StringBuilder output = new StringBuilder(); + String line; + boolean first = true; + while ((line = input.readLine()) != null) { + if(!first) + output.append(System.getProperty("line.separator")); + first = false; + output.append(line); + } + input.close(); + return output.toString(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * Prints the output of an ongoing process to IModelicaMonitor. + * + * @param process Process + * @param monitor IModelicaMonitor + */ + // TODO: clean up + public static void printProcessOutput(final Process process, final IModelicaMonitor monitor) { + Thread thread = new Thread() { + @Override + public void run() { + InputStream stream = process.getInputStream(); + StringBuilder b = new StringBuilder(); + while(true) { + try { + int c; + + c = stream.read(); + + if(c <= 0) + break; + if(monitor != null) { + if((char)c != '\n') + b.append((char)c); + else { + System.out.println("OMC output: " + b.toString()); + String message = b.toString(); + message = message.trim(); + if(message.startsWith("\"")) + message = message.substring(1); + + monitor.message(message); + b.delete(0, b.length()); + } + } + } catch (IOException e) { + e.printStackTrace(); + break; + } + } + } + }; + + thread.run(); + } + + public static SimulationLocation createSimulationLocation(File modelDir, String modelName, String modelContent) { + if (!modelDir.isDirectory()) { + return null; + } + + // there might be a better way to remove whitespace from the string + // but this apparently works fine in this context + modelName = modelName.replace(" ", ""); + + SimulationLocation location = new SimulationLocation(modelDir, modelName); + + location.modelFile = location.getFileInLocation(".mo"); + location.modelScriptFile = location.getFileInLocation(".mos"); + try { + FileWriter writer = new FileWriter(location.modelFile); + writer.write(modelContent); + writer.close(); + } + catch (IOException e) { + e.printStackTrace(); + return null; + } + + // full model files are (apparently) only needed for old parameter comparison routines + if (isOldOMVersion()) { + location.fullModelDir = new File(location.getModelDir(), "fullModel"); + if (!location.fullModelDir.isDirectory()) { + location.fullModelDir.mkdir(); + } + location.fullModelFile = new File(location.fullModelDir, location.getModelName() + "_full.mo"); + location.fullModelScriptFile = new File(location.fullModelDir, location.getModelName() + "_full.mos"); + } + + location.omHome = getOMHome(); + + return location; + } + + public static void createSimulationScripts(SimulationLocation location, HashMap parameters, String additionalScript) + throws FileNotFoundException { + writeScriptFile(location, parameters, additionalScript); + + location.executableFile = location.getFileInLocation(onWindows() ? ".exe" : ""); + location.initFile = location.getFileInLocation("_init.xml"); + location.resultFile = location.getFileInLocation("_res." + parameters.get(ModelicaKeys.OUTPUT_FORMAT)); + + if (isOldOMVersion()) { + writeFullModelScriptFile(location, additionalScript); + } + } + + public static void createFMUSimulationScripts(SimulationLocation location, HashMap parameters, String additionalScript) + throws FileNotFoundException { + writeFMUScriptFile(location, additionalScript); + + location.executableFile = location.getFileInLocation(".fmu"); + location.initFile = location.getFileInLocation("_init.xml"); + location.resultFile = location.getFileInLocation("_res." + parameters.get(ModelicaKeys.OUTPUT_FORMAT)); + + if (isOldOMVersion()) { + writeFullModelScriptFile(location, additionalScript); + } + } + + /** + * + * @param location + * @param parameters + * @param additionalScript + * @throws FileNotFoundException + */ + private static void writeScriptFile(SimulationLocation location, HashMap parameters, String additionalScript) + throws FileNotFoundException { + PrintStream s = new PrintStream(location.modelScriptFile); + s.println("loadFile(\"" + location.modelFile.getName() + "\");"); + if(additionalScript != null) + s.println(additionalScript); + s.print("buildModel(" + location.getModelName()); + s.print(",startTime=" + parameters.get(ModelicaKeys.START_VALUE)); + s.print(",stopTime=" + parameters.get(ModelicaKeys.STOP_VALUE)); + s.print(",method=" + parameters.get(ModelicaKeys.METHOD)); + s.print(",outputFormat=\"" + parameters.get(ModelicaKeys.OUTPUT_FORMAT) + "\""); + s.print(",cflags=\"-O0\""); // disable c-compiler optimization => faster compilation + if(parameters.containsKey(ModelicaKeys.TOLERANCE)) { + s.print(",tolerance=" + parameters.get(ModelicaKeys.TOLERANCE)); + } + if(parameters.containsKey(ModelicaKeys.NUMBER_OF_INTERVALS)) { + s.print(",numberOfIntervals=" + parameters.get(ModelicaKeys.NUMBER_OF_INTERVALS)); + } + if(parameters.containsKey(ModelicaKeys.VARIABLE_FILTER)) { + s.print(",variableFilter=\"" + parameters.get(ModelicaKeys.VARIABLE_FILTER) + "\""); + } + s.print(");\n"); + s.println("getErrorString();"); + s.close(); + } + + /** + * + * @param location + * @param additionalScript + * @throws FileNotFoundException + */ + private static void writeFMUScriptFile(SimulationLocation location, String additionalScript) + throws FileNotFoundException { + PrintStream s = new PrintStream(location.modelScriptFile); + s.println("loadFile(\"" + location.modelFile.getName() + "\");"); + if(additionalScript != null) + s.println(additionalScript); + s.println("translateModelFMU(" + location.getModelName() + ");"); + s.println("getErrorString();"); + s.close(); + } + + /** + * + * @param location + * @param additionalScript + * @throws FileNotFoundException + */ + // TODO: try this + private static void writeFullModelScriptFile(SimulationLocation location, String additionalScript) + throws FileNotFoundException { + PrintStream s = new PrintStream(location.fullModelScriptFile); + s.println("loadFile(\"" + location.modelFile.getName() + "\");"); + if(additionalScript != null) + s.println(additionalScript); + s.print("saveTotalSCode("); + s.print("\"" + location.fullModelDir.getName() + "/" + location.fullModelFile.getName() + "\""); + s.print(", "); + s.print(location.getModelName()); + s.print(");\n"); + s.println("getErrorString();"); + s.close(); + } + + public static void buildFullModel(SimulationLocation location, IModelicaMonitor monitor) + throws ModelicaException { + Process process = runOMC(location.omHome, location.getModelDir(), location.fullModelScriptFile.getAbsolutePath()); + printProcessOutput(process, monitor); + + try { + process.waitFor(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + + trimExtraFromFullModel(location); + } + + private static void trimExtraFromFullModel(SimulationLocation location) { + try { + FileInputStream fs = new FileInputStream(location.fullModelFile); + InputStreamReader in = new InputStreamReader(fs); + BufferedReader br = new BufferedReader(in); + StringBuffer sb = new StringBuffer(); + + String textinLine; + boolean openmodelicaflag = false; + int breakpoint = 0; + while((textinLine = br.readLine()) != null) { + if(openmodelicaflag == true) { + breakpoint = sb.length(); + openmodelicaflag = false; + } + + if(textinLine.contains("end OpenModelica;")) + openmodelicaflag = true; + + sb.append(textinLine + "\n"); // if you don’t put the \n you will have all the code on one line as fer said + } + + br.close(); + in.close(); + fs.close(); + + FileWriter fstream = new FileWriter(location.fullModelFile); + BufferedWriter outobj = new BufferedWriter(fstream); + outobj.write(sb.substring(breakpoint)); + outobj.close(); + fstream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Builds a model with omc. The location of required files is + * defined in simulationLocation. + * + * @param location Location of model files + * @param monitor Monitor for printing build process output + * @throws ModelicaException + */ + public static void buildModel(SimulationLocation location, IModelicaMonitor monitor) + throws ModelicaException { + + Process process = runOMC(location.omHome, location.getModelDir(), location.modelScriptFile.getAbsolutePath()); + printProcessOutput(process, monitor); + + try { + process.waitFor(); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + + if (!location.executableFile.isFile()) { + // If executable file was not created, something went wrong + throw new ModelicaException("executable file not created"); + } + } + + /** + * Runs a model that has been built to simulationLocation. + * Some initial values can be set for a compiled model without + * re-compiling it. + * + * @param location Location of a built model + * @param monitor Monitor for printing process output + * @param inits Initial values for a simulation run + * @param structureChanged + * @return Simulation process + * @throws IOException + */ + public static Process runModelica(SimulationLocation location, IModelicaMonitor monitor, HashMap experimentParameters, HashMap parameterChanges) throws IOException { + try { + ArrayList commands = new ArrayList(); + commands.add(location.executableFile.getAbsolutePath()); + + if(experimentParameters.get(RESULT_FILE_NAME) != null) { + commands.add("-r="+experimentParameters.get(RESULT_FILE_NAME)); + } + + // Write new initial values (parameters). No need to update xml if structure has changed. In that case also xml is up-to-date + if(parameterChanges != null) { + String version = experimentParameters.get(OMC_VERSION); + // TODO: clean up + if(version == null) + version = getOMVersion(location.omHome); + + Double versionNumber = 1.9; + try { + versionNumber = Double.parseDouble(version.substring(0,3)); + } catch (NumberFormatException e) {} + + if(versionNumber < 1.9) { + writeInits(location, experimentParameters, null); + } else { + // Handled in experiment + if(parameterChanges.size() == 1) { + commands.add("-override"); + commands.add(parameterChanges.keySet().iterator().next() + "=" + parameterChanges.values().iterator().next()); + } else { + // FIXME: if you change 1 parameter AND some experiment parameters, only the parameter change takes effect + updateInitFile(location, experimentParameters, parameterChanges); + } + } + + } + + } + catch (Exception e) { + e.printStackTrace(); + } + + return runWithEnvironment(location.omHome, location.getModelDir(), location.executableFile); + } + + public static String getFlatModelText(SimulationLocation location, IModelicaMonitor monitor, List additional) { + String[] command = new String[additional.size()+1]; + command[0] = location.modelFile.getAbsolutePath(); + for (int i = 0; i < additional.size(); i++) { + command[i+1] = additional.get(i); + } + return getProcessOutput(runOMC(location.omHome, location.getModelDir(), command)); + } + + + /** + * Get all parameter variables and their values from model. + * + * @param model model text + * @return a map containing all parameters and values + */ + public static HashMap getModelParameters(String model) { + HashMap result = new HashMap(); + + try { + BufferedReader in = new BufferedReader(new StringReader(model)); + + String line; + String name; + String value; + + while ((line = in.readLine()) != null) { + line = line.trim(); + if (line.startsWith("parameter") && line.contains("=") && line.contains(";")) { + String[] split = line.split(" = "); + name = split[0].trim(); + name = name.substring(name.lastIndexOf(" ") + 1); + value = split[1].trim(); + value = value.substring(0, value.indexOf(";")); + result.put(name, value); + } + } + + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + + return result; + } + + + /** + * Updates inits.xml with the latest values. This is not needed if the model structure + * has changed. When model structure is changed, the model is compiled and a new xml is + * created. + * + * Works with version 1.8.1 and previous versions. 1.9 version does not support this, since + * the init.xml file format has been changed. With 1.9, use updateInitFile() + * + * @param simulationLocation Location of the model + * @param monitor + */ + private static void writeInits(SimulationLocation simulationLocation, HashMap experimentParameters, IModelicaMonitor monitor) { + + try { + // Create the full model code into one file + buildFullModel(simulationLocation, null); + + // Create simulation files from the full description + ArrayList parameters = new ArrayList(); + parameters.add("+s"); + parameters.add(simulationLocation.fullModelFile.getAbsolutePath()); + + Process process = runOMC(simulationLocation.omHome, simulationLocation.fullModelDir, "+s", simulationLocation.fullModelFile.getAbsolutePath()); + + process.waitFor(); + + // Find the new init file + FilenameFilter initFilter = new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + if(name.endsWith("_init.xml")) + return true; + else + return false; + } + }; + + File initFile = null; + for(File f : simulationLocation.fullModelDir.listFiles(initFilter)) { + initFile = f; + break; + } + + if(initFile != null && initFile.isFile()) { + // Replace original init contents with the new contents + replaceInitFileContents(simulationLocation.initFile.getAbsolutePath(), initFile.getAbsolutePath(), experimentParameters); + } + + } catch (ModelicaException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + /** + * Replaces variable and experiment information from oldFile with contents of newFile. + * + * The file is not simply replaced because guid must match with guid in created exe. + * + * @param oldFile old init.xml + * @param newFile new init.xml + */ + private static void replaceInitFileContents(String oldFile, String newFile, HashMap experimentParameters) { + try { + XPath xpath = XPathFactory.newInstance().newXPath(); + + Document oldInit = DocumentBuilderFactory.newInstance() + .newDocumentBuilder().parse(new InputSource(oldFile)); + Document newInit = DocumentBuilderFactory.newInstance() + .newDocumentBuilder().parse(new InputSource(newFile)); + + // Find the original model description. This will be modified + Node oldModelDescription = (Node)xpath.evaluate("fmiModelDescription", oldInit, XPathConstants.NODE); + + // + // VARIABLES + // + // First, remove old model variables + Node oldModelVariables = (Node)xpath.evaluate("fmiModelDescription/ModelVariables", oldInit, XPathConstants.NODE); + + oldModelDescription.removeChild(oldModelVariables); + + // Second, find variables in the new model description + Node newModelVariables = (Node)xpath.evaluate("fmiModelDescription/ModelVariables", newInit, XPathConstants.NODE); + + // Import new variables to old xml + Node importedModelVariables = oldInit.importNode(newModelVariables, true); + oldModelDescription.appendChild(importedModelVariables); + + // + // EXPERIMENT PARAMETERS + // + for(String key : experimentParameters.keySet()) { + // Find parameter + Node parameter = (Node)xpath.evaluate + ("fmiModelDescription/DefaultExperiment/@" + key, + oldInit, + XPathConstants.NODE); + + if(parameter != null) { + // Change parameter value + parameter.setNodeValue(experimentParameters.get(key)); + } + } + + // Write transformed init.xml + Transformer xformer = TransformerFactory.newInstance().newTransformer(); + xformer.transform(new DOMSource(oldInit), new StreamResult(new File(oldFile))); + + } catch (SAXException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } catch (XPathExpressionException e) { + e.printStackTrace(); + } catch (TransformerConfigurationException e) { + e.printStackTrace(); + } catch (TransformerFactoryConfigurationError e) { + e.printStackTrace(); + } catch (TransformerException e) { + e.printStackTrace(); + } + } + + /** + * Updates init file contents with the given experiment and variable changes. + * + * @param simulationLocation Location of simulation files + * @param experimentParameters Experiment parameters + * @param changes Parameter variable changes + */ + public static void updateInitFile(SimulationLocation simulationLocation, HashMap experimentParameters, HashMap changes) { + try { + XPath xpath = XPathFactory.newInstance().newXPath(); + + Document init = DocumentBuilderFactory.newInstance() + .newDocumentBuilder().parse(simulationLocation.initFile); + + // + // EXPERIMENT PARAMETERS + // + for(String key : experimentParameters.keySet()) { + // Find parameter + Node parameter = (Node)xpath.evaluate + ("fmiModelDescription/DefaultExperiment/@" + key, + init, + XPathConstants.NODE); + + if(parameter != null) { + // Change parameter value + parameter.setNodeValue(experimentParameters.get(key)); + } + } + + // + // PARAMETER VARIABLES + // + for(String name : changes.keySet()) { + Node node = (Node)xpath.evaluate + ("//fmiModelDescription/ModelVariables/ScalarVariable[@name='" + name + "']/Real/@start", + init, + XPathConstants.NODE); + if(node != null) { + node.setNodeValue(changes.get(name)); + } + } + + // Write transformed init.xml + Transformer xformer = TransformerFactory.newInstance().newTransformer(); + xformer.transform(new DOMSource(init), new StreamResult(simulationLocation.initFile)); + + } catch (SAXException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (ParserConfigurationException e) { + e.printStackTrace(); + } catch (XPathExpressionException e) { + e.printStackTrace(); + } catch (TransformerConfigurationException e) { + e.printStackTrace(); + } catch (TransformerFactoryConfigurationError e) { + e.printStackTrace(); + } catch (TransformerException e) { + e.printStackTrace(); + } } - - /** - * - * @param scriptFile - * @param modelName - * @param inits - * @param additionalScript - * @throws FileNotFoundException - */ - private static void writeFullModelScriptFile(File fullModelScriptFile, String modelName, File fullModelDir, File fullModel, String additionalScript) throws FileNotFoundException { - PrintStream s = new PrintStream(fullModelScriptFile); - s.println("loadFile(\"" + modelName + ".mo\");"); - if(additionalScript != null) - s.println(additionalScript); - s.print("saveTotalSCode("); - s.print("\"" + fullModelDir.getName() + "/" + fullModel.getName() + "\""); - s.print(", "); - s.print(modelName); - s.print(");\n"); - s.println("getErrorString();"); - s.close(); - } - - /** - * - * @param scriptFile - * @param modelName - * @param inits - * @param additionalScript - * @throws FileNotFoundException - */ - private static void writeFMUScriptFile(File scriptFile, String modelName, String additionalScript) throws FileNotFoundException { - PrintStream s = new PrintStream(scriptFile); - if(additionalScript != null) - s.println(additionalScript); - s.println("loadFile(\"" + modelName + ".mo\");"); - s.println("translateModelFMU(" + modelName + ");"); - s.println("getErrorString();"); - s.close(); - } - - private static void trimExtraFromFullModel(SimulationLocation simulationLocation) { - try { - FileInputStream fs = new FileInputStream(simulationLocation.fullModel); - InputStreamReader in = new InputStreamReader(fs); - BufferedReader br = new BufferedReader(in); - StringBuffer sb = new StringBuffer(); - - String textinLine; - boolean openmodelicaflag = false; - int breakpoint = 0; - while((textinLine = br.readLine()) != null) { - if(openmodelicaflag == true) { - breakpoint = sb.length(); - openmodelicaflag = false; - } - - if(textinLine.contains("end OpenModelica;")) - openmodelicaflag = true; - - - sb.append(textinLine + "\n"); // if you don’t put the \n you will have all the code on one line as fer said - } - - br.close(); - in.close(); - fs.close(); - - FileWriter fstream = new FileWriter(simulationLocation.fullModel); - BufferedWriter outobj = new BufferedWriter(fstream); - outobj.write(sb.substring(breakpoint)); - outobj.close(); - fstream.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public static void createFullMo(SimulationLocation simulationLocation, IModelicaMonitor monitor) throws ModelicaException { - // Create full .mo for parameter comparison - ArrayList parameters = new ArrayList(); - parameters.add(simulationLocation.fullMosFile.getAbsolutePath()); - Process process = runOMC(simulationLocation.simulationDir, simulationLocation.omcHome, monitor, parameters); - try { - process.waitFor(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - trimExtraFromFullModel(simulationLocation); - - } - /** - * Builds a model with omc. The location of required files is - * defined in simulationLocation. - * - * @param simulationLocation Location of model files - * @param monitor Monitor for printing build process output - * @throws ModelicaException - */ - public static void buildModel(SimulationLocation simulationLocation, IModelicaMonitor monitor) throws ModelicaException { - ArrayList parameters = new ArrayList(); - parameters.add(simulationLocation.mosFile.getAbsolutePath()); - runOMC(simulationLocation.simulationDir, simulationLocation.omcHome, monitor, parameters); - - if(!simulationLocation.executableFile.isFile()) - // If .exe file was not created, something went wrong - throw new ModelicaException(".exe file not created\nSee log at " + simulationLocation.simulationDir.getAbsolutePath()); - } - - /** - * Generic method for running omc with some parameters - * - * @param workDir Working directory. (Usually the directory of scriptfile) - * @param monitor IModelicaMonitor for printing modelica output - * @throws ModelicaException - */ - public static Process runOMC(File workDir, IModelicaMonitor monitor, List parameters) throws ModelicaException { - return runOMC(workDir, getModelicaHome(), monitor, parameters); - } - /** - * Generic method for running omc with some parameters - * - * @param workDir Working directory. (Usually the directory of scriptfile) - * @param monitor IModelicaMonitor for printing modelica output - * @param openModelicaHome OpenModelica home folder - * @throws ModelicaException - */ - public static Process runOMC(File workDir, File openModelicaHome, IModelicaMonitor monitor, List parameters) throws ModelicaException { - try { - // Add OMC as the first parameter - parameters.add(0, openModelicaHome + "\\bin\\omc.exe"); - - // Create the build process - ProcessBuilder processBuilder = new ProcessBuilder(parameters) - .directory(workDir.getAbsoluteFile()) - .redirectErrorStream(true); - - // Set environment variables so that OMC can find itself - Map env = processBuilder.environment(); - - env.put("OPENMODELICAHOME", openModelicaHome.getAbsolutePath()); - env.put("OPENMODELICALIBRARY", new File(openModelicaHome, "lib\\omlibrary").getAbsolutePath()); - env.put("OMPATH", new File(openModelicaHome, "bin").getAbsolutePath()); - env.put("MINGW", new File(openModelicaHome, "MinGW").getAbsolutePath()); - env.put("MODELICAUSERCFLAGS", "-O0"); - env.put("PATH", env.get("PATH") - + System.getProperty("path.separator") + new File(openModelicaHome, "bin").getAbsolutePath() - + System.getProperty("path.separator") + new File(openModelicaHome, "MinGW\\lib").getAbsolutePath() - + System.getProperty("path.separator") + new File(openModelicaHome, "MinGW\\bin").getAbsolutePath()); - - // Start the building process - Process process = processBuilder.start(); - - // Print process output - printProcessOutput(process, monitor); - - return process; - } catch(IOException e) { - throw new ModelicaException("Error while running OMC: " + e.getMessage()); - } - } - - public static Process runModelica(SimulationLocation simulationLocation, IModelicaMonitor monitor, HashMap experimentParameters, boolean structureChanged) throws IOException { - if(structureChanged) - return runModelica(simulationLocation, monitor, experimentParameters, null); - else - return runModelica(simulationLocation, monitor, experimentParameters, new HashMap()); - } - - /** - * Runs a model that has been built to simulationLocation. - * Some initial values can be set for a compiled model without - * re-compiling it. - * - * @param simulationLocation Location of a built model - * @param monitor Monitor for printing process output - * @param inits Initial values for a simulation run - * @param structureChanged - * @return Simulation process - * @throws IOException - */ - public static Process runModelica(SimulationLocation simulationLocation, IModelicaMonitor monitor, HashMap experimentParameters, HashMap parameterChanges) throws IOException { - try { - - ArrayList commands = new ArrayList(); - commands.add(simulationLocation.executableFile.getAbsolutePath()); - - if(experimentParameters.get(RESULT_FILE_NAME) != null) { - commands.add("-r="+experimentParameters.get(RESULT_FILE_NAME)); - } - - // Write new initial values (parameters). No need to update xml if structure has changed. In that case also xml is up-to-date - if(parameterChanges != null) { - String version = experimentParameters.get(OMC_VERSION); - if(version == null) - version = getOMCVersion(simulationLocation.omcHome); - - Double versionNumber = 1.9; - try { - versionNumber = Double.parseDouble(version.substring(0,3)); - } catch (NumberFormatException e) {} - - if(versionNumber < 1.9) { - writeInits(simulationLocation, experimentParameters, null); - } else { - // Handled in experiment - if(parameterChanges.size() == 1) { - commands.add("-override"); - commands.add(parameterChanges.keySet().iterator().next() + "=" + parameterChanges.values().iterator().next()); - } else { - // FIXME: if you change 1 parameter AND some experiment parameters, only the parameter change takes effect - updateInitFile(simulationLocation, experimentParameters, parameterChanges); - } - } - - } - - // Create simulation proecss - ProcessBuilder processBuilder = new ProcessBuilder(commands) - .directory(new File(simulationLocation.simulationDir.getAbsolutePath())) - .redirectErrorStream(true); - - // Set environment variables for the process - Map env = processBuilder.environment(); - File openModelicaHome = simulationLocation.omcHome; - if (openModelicaHome == null) - openModelicaHome = getModelicaHome(); - env.put("OPENMODELICAHOME", openModelicaHome.getAbsolutePath()); - env.put("OPENMODELICALIBRARY", openModelicaHome.getAbsolutePath() + "\\lib\\omlibrary"); - env.put("OMPATH", openModelicaHome.getAbsolutePath() + "\\bin"); - env.put("MINGW", openModelicaHome.getAbsolutePath() + "\\MinGW"); - env.put("MODELICAUSERCFLAGS", "-O0"); - env.put("PATH", env.get("PATH") - + System.getProperty("path.separator") + openModelicaHome.getAbsolutePath() + "\\bin" - + System.getProperty("path.separator") + openModelicaHome.getAbsolutePath() + "\\MinGW\\lib" - + System.getProperty("path.separator") + openModelicaHome.getAbsolutePath() + "\\MinGW\\bin"); - - // Simulate model - Process process = processBuilder.start(); - - return process; - } catch(IOException e) { - e.printStackTrace(); - } - return null; - } - - public static String getFlatModelText(SimulationLocation simulationLocation, IModelicaMonitor monitor, List additionalPaths) { - - ArrayList commands = new ArrayList(); - File omHome = getModelicaHome(); - commands.add(omHome + "\\bin\\omc.exe"); - String path = simulationLocation.mosFile.getAbsolutePath(); - path = path.substring(0, path.length() - 1); - commands.add(path); - - for(String additionalPath : additionalPaths) { - commands.add(additionalPath); - } - - ProcessBuilder processBuilder = new ProcessBuilder(commands) - .redirectErrorStream(true).directory(simulationLocation.simulationDir); - - Map env = processBuilder.environment(); - env.put("OPENMODELICAHOME", omHome.getAbsolutePath()); - - // Start the building process - try { - Process process = processBuilder.start(); - return getProcessOutput(process); - } catch (IOException e) { - e.printStackTrace(); - } - - return null; - } - - - /** - * Get all parameter variables and their values from model. Model text is - * provided in a Reader. - * @param reader Reader containing model text - * @return all parameters and their values - */ - public static HashMap getModelParameters(Reader reader) { - HashMap result = new HashMap(); - - try { - BufferedReader in = new BufferedReader(reader); - String line; - String name; - String value; - while ((line = in.readLine()) != null) { - line = line.trim(); - if(line.startsWith("parameter") && line.contains("=") && line.contains(";")) { - String[] split = line.split(" = "); - name = split[0].trim(); - name = name.substring(name.lastIndexOf(" ") + 1); - value = split[1].trim(); - value = value.substring(0, value.indexOf(";")); - result.put(name, value); - } - } - in.close(); - } catch (IOException e) { - e.printStackTrace(); - } - return result; - } - - - /** - * Updates inits.xml with the latest values. This is not needed if the model structure - * has changed. When model structure is changed, the model is compiled and a new xml is - * created. - * - * Vorks with version 1.8.1 and previous versions. 1.9 version does not support this, since - * the init.xml file format has beenchanged. With 1.9, use updateInitFile() - * - * @param simulationLocation Location of the model - * @param monitor - */ - private static void writeInits(SimulationLocation simulationLocation, HashMap experimentParameters, IModelicaMonitor monitor) { - - try { - // Create the full model code into one file - createFullMo(simulationLocation, null); - - // Create simulation files from the full description - ArrayList parameters = new ArrayList(); - parameters.add("+s"); - parameters.add(simulationLocation.fullModel.getAbsolutePath()); - - Process p = runOMC(simulationLocation.fullModelDir, monitor, parameters); - - p.waitFor(); - - // Find the new init file - FilenameFilter initFilter = new FilenameFilter() { - - @Override - public boolean accept(File dir, String name) { - if(name.endsWith("_init.xml")) - return true; - else - return false; - } - }; - - File initFile = null; - for(File f : simulationLocation.fullModelDir.listFiles(initFilter)) { - initFile = f; - break; - } - - if(initFile != null && initFile.isFile()) { - // Replace original init contents with the new contents - replaceInitFileContents(simulationLocation.initFile.getAbsolutePath(), initFile.getAbsolutePath(), experimentParameters); - } - - } catch (ModelicaException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - /** - * Replaces variable and experiment information from oldFile with contents of newFile. - * - * The file is not simply replaced because guid must match with guid in created exe. - * - * @param oldFile old init.xml - * @param newFile new init.xml - */ - private static void replaceInitFileContents(String oldFile, String newFile, HashMap experimentParameters) { - Document oldInit, newInit; - try { - XPath xpath = XPathFactory.newInstance().newXPath(); - - oldInit = DocumentBuilderFactory.newInstance() - .newDocumentBuilder().parse(new InputSource(oldFile)); - - newInit = DocumentBuilderFactory.newInstance() - .newDocumentBuilder().parse(new InputSource(newFile)); - - // Find the original model description. This will be modified - Node oldModelDescription = (Node)xpath.evaluate("fmiModelDescription", oldInit, XPathConstants.NODE); - - - // - // VARIABLES - // - // First, remove old model variables - Node oldModelVariables = (Node)xpath.evaluate("fmiModelDescription/ModelVariables", oldInit, XPathConstants.NODE); - - oldModelDescription.removeChild(oldModelVariables); - - // Second, find variables in the new model description - Node newModelVariables = (Node)xpath.evaluate("fmiModelDescription/ModelVariables", newInit, XPathConstants.NODE); - - - // Import new variables to old xml - Node importedModelVariables = oldInit.importNode(newModelVariables, true); - oldModelDescription.appendChild(importedModelVariables); - - // - // EXPERIMENT PARAMETERS - // - for(String key : experimentParameters.keySet()) { - // Find parameter - Node parameter = (Node)xpath.evaluate - ("fmiModelDescription/DefaultExperiment/@" + key, - oldInit, - XPathConstants.NODE); - - if(parameter != null) { - // Change parameter value - parameter.setNodeValue(experimentParameters.get(key)); - } - } - - - // Write transformed init.xml - Transformer xformer = TransformerFactory.newInstance().newTransformer(); - xformer.transform(new DOMSource(oldInit), new StreamResult(new File(oldFile))); - - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (TransformerConfigurationException e) { - e.printStackTrace(); - } catch (TransformerFactoryConfigurationError e) { - e.printStackTrace(); - } catch (TransformerException e) { - e.printStackTrace(); - } catch (XPathExpressionException e) { - e.printStackTrace(); - } - } - - /** - * Updates init file contents with the given experiment and variable changes - * @param simulationLocation Location of simulation files - * @param experimentParameters Experiment parameters - * @param changes Parameter variable changes - */ - public static void updateInitFile(SimulationLocation simulationLocation, HashMap experimentParameters, HashMap changes) { - try { - XPath xpath = XPathFactory.newInstance().newXPath(); - - Document init = DocumentBuilderFactory.newInstance() - .newDocumentBuilder().parse(simulationLocation.initFile); - - // - // EXPERIMENT PARAMETERS - // - for(String key : experimentParameters.keySet()) { - // Find parameter - Node parameter = (Node)xpath.evaluate - ("fmiModelDescription/DefaultExperiment/@" + key, - init, - XPathConstants.NODE); - - if(parameter != null) { - // Change parameter value - parameter.setNodeValue(experimentParameters.get(key)); - } - } - - // - // PARAMETER VARIABLES - // - - Node node; - for(String name : changes.keySet()) { - node = (Node)xpath.evaluate - ("//fmiModelDescription/ModelVariables/ScalarVariable[@name='" + name + "']/Real/@start", - init, - XPathConstants.NODE); - if(node != null) { - node.setNodeValue(changes.get(name)); - } - } - - // Write transformed init.xml - Transformer xformer = TransformerFactory.newInstance().newTransformer(); - xformer.transform(new DOMSource(init), new StreamResult(simulationLocation.initFile)); - - - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (XPathExpressionException e) { - e.printStackTrace(); - } catch (TransformerConfigurationException e) { - e.printStackTrace(); - } catch (TransformerFactoryConfigurationError e) { - e.printStackTrace(); - } catch (TransformerException e) { - e.printStackTrace(); - } - } } diff --git a/org.simantics.modelica/src/org/simantics/modelica/SimulationLocation.java b/org.simantics.modelica/src/org/simantics/modelica/SimulationLocation.java index 98f5cdd0..70aa6f8b 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/SimulationLocation.java +++ b/org.simantics.modelica/src/org/simantics/modelica/SimulationLocation.java @@ -17,41 +17,92 @@ import java.io.File; * * @author Teemu Lempinen * @author Tuomas Miettinen - * + * @author Janne Kauttio */ public class SimulationLocation { - public File simulationDir; - public File mosFile; - public File fullModelDir; - public File fullMosFile; - public File fullModel; - public File resFile; - public File initFile; - public File executableFile; - public File omcHome; - - public SimulationLocation(File simulationDir, File mosFile, File fullModelDir, File fullMosFile, - File resFile, File initFile, File exeFile) { - this.simulationDir = simulationDir; - this.mosFile = mosFile; - this.fullModelDir = fullModelDir; - this.fullMosFile = fullMosFile; - this.resFile = resFile; - this.initFile = initFile; - this.executableFile = exeFile; - this.fullModel = new File(getFullModelPath()); - this.omcHome = ModelicaManager.getModelicaHome(); - } - - public void setOMCHomeFolder(File omcHome) { - this.omcHome = omcHome; - } - - private String getFullModelPath() { - if(fullMosFile == null) - return null; - - String fullScriptPath = fullMosFile.getAbsolutePath(); - return fullScriptPath.substring(0, fullScriptPath.length()-1); // ...._full.mos -> ..._full.mo - } + + private String modelName; + + public File modelDir; + public File modelFile; + public File modelScriptFile; + public File fullModelDir; + public File fullModelFile; + public File fullModelScriptFile; + public File initFile; + public File executableFile; + public File resultFile; + public File omHome; + + public SimulationLocation(File modelDir, String modelName) { + this.modelDir = modelDir; + this.modelName = modelName; + } + + public File getModelDir() { + return modelDir; + } + + public String getModelName() { + return modelName; + } + + public File getFileInLocation(String name, String affix) { + return new File(modelDir, name + affix); + } + + public File getFileInLocation(String affix) { + return getFileInLocation(modelName, affix); + } + + public SimulationLocation(File modelDir, File modelFile, File modelScriptFile, + File resultFile, File initFile, File executableFile, File omHome) { + this.modelDir = modelDir; + this.modelFile = modelFile; + this.modelScriptFile = modelScriptFile; + this.fullModelDir = null; + this.fullModelFile = null; + this.fullModelScriptFile = null; + this.resultFile = resultFile; + this.initFile = initFile; + this.executableFile = executableFile; + this.omHome = omHome; + } + + public SimulationLocation(File modelDir, File model, File modelScriptFile, + File fullModelDir, File fullModelFile, File fullModelScriptFile, + File resultFile, File initFile, File executableFile, File omHome) { + this.modelDir = modelDir; + this.modelFile = model; + this.modelScriptFile = modelScriptFile; + this.fullModelDir = fullModelDir; + this.fullModelFile = fullModelFile; + this.fullModelScriptFile = fullModelScriptFile; + this.resultFile = resultFile; + this.initFile = initFile; + this.executableFile = executableFile; + this.omHome = omHome; + } + + // TODO: remove this later +// public SimulationLocation(File modelDir, File modelScriptFile, File fullModelDir, File fullModelScriptFile, +// File resultFile, File initFile, File executableFile) { +// this.modelDir = modelDir; +// this.modelScriptFile = modelScriptFile; +// this.fullModelDir = fullModelDir; +// this.fullModelScriptFile = fullModelScriptFile; +// this.resultFile = resultFile; +// this.initFile = initFile; +// this.executableFile = executableFile; +// this.fullModel = new File(getFullModelPath()); +// this.omc = ModelicaManager.getOpenModelicaHome(); +// } + + private String getFullModelPath() { + if(fullModelScriptFile == null) + return null; + + String fullScriptPath = fullModelScriptFile.getAbsolutePath(); + return fullScriptPath.substring(0, fullScriptPath.length()-1); // ..._full.mos -> ..._full.mo + } } \ No newline at end of file diff --git a/org.simantics.modelica/src/org/simantics/modelica/preferences/ModelicaPreferenceInitializer.java b/org.simantics.modelica/src/org/simantics/modelica/preferences/ModelicaPreferenceInitializer.java index 4a1e42ba..553aeaba 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/preferences/ModelicaPreferenceInitializer.java +++ b/org.simantics.modelica/src/org/simantics/modelica/preferences/ModelicaPreferenceInitializer.java @@ -12,7 +12,6 @@ package org.simantics.modelica.preferences; import java.io.File; -import java.io.IOException; import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; import org.eclipse.core.runtime.preferences.ConfigurationScope; @@ -23,36 +22,31 @@ import org.simantics.modelica.ModelicaManager; public class ModelicaPreferenceInitializer extends AbstractPreferenceInitializer { - public ModelicaPreferenceInitializer() { - - } - - @Override - public void initializeDefaultPreferences() { - - IScopeContext context = ConfigurationScope.INSTANCE; - Preferences node = context.getNode(Activator.PLUGIN_ID); - - String omHome = node.get(OpenModelicaPreferences.OM_HOME, null); - if(omHome == null) - // No OM_HOME set - useDefault(node); - else { - File dir = new File(omHome); - if(dir == null || !dir.isDirectory()) - // OM_HOME is not a directory - useDefault(node); - try { - ModelicaManager.getOMCVersion(dir); - } catch (IOException e) { - // OpenModelica not found from directory - useDefault(node); - } - } - } - - private void useDefault(Preferences node) { - node.put(OpenModelicaPreferences.OM_HOME, ModelicaManager.getDefaultModelicaHome().getAbsolutePath()); - } + @Override + public void initializeDefaultPreferences() { + IScopeContext context = ConfigurationScope.INSTANCE; + Preferences node = context.getNode(Activator.PLUGIN_ID); + String omHome = node.get(OpenModelicaPreferences.OM_HOME, null); + if (omHome == null) { + // OM_HOME not set + useDefault(node); + } else { + File dir = new File(omHome); + if(dir == null || !dir.isDirectory()) + // OM_HOME is not a directory + useDefault(node); + // TODO: does not make much sense +// try { +// ModelicaManager.getOpenModelicaVersion(); +// } catch (IOException e) { +// // OpenModelica not found from directory +// useDefault(node); +// } + } + } + + private void useDefault(Preferences node) { + node.put(OpenModelicaPreferences.OM_HOME, ModelicaManager.getDefaultOMHome().getAbsolutePath()); + } } diff --git a/org.simantics.modelica/src/org/simantics/modelica/preferences/OpenModelicaPreferences.java b/org.simantics.modelica/src/org/simantics/modelica/preferences/OpenModelicaPreferences.java index bde3c699..e8b0e6ae 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/preferences/OpenModelicaPreferences.java +++ b/org.simantics.modelica/src/org/simantics/modelica/preferences/OpenModelicaPreferences.java @@ -13,6 +13,6 @@ package org.simantics.modelica.preferences; public class OpenModelicaPreferences { - public static String OM_HOME = "MODELICA_HOME"; + public static String OM_HOME = "OPENMODELICA_HOME"; } diff --git a/org.simantics.modelica/src/org/simantics/modelica/reader/MatFileReader.java b/org.simantics.modelica/src/org/simantics/modelica/reader/MatFileReader.java index afb7a0b7..79db0d6c 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/reader/MatFileReader.java +++ b/org.simantics.modelica/src/org/simantics/modelica/reader/MatFileReader.java @@ -26,9 +26,8 @@ public class MatFileReader implements ResultFileReader { private HashMap parameterValues; - long readBytes = 0; // tracking read data - long dataMark = 0; // mark for actual data + long dataMark = 0; // mark for actual data IntMatrix info; int[] infoData; @@ -45,11 +44,11 @@ public class MatFileReader implements ResultFileReader { return names; } - @Override public int getCount(String item) { return dataHeader.columns; } + /** * Reads all data of a given item */ @@ -71,7 +70,6 @@ public class MatFileReader implements ResultFileReader { in.close(); return (double[])data; - } /** @@ -161,7 +159,6 @@ public class MatFileReader implements ResultFileReader { return (double[][])data; } - private void readVariables() throws IOException { InputStream in = openStream(); readMatrix(in); // Header @@ -246,7 +243,6 @@ public class MatFileReader implements ResultFileReader { private Matrix readMatrix(InputStream in) throws IOException { - int type = getInt(in); int rows = getInt(in); int columns = getInt(in); @@ -256,8 +252,6 @@ public class MatFileReader implements ResultFileReader { String name = getString(in,namlen-1); in.read(); readBytes++; - - if(imagf > 0) throw new IOException("Imaginary part of the matrix is not supported (matrix " + name + ")."); @@ -292,10 +286,6 @@ public class MatFileReader implements ResultFileReader { } private Matrix readMatrix(MatrixHeader header, InputStream in) throws IOException { - - - - switch(header.type) { case 0: { DoubleMatrix matrix = new DoubleMatrix(header.name, header.rows,header.columns); @@ -326,19 +316,15 @@ public class MatFileReader implements ResultFileReader { } private double[] readRow(MatrixHeader header, int column, InputStream in)throws IOException { - if (header.type != 0) throw new IOException("Only double type supported"); - if (infoData[column * 4] != 2) - throw new IOException(); // this is checked in initialization phase. + throw new IOException(); // this is checked in initialization phase. int size = header.columns; int rows = header.rows; double[] v = new double[size]; int sc = infoData[column * 4 + 1]; int c = sc > 0 ? sc-1 : -sc-1; - - skip(c * 8, in); for (int j = 0; j < v.length; ++j) { @@ -347,12 +333,11 @@ public class MatFileReader implements ResultFileReader { v[j] = d; skip((rows-1)*8,in); } - - if(sc < 0) - for(int j=0;j 0 ? sc-1 : -sc-1; - - skip((c+((long)start*(long)rows)) * 8L, in); for (int j = 0; j < v.length; ++j) { @@ -379,12 +362,11 @@ public class MatFileReader implements ResultFileReader { v[j] = d; skip((rows*skip + rows-1)*8,in); } - - if(sc < 0) - for(int j=0;j unSortedRows, InputStream in)throws IOException { @@ -406,35 +388,26 @@ public class MatFileReader implements ResultFileReader { uc[i] = usc[i] > 0 ? usc[i]-1 : -usc[i]-1; } - //Map cToRow = new HashMap(); MapList cToRow = new MapList(); List sortedCs = new ArrayList(); for (int i = 0; i < unSortedRows.size(); i++) { - //cToRow.put(uc[i], unSortedRows.get(i)); cToRow.add(uc[i], unSortedRows.get(i)); sortedCs.add(uc[i]); } List sortedRows = new ArrayList(); -// int sc[] = new int[unSortedRows.size()]; -// int c[] = new int[unSortedRows.size()]; int sc[] = new int[sortedCs.size()]; int c[] = new int[sortedCs.size()]; Collections.sort(sortedCs); - //for (int i = 0; i < unSortedRows.size(); i++) { for (int i = 0; i < sortedCs.size(); i++) { - //int row = cToRow.get(sortedCs.get(i)); int row = cToRow.getValues(sortedCs.get(i)).get(0); sortedRows.add(row); sc[i] = usc[unSortedRows.indexOf(row)]; c[i] = uc[unSortedRows.indexOf(row)]; vs[i] = new double[size]; } - - - skip(c[0] * 8L, in); for (int j = 0; j < size; ++j) { @@ -448,7 +421,6 @@ public class MatFileReader implements ResultFileReader { } else { skip((rows - c[index]-1 + c[0])*8,in); } - //skip((rows-1)*8,in); } } @@ -459,18 +431,7 @@ public class MatFileReader implements ResultFileReader { vs[i][j] = -vs[i][j]; } -// for (int i = 0; i < sortedRows.size(); i++) { -// int row = sortedRows.get(i); -// int rRow = unSortedRows.get(i); -// if (row != rRow) { -// int ri = sortedRows.indexOf(rRow); -// double v[] = vs[i]; -// vs[i] = vs[ri]; -// vs[ri] = v; -// sortedRows.set(i, rRow); -// sortedRows.set(ri, row); -// } -// } + for (int i = 0; i < unSortedRows.size(); i++) { int rRow = unSortedRows.get(i); @@ -498,17 +459,12 @@ public class MatFileReader implements ResultFileReader { private double[][] readRows(MatrixHeader header, List unSortedRows, int start, int count, int skip, InputStream in)throws IOException { - - - ; if (header.type != 0) throw new IOException("Only double type supported"); for (int row : unSortedRows) if (infoData[row * 4] != 2) - throw new IOException(); // this is checked in initialization phase. - - + throw new IOException(); // this is checked in initialization phase. int size = header.columns; int rows = header.rows; @@ -521,39 +477,30 @@ public class MatFileReader implements ResultFileReader { double vs[][] = new double[unSortedRows.size()][]; for (int i = 0; i < unSortedRows.size(); i++) { int row = unSortedRows.get(i); - //vs[i] = new double[count]; usc[i] = infoData[row * 4 + 1]; uc[i] = usc[i] > 0 ? usc[i]-1 : -usc[i]-1; } - //Map cToRow = new HashMap(); MapList cToRow = new MapList(); List sortedCs = new ArrayList(); for (int i = 0; i < unSortedRows.size(); i++) { - //cToRow.put(uc[i], unSortedRows.get(i)); cToRow.add(uc[i], unSortedRows.get(i)); if (!sortedCs.contains(uc[i])) sortedCs.add(uc[i]); } List sortedRows = new ArrayList(); -// int sc[] = new int[unSortedRows.size()]; -// int c[] = new int[unSortedRows.size()]; int sc[] = new int[sortedCs.size()]; int c[] = new int[sortedCs.size()]; Collections.sort(sortedCs); - //for (int i = 0; i < unSortedRows.size(); i++) { for (int i = 0; i < sortedCs.size(); i++) { - //int row = cToRow.get(sortedCs.get(i)); int row = cToRow.getValues(sortedCs.get(i)).get(0); sortedRows.add(row); sc[i] = usc[unSortedRows.indexOf(row)]; c[i] = uc[unSortedRows.indexOf(row)]; vs[i] = new double[count]; } - - long s = start; s *= rows; @@ -571,7 +518,6 @@ public class MatFileReader implements ResultFileReader { } else { skip((rows - c[index]-1 + c[0])*8,in); } - //skip((rows-1)*8,in); } if (skip > 0) skip((skip*rows)*8,in); @@ -619,7 +565,6 @@ public class MatFileReader implements ResultFileReader { double[] valueData = matrix.data; int[] infoData = info.data; int rows = matrix.rows; - //System.out.println("cols="+values.columns+", rows=" +values.rows+ ", data.length="+valueData.length); for(int i=startIndex;i 0 ? sc-1 : -sc-1; - //System.out.println("i=" + i + ", sc=" + sc + ", c=" + c); for(int j=0;j= matrix.columns) adjusted = matrix.columns - 1; diff --git a/org.simantics.modelica/src/org/simantics/modelica/reader/ResultFileReader.java b/org.simantics.modelica/src/org/simantics/modelica/reader/ResultFileReader.java index 2369d49b..e82619e2 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/reader/ResultFileReader.java +++ b/org.simantics.modelica/src/org/simantics/modelica/reader/ResultFileReader.java @@ -19,13 +19,13 @@ public interface ResultFileReader { public int getCount(String item); /** - * Reads all data of a given item + * Reads all data of a given item * @param item * @return * @throws IOException */ - public double[] readData(String item) throws IOException ; - + public double[] readData(String item) throws IOException; + public double[][] readData(List items) throws IOException; /** * Reads data of a given item @@ -36,16 +36,7 @@ public interface ResultFileReader { * @return * @throws IOException */ - public double[] readData(String item, int start, int count, int skip) throws IOException ; + public double[] readData(String item, int start, int count, int skip) throws IOException; + public double[][] readData(List items, int start, int count, int skip) throws IOException; - /** - * Reads all data of given items. - * @param items names of the items. - * @return - * @throws IOException - */ - public double[][] readData(List items) throws IOException ; - - public double[][] readData(List items, int start, int count, int skip) throws IOException ; - } diff --git a/org.simantics.sysdyn.feature/feature.xml b/org.simantics.sysdyn.feature/feature.xml index 52528821..e9e11f98 100644 --- a/org.simantics.sysdyn.feature/feature.xml +++ b/org.simantics.sysdyn.feature/feature.xml @@ -55,11 +55,7 @@ - + + + diff --git a/org.simantics.sysdyn.ui/plugin.xml b/org.simantics.sysdyn.ui/plugin.xml index 69dc4a06..0c03ed70 100644 --- a/org.simantics.sysdyn.ui/plugin.xml +++ b/org.simantics.sysdyn.ui/plugin.xml @@ -2473,6 +2473,11 @@ + + optionList = new ArrayList(); - optionList.add(new String[]{CUSTOM_PATH, CUSTOM_PATH}); - if (installed != null) { - optionList.add(new String[]{"Local installation (" + installedVersion + ")", installed.getAbsolutePath() }); - } - if (builtIn != null) { - optionList.add(new String[]{"Built-in (" + builtInVersion + ")", builtIn.getAbsolutePath()}); - } - - String[][] options = optionList.toArray(new String[optionList.size()][]); - - - rg = new RadioGroupFieldEditor(OpenModelicaPreferences.OM_HOME, - "&Choose the used OpenModelica version", 1, - options, getFieldEditorParent()) { - - @Override - protected void doStore() { - // Do nothing. Path handles saving the value - } - - @Override - protected void fireValueChanged(String property, Object oldValue, Object newValue) { - if((installed != null &&newValue.equals(installed.getAbsolutePath())) || (builtIn != null && newValue.equals(builtIn.getAbsolutePath()))) { - path.setStringValue((String)newValue); - path.setEnabled(false, getFieldEditorParent()); - } else { - path.setEnabled(true, getFieldEditorParent()); - } - } - - @Override - public void doLoadDefault() { - IScopeContext context = ConfigurationScope.INSTANCE; - Preferences node = context.getNode(Activator.PLUGIN_ID); - node.put(OpenModelicaPreferences.OM_HOME, ModelicaManager.getDefaultModelicaHome().getAbsolutePath()); - load(); - } - }; - - addField(rg); - - path = new DirectoryFieldEditor(OpenModelicaPreferences.OM_HOME, - "&Modelica Home:", getFieldEditorParent()) { - - @Override - public void setValidateStrategy(int value) { - super.setValidateStrategy(StringFieldEditor.VALIDATE_ON_KEY_STROKE); - } - - @Override - public void doStore() { - super.doStore(); - IScopeContext context = ConfigurationScope.INSTANCE; - Preferences node = context.getNode(Activator.PLUGIN_ID); - node.put(OpenModelicaPreferences.OM_HOME, getStringValue()); - } - - @Override - protected boolean doCheckState() { - boolean valid = super.doCheckState(); - if(valid) { - // path is a valid directory - String path = getStringValue(); - File dir = new File(path); - try { - String version = ModelicaManager.getOMCVersion(dir); - if(version == null || version.isEmpty()) { - return false; - } - } catch (IOException e) { - return false; - } - } - - return valid; - } - - @Override - public void doLoad() { - super.doLoad(); - String value = getStringValue(); - updatePath(value); - } - - @Override - public void doLoadDefault() { - updatePath(ModelicaManager.getDefaultModelicaHome().getAbsolutePath()); - } - - private void updatePath(String newValue) { - if((installed != null && newValue.equals(installed.getAbsolutePath()) || newValue.equals(builtIn.getAbsolutePath()))) { - path.setStringValue(newValue); - path.setEnabled(false, getFieldEditorParent()); - } else { - path.setEnabled(true, getFieldEditorParent()); - } - } - - - }; - - path.setErrorMessage("Path must be a valid OpenModelica directory"); - addField(path); - } - - @Override - public void init(IWorkbench workbench) { - } - - +public class ModelicaPreferencePage extends FieldEditorPreferencePage implements + IWorkbenchPreferencePage { + + private static String CUSTOM_PATH = "Custom path"; + + private DirectoryFieldEditor path; + private RadioGroupFieldEditor rg; + + public ModelicaPreferencePage() { + super(GRID); + setDescription("Modelica preferences"); + } + + @Override + public void init(IWorkbench workbench) { + setPreferenceStore(new ScopedPreferenceStore(ConfigurationScope.INSTANCE, Activator.PLUGIN_ID)); + } + + @Override + public void createFieldEditors() { + final File installed = ModelicaManager.getInstalledOMHome(); + final File builtIn = ModelicaManager.getBuiltinOMHome(); + + List optionList = new ArrayList(); + optionList.add(new String[]{CUSTOM_PATH, CUSTOM_PATH}); + if (installed != null) { + optionList.add(new String[]{ "Local installation (" + ModelicaManager.getOMVersion(installed) + ")", installed.getAbsolutePath() }); + } + if (builtIn != null) { + optionList.add(new String[]{ "Built-in (" + ModelicaManager.getOMVersion(builtIn) + ")", builtIn.getAbsolutePath() }); + } + + String[][] options = optionList.toArray(new String[optionList.size()][]); + + rg = new RadioGroupFieldEditor(OpenModelicaPreferences.OM_HOME, + "&Choose the used OpenModelica version", 1, + options, getFieldEditorParent()) { + + @Override + protected void doStore() { + // Do nothing. Path handles saving the value + } + + @Override + protected void fireValueChanged(String property, Object oldValue, Object newValue) { + if((installed != null && newValue.equals(installed.getAbsolutePath())) || (builtIn != null && newValue.equals(builtIn.getAbsolutePath()))) { + path.setStringValue((String)newValue); + path.setEnabled(false, getFieldEditorParent()); + } else { + path.setEnabled(true, getFieldEditorParent()); + } + } + + @Override + public void doLoadDefault() { + System.err.println("LOAD DEFAULT"); + IScopeContext context = ConfigurationScope.INSTANCE; + Preferences node = context.getNode(Activator.PLUGIN_ID); + node.put(OpenModelicaPreferences.OM_HOME, ModelicaManager.getDefaultOMHome().getAbsolutePath()); + load(); + } + }; + + addField(rg); + + path = new DirectoryFieldEditor(OpenModelicaPreferences.OM_HOME, + "&Modelica Home:", getFieldEditorParent()) { + + @Override + public void setValidateStrategy(int value) { + super.setValidateStrategy(StringFieldEditor.VALIDATE_ON_KEY_STROKE); + } + + @Override + public void doStore() { + super.doStore(); + IScopeContext context = ConfigurationScope.INSTANCE; + Preferences node = context.getNode(Activator.PLUGIN_ID); + node.put(OpenModelicaPreferences.OM_HOME, getStringValue()); + } + + @Override + protected boolean doCheckState() { + boolean valid = super.doCheckState(); + if(valid) { + // path is a valid directory + String path = getStringValue(); + File dir = new File(path); + String version = ModelicaManager.getOMVersion(dir); + if(version == null || version.isEmpty()) { + return false; + } + } + + return valid; + } + + @Override + public void doLoad() { + super.doLoad(); + String value = getStringValue(); + updatePath(value); + } + + @Override + public void doLoadDefault() { + updatePath(ModelicaManager.getDefaultOMHome().getAbsolutePath()); + } + + private void updatePath(String newValue) { + if((installed != null && newValue.equals(installed.getAbsolutePath()) || newValue.equals(builtIn.getAbsolutePath()))) { + path.setStringValue(newValue); + path.setEnabled(false, getFieldEditorParent()); + } else { + path.setEnabled(true, getFieldEditorParent()); + } + } + + + }; + + path.setErrorMessage("Path must be a valid OpenModelica directory"); + addField(path); + } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/preferences/SolverPreferencePage.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/preferences/SolverPreferencePage.java new file mode 100644 index 00000000..f0289829 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/preferences/SolverPreferencePage.java @@ -0,0 +1,37 @@ +package org.simantics.sysdyn.ui.preferences; + +import org.eclipse.core.runtime.preferences.ConfigurationScope; +import org.eclipse.jface.preference.FieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.RadioGroupFieldEditor; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.preferences.ScopedPreferenceStore; +import org.simantics.sysdyn.solver.SolverSettings; + +public class SolverPreferencePage extends FieldEditorPreferencePage implements + IWorkbenchPreferencePage { + + private FieldEditor solverEditor; + + public SolverPreferencePage() { + super(GRID); + setDescription("Solver preferences"); + } + + @Override + public void init(IWorkbench workbench) { + setPreferenceStore(new ScopedPreferenceStore(ConfigurationScope.INSTANCE, SolverSettings.QUALIFIER)); + } + + @Override + protected void createFieldEditors() { + solverEditor = new RadioGroupFieldEditor(SolverSettings.SOLVER_TYPE, "Solver type", 1, + new String[][] { + { "Internal", SolverSettings.SOLVER_TYPE_INTERNAL }, + { "Open Modelica", SolverSettings.SOLVER_TYPE_OPENMODELICA } + }, getFieldEditorParent()); + addField(solverEditor); + } + +} diff --git a/org.simantics.sysdyn.ui/sysdyn.product b/org.simantics.sysdyn.ui/sysdyn.product index 0cea8366..921a8d4c 100644 --- a/org.simantics.sysdyn.ui/sysdyn.product +++ b/org.simantics.sysdyn.ui/sysdyn.product @@ -13,8 +13,7 @@ - -fixerrors --data @noDefault + -fixerrors --launcher.XXMaxPermSize 192m -ea -Xmx768M -XX:MaxPermSize=192m -Xshare:off -XstartOnFirstThread -Dorg.eclipse.swt.internal.carbon.smallFonts @@ -31,6 +30,7 @@ + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6 diff --git a/org.simantics.sysdyn/META-INF/MANIFEST.MF b/org.simantics.sysdyn/META-INF/MANIFEST.MF index 2409e1bd..2fffaed1 100644 --- a/org.simantics.sysdyn/META-INF/MANIFEST.MF +++ b/org.simantics.sysdyn/META-INF/MANIFEST.MF @@ -33,7 +33,8 @@ Require-Bundle: org.simantics.objmap;bundle-version="0.1.0", org.simantics.jfreechart;bundle-version="1.0.0", org.jfree.jchart;bundle-version="1.0.13", org.jfree.jcommon;bundle-version="1.0.16", - org.simantics.spreadsheet.graph;bundle-version="1.1.0" + org.simantics.spreadsheet.graph;bundle-version="1.1.0", + fi.semantum.sysdyn.solver;bundle-version="0.1.0" Export-Package: org.simantics.sysdyn, org.simantics.sysdyn.adapter, org.simantics.sysdyn.expressionParser, @@ -47,6 +48,7 @@ Export-Package: org.simantics.sysdyn, org.simantics.sysdyn.representation.utils, org.simantics.sysdyn.representation.visitors, org.simantics.sysdyn.simulation, + org.simantics.sysdyn.solver, org.simantics.sysdyn.tableParser, org.simantics.sysdyn.utils, org.simantics.sysdyn.utils.imports diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/FunctionUtils.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/FunctionUtils.java index 1d79f466..2d860011 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/FunctionUtils.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/FunctionUtils.java @@ -17,7 +17,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -30,176 +29,155 @@ import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.ReadRequest; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; import org.simantics.layer0.Layer0; import org.simantics.sysdyn.Activator; import org.simantics.sysdyn.SysdynResource; public class FunctionUtils { - public static List getLibraryPathsForModelica(final SysdynExperiment sysdynExperiment) { - final ArrayList paths = new ArrayList(); - + // SOMETHING WRONG HERE + + public static List getLibraryPathsForModelica(final SysdynExperiment experiment) { try { - Simantics.getSession().syncRequest(new ReadRequest() { - + return Simantics.getSession().syncRequest(new Read>() { @Override - public void run(ReadGraph graph) throws DatabaseException { - SysdynResource sr = SysdynResource.getInstance(graph); + public List perform(ReadGraph graph) throws DatabaseException { + SysdynResource sr = SysdynResource.getInstance(graph); - Set parents = getParents(graph, sysdynExperiment.getModel(), true); - for(Resource parent : parents) { + List paths = new ArrayList(); + for(Resource parent : getParents(graph, experiment.getModel(), true)) { if(graph.isInstanceOf(parent, sr.SysdynModel)) { - String parentName = NameUtils.getSafeName(graph, parent); - paths.add(parentName + "_functions.mo"); + String modelName = NameUtils.getSafeName(graph, parent); + paths.add(modelName + "_functions.mo"); } else { - String libraryname = NameUtils.getSafeName(graph, parent); - paths.add("..\\\\\\\\..\\\\\\\\libraries\\\\\\\\functions\\\\\\\\" + libraryname + ".mo"); + String libraryName = NameUtils.getSafeName(graph, parent); + paths.add("..\\\\\\\\..\\\\\\\\libraries\\\\\\\\functions\\\\\\\\" + libraryName + ".mo"); } } + return paths; } }); - } catch (DatabaseException e) { + } + catch (DatabaseException e) { + e.printStackTrace(); + return null; + } + } + + public static void updateFunctionFilesForExperiment(final SysdynExperiment experiment) { + try { + Simantics.getSession().syncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + SysdynResource sr = SysdynResource.getInstance(graph); + + for (Resource parent : getParents(graph, experiment.getModel(), false)) { + if(graph.isInstanceOf(parent, sr.SysdynModel)) { + String parentName = NameUtils.getSafeName(graph, parent); + File scriptFile = new File(experiment.getExperimentDir(), parentName + "_functions.mo"); + updateFunctionFile(graph, parent, scriptFile, false); + } else { + updateFunctionFileForLibrary(graph, parent); + } + } + + } + }); + } + catch (DatabaseException e) { e.printStackTrace(); } - - return paths; } - private static Set getParents(ReadGraph graph, Resource model, boolean onlyWithContent) throws DatabaseException{ - HashSet parents = new HashSet(); + private static Set getParents(ReadGraph graph, Resource model, boolean ignoreEmpty) + throws DatabaseException{ + Layer0 l0 = Layer0.getInstance(graph); + SysdynResource sr = SysdynResource.getInstance(graph); + + Set parents = new HashSet(); - if(model == null) + if(model == null) { return parents; + } - Layer0 l0 = Layer0.getInstance(graph); - SysdynResource sr = SysdynResource.getInstance(graph); - parents.add(model); + for(Resource r : graph.getObjects(model, l0.IsLinkedTo)) { if(graph.isInstanceOf(r, sr.SharedFunctionOntology)) { parents.add(r); } else { - Collection libraries = graph.syncRequest(new ObjectsWithType( - r, l0.ConsistsOf, sr.SysdynModelicaFunctionLibrary)); - if(!libraries.isEmpty()) + if(!graph.syncRequest(new ObjectsWithType(r, l0.ConsistsOf, sr.SysdynModelicaFunctionLibrary)).isEmpty()) { parents.add(r); + } } } - if(onlyWithContent) { - HashSet contentParents = new HashSet(); + if(ignoreEmpty) { + Set nonEmptyParents = new HashSet(); for(Resource parent : parents) { - if(hasContent(graph, parent)) - contentParents.add(parent); + if(isNonEmpty(graph, parent)) { + nonEmptyParents.add(parent); + } } - parents = contentParents; + parents = nonEmptyParents; } return parents; - } - private static boolean hasContent(ReadGraph graph, Resource library) { - Layer0 l0 = Layer0.getInstance(graph); + private static boolean isNonEmpty(ReadGraph graph, Resource library) + throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); SysdynResource sr = SysdynResource.getInstance(graph); - try { - if(!graph.syncRequest(new ObjectsWithType(library, l0.ConsistsOf, sr.SysdynModelicaFunction)).isEmpty()) - return true; - else { - for(Resource l : graph.syncRequest(new ObjectsWithType(library, l0.ConsistsOf, sr.SysdynModelicaFunctionLibrary))) { - boolean hasContent = hasContent(graph, l); - if(hasContent) - return true; + + if(!graph.syncRequest(new ObjectsWithType(library, l0.ConsistsOf, sr.SysdynModelicaFunction)).isEmpty()) { + return true; + } else { + for(Resource l : graph.syncRequest(new ObjectsWithType(library, l0.ConsistsOf, sr.SysdynModelicaFunctionLibrary))) { + if(isNonEmpty(graph, l)) { + return true; } } - } catch (DatabaseException e) { - e.printStackTrace(); } - return false; - } - - public static void updateFunctionFilesForExperiment(ReadGraph graph, SysdynExperiment experiment) throws DatabaseException { - SysdynResource sr = SysdynResource.getInstance(graph); - - Set parents = getParents(graph, experiment.getModel(), false); - for(Resource parent : parents) { - if(graph.isInstanceOf(parent, sr.SysdynModel)) { - String parentName = NameUtils.getSafeName(graph, parent); - File scriptFile = new File(experiment.getSimulationDir(), parentName + "_functions.mo"); - updateFunctionFile(graph, parent, scriptFile, false); - } else { - updateFunctionFileForLibrary(graph, parent); - } - } - return; + return false; } - /* - private static File getDir(ReadGraph graph, Resource resource) throws DatabaseException { - SysdynResource sr = SysdynResource.getInstance(graph); - Layer0 l0 = Layer0.getInstance(graph); - - Resource library = resource; - while(!graph.isInstanceOf(library, sr.SysdynModel) && !graph.isInstanceOf(library, l0.Ontology)) { - library = graph.getSingleObject(resource, l0.PartOf); + private static void updateFunctionFile(ReadGraph graph, Resource library, File scriptFile, boolean builtIn) + throws DatabaseException { + PrintStream s; + try { + s = new PrintStream(scriptFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return; } - File dir = null; - - if(graph.isInstanceOf(library, sr.SysdynModel)) { - SimulationResource simu = SimulationResource.getInstance(graph); - Resource configuration = graph.getSingleObject(library, simu.HasConfiguration); - SysdynModelManager smm = SysdynModelManager.getInstance(graph.getSession()); - SysdynModel model = smm.getModel(graph, configuration); - dir = model.getSimulationDir(); - } else { - File librariesDir = Activator.getBundleContext().getDataFile("libraries"); - if (!librariesDir.exists()) { - librariesDir.mkdir(); - } - dir = new File(librariesDir, "functions"); - if (!dir.exists()) { - dir.mkdir(); - } - } - return dir; - } - */ - - public static void createExternalFunctionFile(ReadGraph graph, Resource externalFunction, File scriptFile) throws DatabaseException { SysdynResource sr = SysdynResource.getInstance(graph); - - File dir = scriptFile.getParentFile(); - if(!dir.exists()) - dir.mkdir(); + String name = NameUtils.getSafeName(graph, library); - if(!dir.isDirectory()) - return; - - try { - String name = NameUtils.getSafeName(graph, externalFunction); - if(name.endsWith(".o") || name.endsWith(".a")) { - FileOutputStream fos = new FileOutputStream(dir + "\\" + name); - byte[] fileBArray = graph.getPossibleRelatedValue(externalFunction, sr.ExternalFunctionFile_externalFile, Bindings.BYTE_ARRAY); - fos.write(fileBArray); - fos.close(); - } - } catch (IOException e) { - e.printStackTrace(); + if(!builtIn && !graph.isInstanceOf(library, sr.SysdynModel)) { + s.println("package " + name); + } + writeLibrary(graph, library, scriptFile, s, builtIn); + if(!builtIn && !graph.isInstanceOf(library, sr.SysdynModel)) { + s.println("end " + name + ";\n"); } + + s.close(); } - - protected static void updateFunctionFileForLibrary(ReadGraph graph, Resource library) throws DatabaseException { + private static void updateFunctionFileForLibrary(ReadGraph graph, Resource library) + throws DatabaseException { Layer0 l0 = Layer0.getInstance(graph); while(!graph.isInstanceOf(library, l0.Ontology)) { library = graph.getSingleObject(library, l0.PartOf); } - File librariesDir = Activator.getBundleContext().getDataFile("libraries"); + File librariesDir = Activator.getBundleContext().getDataFile("libraries"); if (!librariesDir.exists()) { librariesDir.mkdir(); } @@ -207,6 +185,7 @@ public class FunctionUtils { if (!dir.exists()) { dir.mkdir(); } + String parentName = NameUtils.getSafeName(graph, library); File scriptFile = new File(dir, parentName + ".mo"); @@ -220,26 +199,6 @@ public class FunctionUtils { } - private static void updateFunctionFile(ReadGraph graph, Resource library, File scriptFile, boolean builtIn) throws DatabaseException { - PrintStream s; - try { - s = new PrintStream(scriptFile); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return; - } - - SysdynResource sr = SysdynResource.getInstance(graph); - String name = NameUtils.getSafeName(graph, library); - if(!builtIn && !graph.isInstanceOf(library, sr.SysdynModel)) - s.println("package " + name); - writeLibrary(graph, library, scriptFile, s, builtIn); - if(!builtIn && !graph.isInstanceOf(library, sr.SysdynModel)) - s.println("end " + name + ";\n"); - - s.close(); - } - private static void writeLibrary(ReadGraph graph, Resource library, File scriptFile, PrintStream stream, boolean builtIn) throws DatabaseException { Layer0 l0 = Layer0.getInstance(graph); SysdynResource sr = SysdynResource.getInstance(graph); @@ -254,7 +213,8 @@ public class FunctionUtils { } } - private static void writeLibraryFunctions(ReadGraph graph, Resource library, File scriptFile, PrintStream stream) throws DatabaseException { + private static void writeLibraryFunctions(ReadGraph graph, Resource library, File scriptFile, PrintStream stream) + throws DatabaseException { Layer0 l0 = Layer0.getInstance(graph); SysdynResource sr = SysdynResource.getInstance(graph); for(Resource function : graph.syncRequest(new ObjectsWithType(library, l0.ConsistsOf, sr.SysdynModelicaFunction))) { @@ -272,4 +232,29 @@ public class FunctionUtils { } } } + + private static void createExternalFunctionFile(ReadGraph graph, Resource externalFunction, File scriptFile) + throws DatabaseException { + SysdynResource sr = SysdynResource.getInstance(graph); + + File dir = scriptFile.getParentFile(); + + if(!dir.exists()) + dir.mkdir(); + + if(!dir.isDirectory()) + return; + + try { + String name = NameUtils.getSafeName(graph, externalFunction); + if(name.endsWith(".o") || name.endsWith(".a")) { + FileOutputStream fos = new FileOutputStream(dir + File.separator + name); + byte[] fileBArray = graph.getPossibleRelatedValue(externalFunction, sr.ExternalFunctionFile_externalFile, Bindings.BYTE_ARRAY); + fos.write(fileBArray); + fos.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/MemoryResult.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/MemoryResult.java index b2ece56a..774d404b 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/MemoryResult.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/MemoryResult.java @@ -37,6 +37,7 @@ import org.simantics.databoard.type.Datatype; import org.simantics.modelica.data.DataSet; import org.simantics.modelica.data.SimulationResult; +// TODO: rename to OpenModelicaResult or something as this is very specific? public class MemoryResult extends SysdynResult { private THashMap results; @@ -58,6 +59,7 @@ public class MemoryResult extends SysdynResult { results = new THashMap(); } + @Override public SysdynDataSet getDataSet(String variable) { // Try to get cached result SysdynDataSet result = results.get(variable); @@ -105,7 +107,7 @@ public class MemoryResult extends SysdynResult { addAllInitialValues(result); // For legacy reasons } - public SimulationResult getSimulationResult() { + private SimulationResult getSimulationResult() { return this.simulationResult; } @@ -116,7 +118,7 @@ public class MemoryResult extends SysdynResult { */ private void addAllInitialValues(SimulationResult result) { // Add initial values - for(DataSet ds : result.getInitialValueDataSets()){ + for(DataSet ds : result.getInitialValueDataSets()){ SysdynDataSet sds = new SysdynDataSet(ds.name, getResultName(), ds.times, ds.values); results.put(ds.name, sds); } @@ -128,6 +130,7 @@ public class MemoryResult extends SysdynResult { * * @param file {@link File} where the {@link RecordAccessor} is saved */ + @Override public void saveToFile(File file, IProgressMonitor progressMonitor) { try { // Create Memory Historian diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/OldSysdynExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/OldSysdynExperiment.java new file mode 100644 index 00000000..87d62c8b --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/OldSysdynExperiment.java @@ -0,0 +1,874 @@ +/******************************************************************************* + * Copyright (c) 2010, 2013 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - Bug #4180 + *******************************************************************************/ +package org.simantics.sysdyn.manager; + +import gnu.trove.set.hash.THashSet; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.locks.Lock; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.osgi.service.prefs.Preferences; +import org.simantics.db.ReadGraph; +import org.simantics.db.RequestProcessor; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.VirtualGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.utils.NameUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.service.VirtualGraphSupport; +import org.simantics.layer0.Layer0; +import org.simantics.modelica.IModelicaMonitor; +import org.simantics.modelica.ModelicaException; +import org.simantics.modelica.ModelicaKeys; +import org.simantics.modelica.ModelicaManager; +import org.simantics.modelica.SimulationLocation; +import org.simantics.modelica.data.CSVSimulationResult; +import org.simantics.modelica.data.MatSimulationResult; +import org.simantics.modelica.data.SimulationResult; +import org.simantics.modelica.preferences.OpenModelicaPreferences; +import org.simantics.simulation.data.Datasource; +import org.simantics.simulation.experiment.ExperimentState; +import org.simantics.simulation.experiment.IExperimentListener; +import org.simantics.simulation.ontology.SimulationResource; +import org.simantics.sysdyn.Activator; +import org.simantics.sysdyn.adapter.VariableValueSubscription; +import org.simantics.sysdyn.modelica.ModelicaWriter; +import org.simantics.sysdyn.representation.Configuration; +import org.simantics.sysdyn.representation.Model; +import org.simantics.sysdyn.simulation.SimulationScheduler; + +public class OldSysdynExperiment extends SysdynExperiment { + + protected Session session; + protected Runnable modificationListener; + protected SysdynModel sysdynModel; + protected boolean toggled = false; + @SuppressWarnings("rawtypes") + protected THashSet variableValueSubscriptions = new THashSet(); + @SuppressWarnings("rawtypes") + protected volatile VariableValueSubscription[] variableValueSubscriptionsSnapshot = null; + + protected String previousModelStructure; + protected HashMap previousParameters; + protected Process process; + protected boolean canceled = false; + protected ExperimentState sysdynExperimentState; + + private SysdynResult result; + private File simulationDir; + + protected String experimentName; + protected static String omcVersion = null; + protected static String omcHome = null; + + public static OldSysdynExperiment INSTANCE; + + public OldSysdynExperiment(Resource experiment, Resource model) { + super(experiment, model); + INSTANCE = this; + } + + public static OldSysdynExperiment getInstance() { + return INSTANCE; + } + + public SysdynResult getCurrentResult() { + if(this.result == null) + this.result = new MemoryResult(null, null); + return this.result; + } + + public Collection getActiveResults() { + ArrayList result = new ArrayList(); + if(getCurrentResult() != null) + result.add(getCurrentResult()); + result.addAll(sysdynModel.getDisplayedResults()); + return result; + } + + /** + * Initialize this experiment + * @param g ReadGraph + */ + public void init(ReadGraph g) { + try { + this.experimentName = NameUtils.getSafeName(g, experiment); + } catch (DatabaseException e) { + this.experimentName = "Experiment"; + } + + this.session = g.getSession(); + state = ExperimentState.STOPPED; + for(IExperimentListener listener : listeners.getListeners()) + listener.stateChanged(state); + + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + final Resource configuration = graph.getPossibleObject(model, SimulationResource.getInstance(graph).HasConfiguration); + sysdynModel = SysdynModelManager.getInstance(session).getModel(graph, configuration); + toggleActivation(graph, true); + } + }); + + setSysdynExperimentState(ExperimentState.INITIALIZING); + } + + @Override + public void saveState() { + if(result == null || !(result instanceof MemoryResult)) + return; + // TODO: temporary fix + SaveResultJob saveResultJob = new SaveResultJob(OldSysdynExperiment.this, session, (MemoryResult)result); + saveResultJob.schedule(); + } + + protected Thread getSaveThread(final SysdynResult result, final File file, final IProgressMonitor progressMonitor) { + return new Thread() { + @Override + public void run() { + if(!canceled) { + // Get and store results result.saveToFile(file, progressMonitor); + } } + }; + } + + /** + * Starts a simulation job. Use this method to start a simulation. + */ + @Override + public void simulate(boolean enabled) { + if(enabled && sysdynModel != null) { + if(!ExperimentState.RUNNING.equals(getState())) { + changeState(ExperimentState.RUNNING); + startSimulationJob(); + } + } else if (!toggled){ + changeState(ExperimentState.STOPPED); + } + } + + /** + * Starts a simulation job + */ + protected void startSimulationJob() { + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + SimulationScheduler.start(sysdynModel, OldSysdynExperiment.this); + } + }); + } + + + /** + * Write model configuration to a single Modelica code + * @param monitor + * @param isGame is the experiment a "game experiment". This is needed for modifying the code to work with FMU simulation + * @return Modelica code + */ + protected String getModelicaCode(IModelicaMonitor monitor, boolean isGame, String modelicaVersion) { + String modelText = null; + try { + // Write all configurations once + modelText = ModelicaWriter.write(sysdynModel.getModules(), isGame, modelicaVersion); + } catch (Exception e) { + // Stop experiment and show console + /*setExperimentStopped(experiment); =>*/ simulate(false); + monitor.showConsole(); + monitor.message("Error when writing Modelica code."); + } + return modelText; + } + + /** + * Get all inits and parameter values required for the inits -file + * @param monitor + * @return All inits in a map + */ + protected HashMap getExperimentParameters(IModelicaMonitor monitor) { + Configuration configuration = sysdynModel.getConfiguration(); +// HashMap inits = sysdynModel.getInits(configuration, ""); Not needed anymore, whole xml content is replaced + HashMap parameters = new HashMap(); + Model model = configuration.getModel(); + Double startTime = model.getStartTime(); + Double stopTime = model.getStopTime(); + parameters.put(ModelicaKeys.START_VALUE, startTime.toString()); + parameters.put(ModelicaKeys.STOP_VALUE, stopTime.toString()); + String outputFormat = "mat"; + parameters.put(ModelicaKeys.OUTPUT_FORMAT, outputFormat); + + Double simulationStepLength = model.getSimulationStepLength(); + if(simulationStepLength != null) { + parameters.put(ModelicaKeys.STEP_VALUE, simulationStepLength.toString()); + parameters.put(ModelicaKeys.NUMBER_OF_INTERVALS, "" + ((int)((stopTime - startTime) / simulationStepLength))); + } else { + parameters.put(ModelicaKeys.STEP_VALUE, "" + (stopTime - startTime) / 500); + } + + Double outputInterval = model.getOutputInterval(); + parameters.put(ModelicaKeys.OUTPUT_INTERVAL, outputInterval != null ? outputInterval.toString() : parameters.get(ModelicaKeys.STEP_VALUE)); + + String method = "\"" + model.getSolver() + "\""; + parameters.put(ModelicaKeys.METHOD, method); + if(model.getTolerance() != null) + parameters.put(ModelicaKeys.TOLERANCE, model.getTolerance().toString()); + String variableFilter = model.getVariableFilter(); + if(variableFilter != null && !variableFilter.isEmpty()) + parameters.put(ModelicaKeys.VARIABLE_FILTER, variableFilter); + return parameters; + } + + /** + * Builds a model + * @param simulationLocation + * @param inits + * @param modelText + * @param monitor + */ + protected void buildModel(SimulationLocation simulationLocation, IModelicaMonitor monitor) { + + try { + simulationLocation.executableFile.delete(); + ModelicaManager.buildModel(simulationLocation, monitor); + } catch (ModelicaException e) { + if(e.getMessage() != null) + monitor.message(e.getMessage()); + monitor.showConsole(); + canceled = true; + previousModelStructure = ""; + previousParameters = null; + } + } + + /** + * Run a built model + * @param structureChanged + * @throws IOException + */ + protected void runModelica(SimulationLocation simulationLocation, IModelicaMonitor monitor, IProgressMonitor progressMonitor, HashMap experimentParameters, HashMap changes) throws IOException { + progressMonitor.subTask("Simulate model"); + process = ModelicaManager.runModelica( + simulationLocation, + monitor, + experimentParameters, + changes + ); + ModelicaManager.printProcessOutput(process, monitor); + + Thread resultThread = getResultThread(simulationLocation, experimentParameters, monitor, progressMonitor); + resultThread.run(); + + process = null; + } + + /** + * Get a thread for reading and saving reuslts from a normal simulation + * @param simulationLocation + * @param inits + * @param monitor + * @param progressMonitor + * @return + */ + protected Thread getResultThread(final SimulationLocation simulationLocation, final HashMap experimentParameters, final IModelicaMonitor monitor, final IProgressMonitor progressMonitor) { + return new Thread() { + @Override + public void run() { + try { + process.waitFor(); + + if(!canceled) { + // Get and store results + progressMonitor.worked(1); + progressMonitor.subTask("Read results"); + SimulationResult result; + if(simulationLocation.resultFile.getName().endsWith(".csv")) + result = new CSVSimulationResult(); + else if(simulationLocation.resultFile.getName().endsWith(".plt")) + result = new SimulationResult(); + else + result = new MatSimulationResult(); // The latest format + + // The interval of results saved. Every result? Every other result? etc... + int outIntervalInt = 1; + String outputInterval = experimentParameters.get(ModelicaKeys.OUTPUT_INTERVAL); + if(outputInterval != null) { + String stepTime = experimentParameters.get(ModelicaKeys.STEP_VALUE); + String stopTime = experimentParameters.get(ModelicaKeys.STOP_VALUE); + + Double step = Double.parseDouble(stepTime); + Double stop = Double.parseDouble(stopTime); + Double outInterval = Double.parseDouble(outputInterval); + + outIntervalInt = (int)getInterval(outInterval, step); + // Actually you might be able to use an outInterval one or two longer. + int maxIntervalInt = (int)Math.round(stop / step); + if (outIntervalInt > maxIntervalInt) + outIntervalInt = maxIntervalInt; + } + + result.initRead(simulationLocation.resultFile); + result.readTime(simulationLocation.resultFile, outIntervalInt); + //result.readInits(simulationLocation.initFile); // Parameter values are read from .mat + result.filter(); + ((MemoryResult)getCurrentResult()).setResult(result); + ((MemoryResult)getCurrentResult()).setResultFile(simulationLocation.resultFile); + progressMonitor.worked(1); + resultsChanged(); + + simulate(false); + + String errorString = result.getResultReadErrors(); + if(errorString != null && !errorString.isEmpty()) + monitor.message(errorString); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }; + } + + protected static long getInterval(double outputLength, double stepLength) { + double interval = outputLength / stepLength; + if (interval <= 1) + return 1; + return Math.round(interval); + } + + + /** + * + * @param sysdynModel + * @param modelText + * @param inits + * @param additionalScript + * @return + * @throws IOException + */ + protected SimulationLocation createSimulationFiles(SysdynModel sysdynModel, String modelText, HashMap inits, String additionalScript, boolean fmu) throws IOException { + File simulationDir = getExperimentDir(); + + // update all function files. both the model's and built-in + FunctionUtils.updateFunctionFilesForExperiment(this); + + + SimulationLocation location = ModelicaManager.createSimulationLocation(simulationDir, sysdynModel.getConfiguration().getLabel(), modelText); + if (fmu) { + ModelicaManager.createFMUSimulationScripts(location, inits, additionalScript); + } + else { + ModelicaManager.createSimulationScripts(location, inits, additionalScript); + } + return location; + } + + /** + * Get a simulation directory for this model + * @return File directory + */ + public File getExperimentDir() { + if(simulationDir == null) { + File modelsDir = Activator.getBundleContext().getDataFile("models"); + String experimentName = this.experimentName; + List files = Arrays.asList(modelsDir.list()); + if (files.contains(experimentName)) { + int i = 2; + while (files.contains(experimentName + "_" + i)){ + i++; + } + experimentName += "_" + i; + } + + simulationDir = Activator.getBundleContext().getDataFile("models/" + experimentName); + if (!simulationDir.exists()) { + simulationDir.mkdir(); + } + } + return simulationDir; + } + + /** + * + * @return + */ + protected String getAdditionalScripts() { + StringBuilder functionscript = new StringBuilder(); + for(String path : FunctionUtils.getLibraryPathsForModelica(this)) { + functionscript.append("loadFile(\"" + path + "\");\n"); + } + return functionscript.toString(); + } + + /** + * Starts simulating a model. Call only from inside simulation job! Start simulation using simulate(true). + * @param monitor + * @param progressMonitor + * @throws IOException + */ + public synchronized void simulate(final IModelicaMonitor monitor, final IProgressMonitor progressMonitor, String modelName) throws IOException { + canceled = false; + progressMonitor.subTask("Write modelica classes"); + + omcVersion = ModelicaManager.getDefaultOMVersion(); + + monitor.message("Simulate " + modelName + " using OpenModelica " + omcVersion); + + // Get Modelica code + String modelText = getModelicaCode(monitor, false, omcVersion); + if(modelText == null) + return; + progressMonitor.worked(1); + + // Write initial files and add init-parameters + progressMonitor.subTask("Write simulation files"); + HashMap experimentParameters = getExperimentParameters(monitor); + + // add loadFile script to load all related functions and function libraries + String additionalScript = getAdditionalScripts(); + + // Create simulation files + SimulationLocation simulationLocation = createSimulationFiles(sysdynModel, modelText, experimentParameters, additionalScript, false); + progressMonitor.worked(1); + + // Build the model and store previous model structure and inits that affect the building + // If there is no exe file OR the model structure has not changed, no need to build + String flatModelText = ModelicaManager.getFlatModelText(simulationLocation, monitor, FunctionUtils.getLibraryPathsForModelica(this)); + boolean structureChanged = sysdynModel.isStructureModified(); + + if (!simulationLocation.executableFile.isFile() || structureChanged) { + progressMonitor.subTask("Build model"); + previousModelStructure = flatModelText; + previousParameters = ModelicaManager.getModelParameters(previousModelStructure); + + buildModel(simulationLocation, monitor); + } + + // Add changed parameters in case that structure has not changed + HashMap changes = structureChanged ? null : new HashMap(); + if(!structureChanged && previousParameters != null && omcVersion.startsWith("1.9")) { + HashMap newParameters = ModelicaManager.getModelParameters(flatModelText); + for(String key : previousParameters.keySet()) { + if(!previousParameters.get(key).equals(newParameters.get(key))) { + changes.put(key, newParameters.get(key)); + } + } + previousParameters = newParameters; + } + progressMonitor.worked(1); + + if(simulationLocation != null && !canceled) { + // Simulate the model + runModelica(simulationLocation, monitor, progressMonitor, experimentParameters, changes); + } + + if(canceled) + simulate(false); + process = null; + } + + /** + * Get the version of the OpenModelica compiler that is defined to be used + * in Preferences + * @return OpenModelica version + */ + protected String getOpenModelicaVersion() { + String omVersion = null; + + IScopeContext context = DefaultScope.INSTANCE; + Preferences node = context.getNode(org.simantics.modelica.Activator.PLUGIN_ID); + String omHome = node.get(OpenModelicaPreferences.OM_HOME, null); + if(omHome != null) { + File omHomeDir = new File(omHome); + if(omHomeDir != null && omHomeDir.isDirectory()) + omVersion = ModelicaManager.getOMVersion(omHomeDir); + } + + if(omVersion == null) { + omVersion = ModelicaManager.getDefaultOMVersion(); + } + + return omVersion; + } + + + /** + * Method that compares given modelText and inits to previous model and inits + * @param modelText Textual representation of a model (Modelica code) + * @param inits map of init parameters + * @return true if the model has changed, false otherwise + */ +// protected boolean hasStructureChanged(String modelText) { +// +// if(previousModelStructure == null) +// return true; +// +// // Then compare the actual model structure +// BufferedReader current = new BufferedReader( +// new StringReader(modelText)); +// BufferedReader previous = new BufferedReader( +// new StringReader(previousModelStructure)); +// +// String c, p; +// try { +// // Read both current and previous model texts at the same time +// c = current.readLine(); +// p = previous.readLine(); +// +// while (c != null && p != null) { +// // if the lines are the same, no need for further examination +// if(!c.equals(p)) { +// if(c.contains("parameter") && p.contains("parameter")) { +// /* +// * The line is a parameter definition. +// * In this case only what is before '=' matters +// * +// * parameter Real Var = 1; +// * is structurally same as +// * parameter Real Var = 2; +// */ +// int i = c.indexOf("="); +// if(!c.substring(0, i).equals(p.substring(0, i))) { +// // different parameter definition +// return true; +// } +// } else { +// // other than a line containing parameters differs +// return true; +// } +// } +// c = current.readLine(); +// p = previous.readLine(); +// } +// +// if((c == null && p != null) || (c != null && p == null)) { +// // different lengths +// return true; +// } +// +// } catch(IOException e) { +// // Something went wrong in the comparison, it is safer to say that the structure has changed +// return true; +// } +// return false; +// } + + /** + * Destroy an ongoing simulation process + */ + public void cancelSimulation() { + canceled = true; + if(process != null) { + process.destroy(); + } + } + + /** + * Toggle simulation state + * @param enabled true == RUNNING, false == STOPPED + */ + public void toggleSimulation(boolean enabled) { + if(enabled) { + this.toggled = true; + changeState(ExperimentState.RUNNING); + if(modificationListener == null) { + + modificationListener = new Runnable() { + + @Override + public void run() { + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + if(getState() == ExperimentState.RUNNING) { + SimulationScheduler.start(sysdynModel, OldSysdynExperiment.this); + } + + } + }); + + }; + }; + sysdynModel.addModificationListener(modificationListener); + } + } + else { + changeState(ExperimentState.STOPPED); + this.toggled = false; + } + + } + + @Override + public void refresh(RequestProcessor session) { + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + init(graph); + } + + }); + } + + @Override + public void refresh(Session session) { + refresh((RequestProcessor)session); + } + + @Override + protected void localStateChange() { + setSysdynExperimentState(getState()); + switch(state) { + case DISPOSED: + onExperimentDisposed(); + break; + default: + break; + } + + } + + /** + * Returns sysdyn experiment state. It is usually the same as ordinary experiment state. + * Initializing phase takes longer than normally in game experiments. + * @return + */ + public ExperimentState getSysdynExperimentState() { + return sysdynExperimentState; + } + + protected void setSysdynExperimentState(final ExperimentState state) { + sysdynExperimentState = state; + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + VirtualGraphSupport support = graph.getService(VirtualGraphSupport.class); + final Session session = graph.getSession(); + session.asyncRequest(new WriteRequest(support.getWorkspacePersistent("experiments")) { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + SimulationResource SR = SimulationResource.getInstance(graph); + graph.deny(model, SR.HasExperimentState); + graph.deny(experiment, SR.HasExperimentState); + + Resource st = graph.newResource(); + switch(state) { + case INITIALIZING: + graph.claim(st, L0.InstanceOf, SR.ExperimentState_Initializing); + break; + case RUNNING: + graph.claim(st, L0.InstanceOf, SR.ExperimentState_Running); + break; + case STOPPED: + graph.claim(st, L0.InstanceOf, SR.ExperimentState_Stopped); + break; + case DISPOSED: + graph.claim(st, L0.InstanceOf, SR.ExperimentState_Disposed); + break; + } + + graph.claim(model, SR.HasExperimentState, st); + graph.claim(experiment, SR.HasExperimentState, st); + }}); + } + }); + } + + /** + * 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); + } + }); + } + + + /** + * Toggles the active-state of this experiment on or off + * @param graph ReadGraph + * @param activate The active-state of this experiment + */ + protected void toggleActivation(ReadGraph graph, final boolean activate) { + VirtualGraphSupport support = graph.getService(VirtualGraphSupport.class); + final Session session = graph.getSession(); + session.asyncRequest(new WriteRequest(support.getWorkspacePersistent("experiments")) { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + VirtualGraph runtime = graph.getService(VirtualGraph.class); + + session.asyncRequest(new WriteRequest(runtime) { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + SimulationResource SIMU = SimulationResource.getInstance(graph); + if(activate) + graph.claim(experiment, SIMU.IsActive, experiment); + else + graph.denyStatement(experiment, SIMU.IsActive, experiment); + } + + }); + } + }); + } + + + /* Result subscriptions */ + + @SuppressWarnings("rawtypes") + /** + * Copy from AprosExperiment + * @param subscription + */ + @Override + public void addVariableValueSubscription(VariableValueSubscription subscription) { + assert subscription != null; + synchronized (variableValueSubscriptions) { + //System.out.println("ADD listener " + subscription); + variableValueSubscriptions.add(subscription); + variableValueSubscriptionsSnapshot = null; + } + } + + @SuppressWarnings("rawtypes") + /** + * Copy from AprosExperiment + * @param subscription + */ + @Override + public void removeVariableValueSubscription(VariableValueSubscription subscription) { + assert subscription != null; + synchronized (variableValueSubscriptions) { + //System.out.println("REMOVE listener " + subscription); + variableValueSubscriptions.remove(subscription); + variableValueSubscriptionsSnapshot = null; + } + } + + @SuppressWarnings("rawtypes") + /** + * Copy from AprosExperiment + * @return + */ + @Override + public VariableValueSubscription[] getListenerSnapshot() { + VariableValueSubscription[] snapshot = variableValueSubscriptionsSnapshot; + if (snapshot == null) { + synchronized (variableValueSubscriptions) { + snapshot = variableValueSubscriptionsSnapshot; + if (snapshot == null) { + snapshot = variableValueSubscriptionsSnapshot = variableValueSubscriptions.toArray(new VariableValueSubscription[variableValueSubscriptions.size()]); + } + } + //System.out.println("listener count: " + snapshot.length); + } + return snapshot; + } + + volatile long previousVariableUpdateTime = 0; + volatile boolean skippedVariableUpdate = true; + + + /** + * Modified copy from AprosExperiment + */ + public void resultsChanged() { + long time = System.nanoTime(); + if(time - previousVariableUpdateTime > 100000000) { + updateSubscriptions(); + previousVariableUpdateTime = time; + } + else + skippedVariableUpdate = true; + } + + @SuppressWarnings("rawtypes") + /** + * Modified copy from AporsExperiment + */ + @Override + public void updateSubscriptions() { + for(VariableValueSubscription subscription : getListenerSnapshot()) + subscription.update(); + skippedVariableUpdate = false; + } + + public int numberOfSimulationRunSteps() { + /* + * 1. Write modelica files + * 2. Write other simulation files + * 3. Build model OR update parameters + * 4. Run modelica + * 5. Read results + */ + return 5; + } + + + /* Experiment methods that are not used in this experiment */ + + @Override + public Lock getDatasourceLock() { + return null; + } + + @Override + public Datasource getDatasource() { + return null; + } + + @Override + public void simulateDuration(double duration) { + System.out.println("simulateDuartion"); + } + + + @Override + public void rewindTo(double time) { + System.out.println("rewindTo"); + } + +} + diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SaveResultJob.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SaveResultJob.java index caf06b3d..38a87e6c 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SaveResultJob.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SaveResultJob.java @@ -40,12 +40,12 @@ import org.simantics.sysdyn.SysdynResource; public class SaveResultJob extends Job { private final MemoryResult sysdynResult; - private final SysdynExperiment experiment; + private final OldSysdynExperiment experiment; private final Session session; private IProgressMonitor monitor; private File file; - public SaveResultJob(final SysdynExperiment experiment, Session session, final MemoryResult result) { + public SaveResultJob(final OldSysdynExperiment experiment, Session session, final MemoryResult result) { super("Save Result"); this.experiment = experiment; this.sysdynResult = result; @@ -71,7 +71,7 @@ public class SaveResultJob extends Job { if(!root.isDirectory()) root.mkdir(); File projectRoot = new File(root, projectName); if(!projectRoot.isDirectory()) projectRoot.mkdir(); - File file = new File( projectRoot, UUID.randomUUID().toString() + ".dbb"); + File file = new File(projectRoot, UUID.randomUUID().toString() + ".dbb"); return file; } }); diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SaveResultSetJob.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SaveResultSetJob.java index 21385549..ea2f9e62 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SaveResultSetJob.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SaveResultSetJob.java @@ -41,12 +41,12 @@ import org.simantics.sysdyn.SysdynResource; public class SaveResultSetJob extends Job { private final ArrayList sysdynResults; - private final SysdynExperiment experiment; + private final OldSysdynExperiment experiment; private final Session session; private IProgressMonitor monitor; private File file; - public SaveResultSetJob(final SysdynExperiment experiment, Session session, final ArrayList results) { + public SaveResultSetJob(final OldSysdynExperiment experiment, Session session, final ArrayList results) { super("Save Results"); this.experiment = experiment; this.sysdynResults = results; diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynConsole.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynConsole.java index c6334cfa..3d20128c 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynConsole.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynConsole.java @@ -15,9 +15,9 @@ import org.eclipse.ui.console.MessageConsole; import org.eclipse.ui.console.MessageConsoleStream; import org.eclipse.ui.console.PatternMatchEvent; import org.eclipse.ui.console.TextConsole; -import org.simantics.modelica.IModelicaMonitor; +import org.simantics.sysdyn.solver.ISolverMonitor; -public class SysdynConsole implements IModelicaMonitor { +public class SysdynConsole implements ISolverMonitor { private static String SYSDYN_CONSOLE = "Sysdyn modelica console"; private MessageConsole console; @@ -164,7 +164,6 @@ public class SysdynConsole implements IModelicaMonitor { IConsoleManager conMan = plugin.getConsoleManager(); conMan.showConsoleView(console); } - class IssueLink implements IHyperlink { @@ -198,7 +197,7 @@ public class SysdynConsole implements IModelicaMonitor { @Override public void linkActivated() { - System.out.println("MODELICA LINK"); + System.err.println("MODELICA LINK"); } } 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 d7c488df..6bfd9706 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java @@ -15,20 +15,13 @@ package org.simantics.sysdyn.manager; import gnu.trove.set.hash.THashSet; import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; import java.util.List; import java.util.concurrent.locks.Lock; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.preferences.DefaultScope; -import org.eclipse.core.runtime.preferences.IScopeContext; -import org.osgi.service.prefs.Preferences; import org.simantics.db.ReadGraph; import org.simantics.db.RequestProcessor; import org.simantics.db.Resource; @@ -41,15 +34,6 @@ import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.service.VirtualGraphSupport; import org.simantics.layer0.Layer0; -import org.simantics.modelica.IModelicaMonitor; -import org.simantics.modelica.ModelicaException; -import org.simantics.modelica.ModelicaKeys; -import org.simantics.modelica.ModelicaManager; -import org.simantics.modelica.SimulationLocation; -import org.simantics.modelica.data.CSVSimulationResult; -import org.simantics.modelica.data.MatSimulationResult; -import org.simantics.modelica.data.SimulationResult; -import org.simantics.modelica.preferences.OpenModelicaPreferences; import org.simantics.simulation.data.Datasource; import org.simantics.simulation.experiment.Experiment; import org.simantics.simulation.experiment.ExperimentState; @@ -58,839 +42,455 @@ import org.simantics.simulation.experiment.IExperimentListener; import org.simantics.simulation.ontology.SimulationResource; import org.simantics.sysdyn.Activator; import org.simantics.sysdyn.adapter.VariableValueSubscription; -import org.simantics.sysdyn.modelica.ModelicaWriter; -import org.simantics.sysdyn.representation.Configuration; -import org.simantics.sysdyn.representation.Model; -import org.simantics.sysdyn.simulation.SimulationScheduler; +import org.simantics.sysdyn.solver.ISolverMonitor; +import org.simantics.sysdyn.solver.ISolver; +import org.simantics.sysdyn.solver.InternalSolver; +import org.simantics.sysdyn.solver.SimulationJob; +import org.simantics.sysdyn.solver.SolverSettings; +import org.simantics.sysdyn.solver.SolverSettings.SolverType; public class SysdynExperiment extends Experiment implements IDynamicExperiment, VariableSubscriptionManager { - - protected Session session; - protected Runnable modificationListener; - protected SysdynModel sysdynModel; - protected boolean toggled = false; - @SuppressWarnings("rawtypes") - protected THashSet variableValueSubscriptions = new THashSet(); - @SuppressWarnings("rawtypes") - protected volatile VariableValueSubscription[] variableValueSubscriptionsSnapshot = null; - - protected String previousModelStructure; - protected HashMap previousParameters; - protected Process process; - protected boolean canceled = false; - protected ExperimentState sysdynExperimentState; - - private MemoryResult result; - private File simulationDir; - - protected String experimentName; - protected static String omcVersion = null; - protected static String omcHome = null; - - public static SysdynExperiment INSTANCE; - - public SysdynExperiment(Resource experiment, Resource model) { - super(experiment, model); - INSTANCE = this; - } - - public static SysdynExperiment getInstance() { - return INSTANCE; - } - - public MemoryResult getCurrentResult() { - if(this.result == null) - this.result = new MemoryResult(null, null); - return this.result; - } - - public Collection getActiveResults() { - ArrayList result = new ArrayList(); - if(getCurrentResult() != null) - result.add(getCurrentResult()); - result.addAll(sysdynModel.getDisplayedResults()); - return result; - } - - /** - * Initialize this experiment - * @param g ReadGraph - */ - public void init(ReadGraph g) { - try { - this.experimentName = NameUtils.getSafeName(g, experiment); - } catch (DatabaseException e) { - this.experimentName = "Experiment"; - } - - this.session = g.getSession(); - state = ExperimentState.STOPPED; - for(IExperimentListener listener : listeners.getListeners()) - listener.stateChanged(state); - - session.asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - final Resource configuration = graph.getPossibleObject(model, SimulationResource.getInstance(graph).HasConfiguration); - sysdynModel = SysdynModelManager.getInstance(session).getModel(graph, configuration); - toggleActivation(graph, true); - } - }); - - setSysdynExperimentState(ExperimentState.INITIALIZING); - } - - @Override - public void saveState() { - if(result == null || !(result instanceof MemoryResult)) - return; - SaveResultJob saveResultJob = new SaveResultJob(SysdynExperiment.this, session, result); - saveResultJob.schedule(); - } - - protected Thread getSaveThread(final SysdynResult result, final File file, final IProgressMonitor progressMonitor) { - return new Thread() { - @Override - public void run() { - if(!canceled) { - // Get and store results result.saveToFile(file, progressMonitor); - } } - }; - } - - /** - * Starts a simulation job. Use this method to start a simulation. - */ - @Override - public void simulate(boolean enabled) { - if(enabled && sysdynModel != null) { - if(!ExperimentState.RUNNING.equals(getState())) { - changeState(ExperimentState.RUNNING); - startSimulationJob(); - } - } else if (!toggled){ - changeState(ExperimentState.STOPPED); - } - } - - /** - * Starts a simulation job - */ - protected void startSimulationJob() { - session.asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - SimulationScheduler.start(sysdynModel, SysdynExperiment.this); - } - }); - } - - - /** - * Write model configuration to a single Modelica code - * @param monitor - * @param isGame is the experiment a "game experiment". This is needed for modifying the code to work with FMU simulation - * @return Modelica code - */ - protected String getModelicaCode(IModelicaMonitor monitor, boolean isGame, String modelicaVersion) { - String modelText = null; - try { - // Write all configurations once - modelText = ModelicaWriter.write(sysdynModel.getModules(), isGame, modelicaVersion); - } catch (Exception e) { - // Stop experiment and show console - /*setExperimentStopped(experiment); =>*/ simulate(false); - monitor.showConsole(); - monitor.message("Error when writing Modelica code."); - } - return modelText; - } - - /** - * Get all inits and parameter values required for the inits -file - * @param monitor - * @return All inits in a map - */ - protected HashMap getExperimentParameters(IModelicaMonitor monitor) { - Configuration configuration = sysdynModel.getConfiguration(); -// HashMap inits = sysdynModel.getInits(configuration, ""); Not needed anymore, whole xml content is replaced - HashMap parameters = new HashMap(); - Model model = configuration.getModel(); - Double startTime = model.getStartTime(); - Double stopTime = model.getStopTime(); - parameters.put(ModelicaKeys.START_VALUE, startTime.toString()); - parameters.put(ModelicaKeys.STOP_VALUE, stopTime.toString()); - String outputFormat = "mat"; - parameters.put(ModelicaKeys.OUTPUT_FORMAT, outputFormat); - - Double simulationStepLength = model.getSimulationStepLength(); - if(simulationStepLength != null) { - parameters.put(ModelicaKeys.STEP_VALUE, simulationStepLength.toString()); - parameters.put(ModelicaKeys.NUMBER_OF_INTERVALS, "" + ((int)((stopTime - startTime) / simulationStepLength))); - } else { - parameters.put(ModelicaKeys.STEP_VALUE, "" + (stopTime - startTime) / 500); - } - - Double outputInterval = model.getOutputInterval(); - parameters.put(ModelicaKeys.OUTPUT_INTERVAL, outputInterval != null ? outputInterval.toString() : parameters.get(ModelicaKeys.STEP_VALUE)); - - String method = "\"" + model.getSolver() + "\""; - parameters.put(ModelicaKeys.METHOD, method); - if(model.getTolerance() != null) - parameters.put(ModelicaKeys.TOLERANCE, model.getTolerance().toString()); - String variableFilter = model.getVariableFilter(); - if(variableFilter != null && !variableFilter.isEmpty()) - parameters.put(ModelicaKeys.VARIABLE_FILTER, variableFilter); - return parameters; - } - - /** - * Builds a model - * @param simulationLocation - * @param inits - * @param modelText - * @param monitor - */ - protected void buildModel(SimulationLocation simulationLocation, IModelicaMonitor monitor) { - - try { - simulationLocation.executableFile.delete(); - ModelicaManager.buildModel(simulationLocation, monitor); - } catch (ModelicaException e) { - if(e.getMessage() != null) - monitor.message(e.getMessage()); - monitor.showConsole(); - canceled = true; - previousModelStructure = ""; - previousParameters = null; - } - } - - /** - * Run a built model - * @param structureChanged - * @throws IOException - */ - protected void runModelica(SimulationLocation simulationLocation, IModelicaMonitor monitor, IProgressMonitor progressMonitor, HashMap experimentParameters, HashMap changes) throws IOException { - progressMonitor.subTask("Simulate model"); - process = ModelicaManager.runModelica( - simulationLocation, - monitor, - experimentParameters, - changes - ); - ModelicaManager.printProcessOutput(process, monitor); - - Thread resultThread = getResultThread(simulationLocation, experimentParameters, monitor, progressMonitor); - resultThread.run(); - - process = null; - } - - /** - * Get a thread for reading and saving reuslts from a normal simulation - * @param simulationLocation - * @param inits - * @param monitor - * @param progressMonitor - * @return - */ - protected Thread getResultThread(final SimulationLocation simulationLocation, final HashMap experimentParameters, final IModelicaMonitor monitor, final IProgressMonitor progressMonitor) { - return new Thread() { - @Override - public void run() { - try { - process.waitFor(); - - if(!canceled) { - // Get and store results - progressMonitor.worked(1); - progressMonitor.subTask("Read results"); - SimulationResult result; - if(simulationLocation.resFile.getName().endsWith(".csv")) - result = new CSVSimulationResult(); - else if(simulationLocation.resFile.getName().endsWith(".plt")) - result = new SimulationResult(); - else - result = new MatSimulationResult(); // The latest format - - // The interval of results saved. Every result? Every other result? etc... - int outIntervalInt = 1; - String outputInterval = experimentParameters.get(ModelicaKeys.OUTPUT_INTERVAL); - if(outputInterval != null) { - String stepTime = experimentParameters.get(ModelicaKeys.STEP_VALUE); - String stopTime = experimentParameters.get(ModelicaKeys.STOP_VALUE); - - Double step = Double.parseDouble(stepTime); - Double stop = Double.parseDouble(stopTime); - Double outInterval = Double.parseDouble(outputInterval); - - outIntervalInt = (int)getInterval(outInterval, step); - // Actually you might be able to use an outInterval one or two longer. - int maxIntervalInt = (int)Math.round(stop / step); - if (outIntervalInt > maxIntervalInt) - outIntervalInt = maxIntervalInt; - } - - result.initRead(simulationLocation.resFile); - result.readTime(simulationLocation.resFile, outIntervalInt); - //result.readInits(simulationLocation.initFile); // Parameter values are read from .mat - result.filter(); - getCurrentResult().setResult(result); - getCurrentResult().setResultFile(simulationLocation.resFile); - progressMonitor.worked(1); - resultsChanged(); - - simulate(false); - - String errorString = result.getResultReadErrors(); - if(errorString != null && !errorString.isEmpty()) - monitor.message(errorString); - } - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - }; - } - - protected static long getInterval(double outputLength, double stepLength) { - double interval = outputLength / stepLength; - if (interval <= 1) - return 1; - return Math.round(interval); - } - - - /** - * - * @param sysdynModel - * @param modelText - * @param inits - * @param additionalScript - * @return - * @throws IOException - */ - protected SimulationLocation createSimulationFiles(SysdynModel sysdynModel, String modelText, HashMap inits, String additionalScript, boolean fmu) throws IOException { - File simulationDir = getSimulationDir(); - - // update all function files. both the model's and built-in - try { - final SysdynExperiment experiment = this; - session.syncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - FunctionUtils.updateFunctionFilesForExperiment(graph, experiment); - } - }); - } catch (DatabaseException e) { - e.printStackTrace(); - } - - return ModelicaManager.createSimulationFiles( - simulationDir, - sysdynModel.getConfiguration().getLabel(), - modelText, - inits, - additionalScript, - fmu); - } - - /** - * Get a simulation directory for this model - * @return File directory - */ - public File getSimulationDir() { - if(simulationDir == null) { + + // TODO: change to protected as necessary when oldSysdynExperiment is removed + + private Session session; + private Runnable modificationListener; + private SysdynModel sysdynModel; + private boolean toggled = false; + + @SuppressWarnings("rawtypes") + private THashSet variableValueSubscriptions = new THashSet(); + @SuppressWarnings("rawtypes") + private VariableValueSubscription[] variableValueSubscriptionsSnapshot = null; + + private Process process; + private boolean canceled = false; + private ExperimentState sysdynExperimentState; + + private SysdynResult result; + + private ISolver solver; + + private String experimentName; + private File experimentDir; + + public SysdynExperiment(Resource experiment, Resource model) { + super(experiment, model); + this.solver = null; + this.experimentName = "Experiment"; + this.experimentDir = null; + } + + public SysdynResult getCurrentResult() { + if(this.result == null) + this.result = new MemoryResult(null, null); + return this.result; + } + + public void setCurrentResult(SysdynResult result) { + this.result = result; + } + + public Collection getActiveResults() { + ArrayList result = new ArrayList(); + if(getCurrentResult() != null) + result.add(getCurrentResult()); + result.addAll(sysdynModel.getDisplayedResults()); + return result; + } + + /** + * Initialize this experiment + * @param g ReadGraph + */ + public void init(ReadGraph g) { + try { + this.experimentName = NameUtils.getSafeName(g, experiment); + } catch (DatabaseException e) { + this.experimentName = "Experiment"; + } + + this.session = g.getSession(); + state = ExperimentState.STOPPED; + for(IExperimentListener listener : listeners.getListeners()) + listener.stateChanged(state); + + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + final Resource configuration = graph.getPossibleObject(model, SimulationResource.getInstance(graph).HasConfiguration); + sysdynModel = SysdynModelManager.getInstance(session).getModel(graph, configuration); + toggleActivation(graph, true); + } + }); + + setSysdynExperimentState(ExperimentState.INITIALIZING); + } + + @Override + public void saveState() { + if(result == null || !(result instanceof MemoryResult)) + return; + // TODO: fix this + //SaveResultJob saveResultJob = new SaveResultJob(AltSysdynExperiment.this, session, result); + //saveResultJob.schedule(); + } + + protected Thread getSaveThread(final SysdynResult result, final File file, final IProgressMonitor progressMonitor) { + return new Thread() { + @Override + public void run() { + if(!canceled) { + // Get and store results result.saveToFile(file, progressMonitor); + } } + }; + } + + @Override + public void simulate(boolean enabled) { + // TODO: add state checks + if (enabled) { + SimulationJob job = new SimulationJob(sysdynModel.getConfiguration().getLabel(), this); + job.schedule(); + } + } + + /** + * Destroy an ongoing simulation process + */ + public void cancelSimulation() { + canceled = true; + if(process != null) { + process.destroy(); + } + } + + /** + * Toggle simulation state + * @param enabled true == RUNNING, false == STOPPED + */ + public void toggleSimulation(boolean enabled) { + if(enabled) { + this.toggled = true; + changeState(ExperimentState.RUNNING); + if(modificationListener == null) { + + modificationListener = new Runnable() { + + @Override + public void run() { + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + if(getState() == ExperimentState.RUNNING) { + // TODO: fix this + //SimulationScheduler.start(sysdynModel, this); + } + + } + }); + + }; + }; + sysdynModel.addModificationListener(modificationListener); + } + } + else { + changeState(ExperimentState.STOPPED); + this.toggled = false; + } + + } + + @Override + public void refresh(RequestProcessor session) { + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + init(graph); + } + + }); + } + + @Override + public void refresh(Session session) { + refresh((RequestProcessor)session); + } + + @Override + protected void localStateChange() { + setSysdynExperimentState(getState()); + switch(state) { + case DISPOSED: + onExperimentDisposed(); + break; + default: + break; + } + + } + + /** + * Returns sysdyn experiment state. It is usually the same as ordinary experiment state. + * Initializing phase takes longer than normally in game experiments. + * @return + */ + public ExperimentState getSysdynExperimentState() { + return sysdynExperimentState; + } + + protected void setSysdynExperimentState(final ExperimentState state) { + sysdynExperimentState = state; + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + VirtualGraphSupport support = graph.getService(VirtualGraphSupport.class); + final Session session = graph.getSession(); + session.asyncRequest(new WriteRequest(support.getWorkspacePersistent("experiments")) { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + Layer0 L0 = Layer0.getInstance(graph); + SimulationResource SR = SimulationResource.getInstance(graph); + graph.deny(model, SR.HasExperimentState); + graph.deny(experiment, SR.HasExperimentState); + + Resource st = graph.newResource(); + switch(state) { + case INITIALIZING: + graph.claim(st, L0.InstanceOf, SR.ExperimentState_Initializing); + break; + case RUNNING: + graph.claim(st, L0.InstanceOf, SR.ExperimentState_Running); + break; + case STOPPED: + graph.claim(st, L0.InstanceOf, SR.ExperimentState_Stopped); + break; + case DISPOSED: + graph.claim(st, L0.InstanceOf, SR.ExperimentState_Disposed); + break; + } + + graph.claim(model, SR.HasExperimentState, st); + graph.claim(experiment, SR.HasExperimentState, st); + }}); + } + }); + } + + /** + * 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); + } + }); + } + + + /** + * Toggles the active-state of this experiment on or off + * @param graph ReadGraph + * @param activate The active-state of this experiment + */ + protected void toggleActivation(ReadGraph graph, final boolean activate) { + VirtualGraphSupport support = graph.getService(VirtualGraphSupport.class); + final Session session = graph.getSession(); + session.asyncRequest(new WriteRequest(support.getWorkspacePersistent("experiments")) { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + VirtualGraph runtime = graph.getService(VirtualGraph.class); + + session.asyncRequest(new WriteRequest(runtime) { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + SimulationResource SIMU = SimulationResource.getInstance(graph); + if(activate) + graph.claim(experiment, SIMU.IsActive, experiment); + else + graph.denyStatement(experiment, SIMU.IsActive, experiment); + } + + }); + } + }); + } + + + /* Result subscriptions */ + + @SuppressWarnings("rawtypes") + /** + * Copy from AprosExperiment + * @param subscription + */ + @Override + public void addVariableValueSubscription(VariableValueSubscription subscription) { + assert subscription != null; + synchronized (variableValueSubscriptions) { + variableValueSubscriptions.add(subscription); + variableValueSubscriptionsSnapshot = null; + } + } + + @SuppressWarnings("rawtypes") + /** + * Copy from AprosExperiment + * @param subscription + */ + @Override + public void removeVariableValueSubscription(VariableValueSubscription subscription) { + assert subscription != null; + synchronized (variableValueSubscriptions) { + variableValueSubscriptions.remove(subscription); + variableValueSubscriptionsSnapshot = null; + } + } + + @SuppressWarnings("rawtypes") + /** + * Copy from AprosExperiment + * @return + */ + @Override + public VariableValueSubscription[] getListenerSnapshot() { + VariableValueSubscription[] snapshot = variableValueSubscriptionsSnapshot; + if (snapshot == null) { + synchronized (variableValueSubscriptions) { + snapshot = variableValueSubscriptionsSnapshot; + if (snapshot == null) { + snapshot = variableValueSubscriptionsSnapshot = + variableValueSubscriptions.toArray(new VariableValueSubscription[variableValueSubscriptions.size()]); + } + } + } + return snapshot; + } + + volatile long previousVariableUpdateTime = 0; + + /** + * Modified copy from AprosExperiment + */ + public void resultsChanged() { + long time = System.nanoTime(); + if(time - previousVariableUpdateTime > 100000000) { + updateSubscriptions(); + previousVariableUpdateTime = time; + } + } + + @SuppressWarnings("rawtypes") + /** + * Modified copy from AporsExperiment + */ + @Override + public void updateSubscriptions() { + for(VariableValueSubscription subscription : getListenerSnapshot()) + subscription.update(); + } + + /* Experiment methods that are not used in this experiment */ + + @Override + public Lock getDatasourceLock() { + throw new UnsupportedOperationException(); + } + + @Override + public Datasource getDatasource() { + throw new UnsupportedOperationException(); + } + + @Override + public void simulateDuration(double duration) { + throw new UnsupportedOperationException(); + } + + @Override + public void rewindTo(double time) { + throw new UnsupportedOperationException(); + } + + // simulation stuff + + public int simulationSteps() { + return 5; + } + + public void simulate(ISolverMonitor solverMonitor, IProgressMonitor progressMonitor) { + progressMonitor.subTask("selecting solver..."); + + SolverType preferenceType = SolverSettings.getSelectedSolverType(); + if (solver == null || !solver.getType().equals(preferenceType)) { + switch(preferenceType) { + case INTERNAL: + this.solver = new InternalSolver(this, sysdynModel, solverMonitor); + break; + case OPENMODELICA: + System.err.println("please reload the experiment"); + return; + default: + // should not happen + return; + } + } + + progressMonitor.worked(1); + progressMonitor.subTask("generating model..."); + + solver.initialize(); + + progressMonitor.worked(1); + progressMonitor.subTask("building model..."); + + solver.buildModel(); + + progressMonitor.worked(1); + progressMonitor.subTask("running solver..."); + + solver.runSolver(); + + progressMonitor.worked(1); + progressMonitor.subTask("getting results..."); + + solver.updateResults(); + + progressMonitor.worked(1); + } + + // TODO: clean this up a bit maybe? + public File getExperimentDir() { + if (experimentDir == null) { File modelsDir = Activator.getBundleContext().getDataFile("models"); - String experimentName = this.experimentName; + String name = experimentName; List files = Arrays.asList(modelsDir.list()); - if (files.contains(experimentName)) { + if (files.contains(name)) { int i = 2; - while (files.contains(experimentName + "_" + i)){ + while (files.contains(name + "_" + i)){ i++; } - experimentName += "_" + i; - } - - simulationDir = Activator.getBundleContext().getDataFile("models/" + experimentName); - if (!simulationDir.exists()) { - simulationDir.mkdir(); + name += "_" + i; } + experimentDir = new File(modelsDir, name); + experimentDir.mkdir(); } - return simulationDir; - } - - /** - * - * @return - */ - protected String getAdditionalScripts() { - StringBuilder functionscript = new StringBuilder(); - for(String path : FunctionUtils.getLibraryPathsForModelica(this)) { - functionscript.append("loadFile(\"" + path + "\");\n"); - } - return functionscript.toString(); - } - - /** - * Starts simulating a model. Call only from inside simulation job! Start simulation using simulate(true). - * @param monitor - * @param progressMonitor - * @throws IOException - */ - public synchronized void simulate(final IModelicaMonitor monitor, final IProgressMonitor progressMonitor, String modelName) throws IOException { - canceled = false; - progressMonitor.subTask("Write modelica classes"); - - File home = ModelicaManager.getModelicaHome(); - if (omcHome == null || !home.getAbsolutePath().equals(omcHome)) { - omcVersion = ModelicaManager.getOMCVersion(home); - omcHome = home.getAbsolutePath(); - } - monitor.message("Simulate " + modelName + " using OpenModelica " + omcVersion); - - // Get Modelica code - String modelText = getModelicaCode(monitor, false, omcVersion); - if(modelText == null) - return; - progressMonitor.worked(1); - - // Write initial files and add init-parameters - progressMonitor.subTask("Write simulation files"); - HashMap experimentParameters = getExperimentParameters(monitor); - - // add loadFile script to load all related functions and function libraries - String additionalScript = getAdditionalScripts(); - - // Create simulation files - SimulationLocation simulationLocation = createSimulationFiles(sysdynModel, modelText, experimentParameters, additionalScript, false); - progressMonitor.worked(1); - - // Build the model and store previous model structure and inits that affect the building - // If there is no exe file OR the model structure has not changed, no need to build - String flatModelText = ModelicaManager.getFlatModelText(simulationLocation, monitor, FunctionUtils.getLibraryPathsForModelica(this)); - boolean structureChanged = sysdynModel.isStructureModified(); - - if (!simulationLocation.executableFile.isFile() || structureChanged) { - progressMonitor.subTask("Build model"); - previousModelStructure = flatModelText; - StringReader reader = new StringReader(previousModelStructure); - previousParameters = ModelicaManager.getModelParameters(reader); - reader.close(); - - buildModel(simulationLocation, monitor); - } - - // Add changed parameters in case that structure has not changed - HashMap changes = structureChanged ? null : new HashMap(); - if(!structureChanged && previousParameters != null && omcVersion.startsWith("1.9")) { - StringReader reader = new StringReader(flatModelText); - HashMap newParameters = ModelicaManager.getModelParameters(reader); - reader.close(); - for(String key : previousParameters.keySet()) { - if(!previousParameters.get(key).equals(newParameters.get(key))) { - changes.put(key, newParameters.get(key)); - } - } - previousParameters = newParameters; - } - progressMonitor.worked(1); - - if(simulationLocation != null && !canceled) { - // Simulate the model - runModelica(simulationLocation, monitor, progressMonitor, experimentParameters, changes); - } - - if(canceled) - simulate(false); - process = null; - } - - /** - * Get the version of the OpenModelica compiler that is defined to be used - * in Preferences - * @return OpenModelica version - */ - protected String getOpenModelicaVersion() { - String omVersion = null; - - try { - IScopeContext context = DefaultScope.INSTANCE; - Preferences node = context.getNode(org.simantics.modelica.Activator.PLUGIN_ID); - String omHome = node.get(OpenModelicaPreferences.OM_HOME, null); - if(omHome != null) { - File omHomeDir = new File(omHome); - if(omHomeDir != null && omHomeDir.isDirectory()) - omVersion = ModelicaManager.getOMCVersion(omHomeDir); - } - - if(omVersion == null) { - omVersion = ModelicaManager.getOMCVersion(ModelicaManager.getModelicaHome()); - } - - } catch (IOException e) { - } - - return omVersion; - } - - - /** - * Method that compares given modelText and inits to previous model and inits - * @param modelText Textual representation of a model (Modelica code) - * @param inits map of init parameters - * @return true if the model has changed, false otherwise - */ -// protected boolean hasStructureChanged(String modelText) { -// -// if(previousModelStructure == null) -// return true; -// -// // Then compare the actual model structure -// BufferedReader current = new BufferedReader( -// new StringReader(modelText)); -// BufferedReader previous = new BufferedReader( -// new StringReader(previousModelStructure)); -// -// String c, p; -// try { -// // Read both current and previous model texts at the same time -// c = current.readLine(); -// p = previous.readLine(); -// -// while (c != null && p != null) { -// // if the lines are the same, no need for further examination -// if(!c.equals(p)) { -// if(c.contains("parameter") && p.contains("parameter")) { -// /* -// * The line is a parameter definition. -// * In this case only what is before '=' matters -// * -// * parameter Real Var = 1; -// * is structurally same as -// * parameter Real Var = 2; -// */ -// int i = c.indexOf("="); -// if(!c.substring(0, i).equals(p.substring(0, i))) { -// // different parameter definition -// return true; -// } -// } else { -// // other than a line containing parameters differs -// return true; -// } -// } -// c = current.readLine(); -// p = previous.readLine(); -// } -// -// if((c == null && p != null) || (c != null && p == null)) { -// // different lengths -// return true; -// } -// -// } catch(IOException e) { -// // Something went wrong in the comparison, it is safer to say that the structure has changed -// return true; -// } -// return false; -// } - - /** - * Destroy an ongoing simulation process - */ - public void cancelSimulation() { - canceled = true; - if(process != null) { - process.destroy(); - } - } - - /** - * Toggle simulation state - * @param enabled true == RUNNING, false == STOPPED - */ - public void toggleSimulation(boolean enabled) { - if(enabled) { - this.toggled = true; - changeState(ExperimentState.RUNNING); - if(modificationListener == null) { - - modificationListener = new Runnable() { - - @Override - public void run() { - session.asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - if(getState() == ExperimentState.RUNNING) { - SimulationScheduler.start(sysdynModel, SysdynExperiment.this); - } - - } - }); - - }; - }; - sysdynModel.addModificationListener(modificationListener); - } - } - else { - changeState(ExperimentState.STOPPED); - this.toggled = false; - } - - } - - @Override - public void refresh(RequestProcessor session) { - session.asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - init(graph); - } - - }); - } - - @Override - public void refresh(Session session) { - refresh((RequestProcessor)session); - } - - @Override - protected void localStateChange() { - setSysdynExperimentState(getState()); - switch(state) { - case DISPOSED: - onExperimentDisposed(); - break; - default: - break; - } - - } - - /** - * Returns sysdyn experiment state. It is usually the same as ordinary experiment state. - * Initializing phase takes longer than normally in game experiments. - * @return - */ - public ExperimentState getSysdynExperimentState() { - return sysdynExperimentState; - } - - protected void setSysdynExperimentState(final ExperimentState state) { - sysdynExperimentState = state; - session.asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - VirtualGraphSupport support = graph.getService(VirtualGraphSupport.class); - final Session session = graph.getSession(); - session.asyncRequest(new WriteRequest(support.getWorkspacePersistent("experiments")) { - @Override - public void perform(WriteGraph graph) throws DatabaseException { - Layer0 L0 = Layer0.getInstance(graph); - SimulationResource SR = SimulationResource.getInstance(graph); - graph.deny(model, SR.HasExperimentState); - graph.deny(experiment, SR.HasExperimentState); - - Resource st = graph.newResource(); - switch(state) { - case INITIALIZING: - graph.claim(st, L0.InstanceOf, SR.ExperimentState_Initializing); - break; - case RUNNING: - graph.claim(st, L0.InstanceOf, SR.ExperimentState_Running); - break; - case STOPPED: - graph.claim(st, L0.InstanceOf, SR.ExperimentState_Stopped); - break; - case DISPOSED: - graph.claim(st, L0.InstanceOf, SR.ExperimentState_Disposed); - break; - } - - graph.claim(model, SR.HasExperimentState, st); - graph.claim(experiment, SR.HasExperimentState, st); - }}); - } - }); - } - - /** - * 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); - } - }); - } - - - /** - * Toggles the active-state of this experiment on or off - * @param graph ReadGraph - * @param activate The active-state of this experiment - */ - protected void toggleActivation(ReadGraph graph, final boolean activate) { - VirtualGraphSupport support = graph.getService(VirtualGraphSupport.class); - final Session session = graph.getSession(); - session.asyncRequest(new WriteRequest(support.getWorkspacePersistent("experiments")) { - @Override - public void perform(WriteGraph graph) throws DatabaseException { - VirtualGraph runtime = graph.getService(VirtualGraph.class); - - session.asyncRequest(new WriteRequest(runtime) { - - @Override - public void perform(WriteGraph graph) throws DatabaseException { - SimulationResource SIMU = SimulationResource.getInstance(graph); - if(activate) - graph.claim(experiment, SIMU.IsActive, experiment); - else - graph.denyStatement(experiment, SIMU.IsActive, experiment); - } - - }); - } - }); - } - - - /* Result subscriptions */ - - @SuppressWarnings("rawtypes") - /** - * Copy from AprosExperiment - * @param subscription - */ - @Override - public void addVariableValueSubscription(VariableValueSubscription subscription) { - assert subscription != null; - synchronized (variableValueSubscriptions) { - //System.out.println("ADD listener " + subscription); - variableValueSubscriptions.add(subscription); - variableValueSubscriptionsSnapshot = null; - } - } - - @SuppressWarnings("rawtypes") - /** - * Copy from AprosExperiment - * @param subscription - */ - @Override - public void removeVariableValueSubscription(VariableValueSubscription subscription) { - assert subscription != null; - synchronized (variableValueSubscriptions) { - //System.out.println("REMOVE listener " + subscription); - variableValueSubscriptions.remove(subscription); - variableValueSubscriptionsSnapshot = null; - } - } - - @SuppressWarnings("rawtypes") - /** - * Copy from AprosExperiment - * @return - */ - @Override - public VariableValueSubscription[] getListenerSnapshot() { - VariableValueSubscription[] snapshot = variableValueSubscriptionsSnapshot; - if (snapshot == null) { - synchronized (variableValueSubscriptions) { - snapshot = variableValueSubscriptionsSnapshot; - if (snapshot == null) { - snapshot = variableValueSubscriptionsSnapshot = variableValueSubscriptions.toArray(new VariableValueSubscription[variableValueSubscriptions.size()]); - } - } - //System.out.println("listener count: " + snapshot.length); - } - return snapshot; - } - - volatile long previousVariableUpdateTime = 0; - volatile boolean skippedVariableUpdate = true; - - - /** - * Modified copy from AprosExperiment - */ - public void resultsChanged() { - long time = System.nanoTime(); - if(time - previousVariableUpdateTime > 100000000) { - updateSubscriptions(); - previousVariableUpdateTime = time; - } - else - skippedVariableUpdate = true; - } - - @SuppressWarnings("rawtypes") - /** - * Modified copy from AporsExperiment - */ - @Override - public void updateSubscriptions() { - for(VariableValueSubscription subscription : getListenerSnapshot()) - subscription.update(); - skippedVariableUpdate = false; - } - - public int numberOfSimulationRunSteps() { - /* - * 1. Write modelica files - * 2. Write other simulation files - * 3. Build model OR update parameters - * 4. Run modelica - * 5. Read results - */ - return 5; - } - - - /* Experiment methods that are not used in this experiment */ - - @Override - public Lock getDatasourceLock() { - return null; - } - - @Override - public Datasource getDatasource() { - return null; - } - - @Override - public void simulateDuration(double duration) { - System.out.println("simulateDuartion"); - } - - - @Override - public void rewindTo(double time) { - System.out.println("rewindTo"); - } + + return experimentDir; + } } 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 d99f014f..21e7ccb3 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java @@ -49,7 +49,7 @@ import org.simantics.utils.datastructures.Triple; * @author Teemu Lempinen * */ -public class SysdynGameExperiment extends SysdynExperiment { +public class SysdynGameExperiment extends OldSysdynExperiment { private FMUControlJNI control; private String[] subscription; @@ -187,11 +187,8 @@ public class SysdynGameExperiment extends SysdynExperiment { if(modelText == null) return; - File home = ModelicaManager.getModelicaHome(); - if (omcHome == null || !home.getAbsolutePath().equals(omcHome)) { - omcVersion = ModelicaManager.getOMCVersion(home); - omcHome = home.getAbsolutePath(); - } + omcVersion = ModelicaManager.getDefaultOMVersion(); + monitor.message("Simulate " + modelName + " using OpenModelica " + omcVersion); progressMonitor.worked(1); @@ -404,7 +401,7 @@ public class SysdynGameExperiment extends SysdynExperiment { } monitor.subTask("Display results"); - getCurrentResult().setResult(new GameResult(SysdynGameExperiment.this.results, SysdynGameExperiment.this.subscription)); + ((MemoryResult)getCurrentResult()).setResult(new GameResult(SysdynGameExperiment.this.results, SysdynGameExperiment.this.subscription)); monitor.worked(1); resultsChanged(); @@ -517,7 +514,7 @@ public class SysdynGameExperiment extends SysdynExperiment { results.get(subscription[k]).add(currentValues[k]); } - getCurrentResult().setResult(new GameResult(this.results, this.subscription)); + ((MemoryResult)getCurrentResult()).setResult(new GameResult(this.results, this.subscription)); resultsChanged(); } catch (FMUJNIException e) { System.err.println("SysdynGameExperiment getInitialResultValues failed: " + e.getMessage()); diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java index 4d091dc6..561a99d8 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java @@ -39,7 +39,6 @@ import org.simantics.objmap.IMappingListener; import org.simantics.objmap.MappingException; import org.simantics.objmap.Mappings; import org.simantics.project.IProject; -import org.simantics.simulation.experiment.IDynamicExperiment; import org.simantics.simulation.experiment.IExperiment; import org.simantics.simulation.model.IModel; import org.simantics.simulation.ontology.SimulationResource; @@ -61,12 +60,14 @@ import org.simantics.sysdyn.representation.Variability; import org.simantics.sysdyn.representation.expressions.Expression; import org.simantics.sysdyn.representation.expressions.IExpression; import org.simantics.sysdyn.representation.expressions.ParameterExpression; +import org.simantics.sysdyn.solver.SolverSettings; +import org.simantics.sysdyn.solver.SolverSettings.SolverType; /** * Maintains a Java representation of system dynamic model. * @author Hannu Niemistö, Teemu Lempinen */ -public class SysdynModel implements IMappingListener, IModel, VariableSubscriptionManager { +public class SysdynModel implements IModel, IMappingListener, VariableSubscriptionManager { private Session session; @@ -93,7 +94,6 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti @SuppressWarnings("rawtypes") private final Map services = new HashMap(); - private boolean structureModified = false; /** @@ -243,10 +243,7 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti }); } - - /* - * a dummy(?) call for experiments - */ + // A dummy call for experiments public SysdynModel(Resource modelResource) { this.modelResource = modelResource; } @@ -409,7 +406,6 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti @Override public IExperiment loadExperiment(ReadGraph g, Resource experiment, IExperimentActivationListener listener) { - // Make sure that configurationResource exists if(configurationResource == null && modelResource != null) { SimulationResource simu = SimulationResource.getInstance(g); @@ -422,11 +418,10 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti } } - try { // Create a new experiment based on the experiment resource type SysdynResource sr = SysdynResource.getInstance(g); - IDynamicExperiment exp; + SysdynExperiment exp; if(g.isInstanceOf(experiment, sr.PlaybackExperiment)) { exp = new SysdynPlaybackExperiment(experiment, modelResource); @@ -435,13 +430,22 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti } else if(g.isInstanceOf(experiment, sr.SensitivityAnalysisExperiment)) { exp = new SysdynSensitivityAnalysisExperiment(experiment, modelResource); } else if(g.isInstanceOf(experiment, sr.BasicExperiment)) { - exp = new SysdynExperiment(experiment, modelResource); + // TODO: this is a temporary hack to make sure at least one + // working implementation is available even if the new solver + // architecture is completely broken + if (SolverType.INTERNAL.equals(SolverSettings.getSelectedSolverType())) { + exp = new SysdynExperiment(experiment, modelResource); + } + else { + exp = new OldSysdynExperiment(experiment, modelResource); + } } else { return null; } - - ((SysdynExperiment)exp).init(g); - + + // TODO: should maybe get the model from model manager? + + exp.init(g); VirtualGraphSupport support = g.getSession().getService(VirtualGraphSupport.class); ExperimentRuns.createRun(g.getSession(), support.getWorkspacePersistent("experiments"), experiment, exp, SysdynResource.URIs.Experiment_Run, listener, null); @@ -458,10 +462,12 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti /** * Get active results. To update the active results, use getAndUpdateActiveResults() + * * @param graph ReadGraph * @return all active SysdynResults (last update with getAndUpdateActiveResults()) */ public Collection getDisplayedResults() { + // TODO: displayedResults are always empty? if(displayedResults == null) return new ArrayList(); else @@ -489,7 +495,7 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti } else if (element instanceof IndependentVariable) { IndependentVariable variable = (IndependentVariable) element; //FIXME: more general solution for finding out if the variable is a parameter - if(variable != null && variable.getExpressions() != null && variable.getExpressions() != null && variable.getExpressions().get(0) != null) { + if(variable != null && variable.getExpressions() != null && variable.getExpressions().get(0) != null) { IExpression expression = variable.getExpressions().get(0); if (expression instanceof ParameterExpression) { Double value = ((ParameterExpression)expression).getValue(); @@ -517,7 +523,6 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti public void addVariableValueSubscription(VariableValueSubscription subscription) { assert subscription != null; synchronized (variableValueSubscriptions) { - //System.out.println("ADD listener " + subscription); variableValueSubscriptions.add(subscription); variableValueSubscriptionsSnapshot = null; } @@ -532,7 +537,6 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti public void removeVariableValueSubscription(VariableValueSubscription subscription) { assert subscription != null; synchronized (variableValueSubscriptions) { - //System.out.println("REMOVE listener " + subscription); variableValueSubscriptions.remove(subscription); variableValueSubscriptionsSnapshot = null; } @@ -553,7 +557,6 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti snapshot = variableValueSubscriptionsSnapshot = variableValueSubscriptions.toArray(new VariableValueSubscription[variableValueSubscriptions.size()]); } } - //System.out.println("listener count: " + snapshot.length); } return snapshot; } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModelManager.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModelManager.java index 82cf2f05..c902f9cc 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModelManager.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModelManager.java @@ -42,7 +42,6 @@ public class SysdynModelManager { if(model == null) { try { session.syncRequest(new ReadRequest() { - @Override public void run(ReadGraph graph) throws DatabaseException { SysdynModel model = new SysdynModel(graph, resource); @@ -52,7 +51,6 @@ public class SysdynModelManager { } catch (DatabaseException e) { e.printStackTrace(); } - model = models.get(resource); } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java index 7e5690cb..38ae0385 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java @@ -25,11 +25,10 @@ import org.simantics.db.exception.DatabaseException; import org.simantics.Simantics; import org.simantics.db.request.Read; import org.simantics.simulation.experiment.ExperimentState; -import org.simantics.simulation.experiment.IDynamicExperiment; import org.simantics.simulation.ontology.SimulationResource; import org.simantics.sysdyn.SysdynResource; -public class SysdynPlaybackExperiment extends SysdynExperiment implements IDynamicExperiment { +public class SysdynPlaybackExperiment extends OldSysdynExperiment { public static long DURATION_SLOW = 20000; public static long DURATION_NORMAL = 10000; diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynSensitivityAnalysisExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynSensitivityAnalysisExperiment.java index c4377654..063c3867 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynSensitivityAnalysisExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynSensitivityAnalysisExperiment.java @@ -46,7 +46,7 @@ import org.simantics.sysdyn.adapter.generator.IGenerator; * @author Tuomas Miettinen * */ -public class SysdynSensitivityAnalysisExperiment extends SysdynExperiment { +public class SysdynSensitivityAnalysisExperiment extends OldSysdynExperiment { private ArrayList results = null; private int numberOfRuns = 0; @@ -109,9 +109,9 @@ public class SysdynSensitivityAnalysisExperiment extends SysdynExperiment { } private void runSensitivityRun(HashMap values, HashMap experimentParameters) { - int indexOfDot = simulationLocation.resFile.toString().lastIndexOf('.'); + int indexOfDot = simulationLocation.resultFile.toString().lastIndexOf('.'); if (indexOfDot > 1) { - String resFile = simulationLocation.resFile.toString(); + String resFile = simulationLocation.resultFile.toString(); String newResFile = resFile.substring(0, indexOfDot) + currentRun + resFile.substring(indexOfDot); experimentParameters.put(ModelicaManager.RESULT_FILE_NAME, newResFile); } @@ -164,7 +164,7 @@ public class SysdynSensitivityAnalysisExperiment extends SysdynExperiment { changes = new HashMap(); } - String version = ModelicaManager.getOMCVersion(simulationLocation.omcHome); + String version = ModelicaManager.getOMVersion(simulationLocation.omHome); experimentParameters.put(ModelicaManager.OMC_VERSION, version); @@ -322,7 +322,7 @@ public class SysdynSensitivityAnalysisExperiment extends SysdynExperiment { public void saveState() { if(results == null || !(results instanceof ArrayList)) return; - SaveResultSetJob saveResultSetJob = new SaveResultSetJob((SysdynExperiment)this, session, results); + SaveResultSetJob saveResultSetJob = new SaveResultSetJob((OldSysdynExperiment)this, session, results); saveResultSetJob.schedule(); } @@ -356,11 +356,7 @@ public class SysdynSensitivityAnalysisExperiment extends SysdynExperiment { @Override public synchronized void simulate(IModelicaMonitor monitor, IProgressMonitor progressMonitor, String modelName) throws IOException { - File home = ModelicaManager.getModelicaHome(); - if (omcHome == null || !home.getAbsolutePath().equals(omcHome)) { - omcVersion = ModelicaManager.getOMCVersion(home); - omcHome = home.getAbsolutePath(); - } + omcVersion = ModelicaManager.getDefaultOMVersion(); // Make sure that omc version is 1.9 or higher. // Builtin version during this change is 1.9 beta 4 diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java index 5daae250..92e8c99e 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java @@ -20,17 +20,17 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.ui.PlatformUI; import org.simantics.modelica.IModelicaMonitor; +import org.simantics.sysdyn.manager.OldSysdynExperiment; import org.simantics.sysdyn.manager.SysdynConsole; -import org.simantics.sysdyn.manager.SysdynExperiment; import org.simantics.sysdyn.manager.SysdynModel; public class SimulationJob extends Job { private SysdynModel model; - private SysdynExperiment experiment; + private OldSysdynExperiment experiment; private IModelicaMonitor monitor; - public SimulationJob(SysdynModel model, SysdynExperiment experiment) { + public SimulationJob(SysdynModel model, OldSysdynExperiment experiment) { super("Simulate " + model.getConfiguration().getLabel()); this.model = model; this.experiment = experiment; @@ -47,8 +47,8 @@ public class SimulationJob extends Job { monitor.beginTask("Simulate " + model.getConfiguration().getLabel(), experiment.numberOfSimulationRunSteps()); try { model.update(); - if(experiment instanceof SysdynExperiment) { - ((SysdynExperiment)experiment).simulate(this.monitor, monitor, model.getConfiguration().getLabel()); + if(experiment instanceof OldSysdynExperiment) { + ((OldSysdynExperiment)experiment).simulate(this.monitor, monitor, model.getConfiguration().getLabel()); model.setStructureModified(false); } } catch (Exception e) { diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java index 0ee92dc8..bd4d7d69 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java @@ -11,15 +11,15 @@ *******************************************************************************/ package org.simantics.sysdyn.simulation; -import org.simantics.sysdyn.manager.SysdynExperiment; +import org.simantics.sysdyn.manager.OldSysdynExperiment; import org.simantics.sysdyn.manager.SysdynModel; public class SimulationScheduler { SysdynModel model; - SysdynExperiment experiment; + OldSysdynExperiment experiment; SimulationJob job; - private SimulationScheduler(SysdynModel model, SysdynExperiment experiment) { + private SimulationScheduler(SysdynModel model, OldSysdynExperiment experiment) { this.model = model; this.experiment = experiment; this.job = new SimulationJob(model, experiment); @@ -29,7 +29,7 @@ public class SimulationScheduler { job.schedule(); } - public static synchronized SimulationScheduler start(SysdynModel model, SysdynExperiment experiment) { + public static synchronized SimulationScheduler start(SysdynModel model, OldSysdynExperiment experiment) { SimulationScheduler scheduler = model.getService(SimulationScheduler.class); if(scheduler == null || !scheduler.experiment.equals(experiment)) { scheduler = new SimulationScheduler(model, experiment); diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/ISolver.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/ISolver.java new file mode 100644 index 00000000..a55bf3d4 --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/ISolver.java @@ -0,0 +1,12 @@ +package org.simantics.sysdyn.solver; + +import org.simantics.sysdyn.solver.SolverSettings.SolverType; + +public interface ISolver { + + public void initialize(); + public void buildModel(); + public void runSolver(); + public void updateResults(); + public SolverType getType(); +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/ISolverMonitor.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/ISolverMonitor.java new file mode 100644 index 00000000..9df8735e --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/ISolverMonitor.java @@ -0,0 +1,9 @@ +package org.simantics.sysdyn.solver; + +import org.simantics.modelica.IModelicaMonitor; + +public interface ISolverMonitor extends IModelicaMonitor { + public void message(String message); + public void clearConsole(); + public void showConsole(); +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolver.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolver.java new file mode 100644 index 00000000..66e18ee6 --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolver.java @@ -0,0 +1,150 @@ +package org.simantics.sysdyn.solver; + +import java.util.HashMap; + +import org.simantics.db.exception.DatabaseException; +import org.simantics.modelica.ModelicaManager; +import org.simantics.modelica.SimulationLocation; +import org.simantics.sysdyn.manager.FunctionUtils; +import org.simantics.sysdyn.manager.SysdynDataSet; +import org.simantics.sysdyn.manager.SysdynExperiment; +import org.simantics.sysdyn.manager.SysdynModel; +import org.simantics.sysdyn.modelica.ModelicaWriter; +import org.simantics.sysdyn.representation.Model; +import org.simantics.sysdyn.solver.SolverSettings.SolverType; + +import fi.semantum.sysdyn.solver.Solver; + +public class InternalSolver implements ISolver { + + private SysdynExperiment experiment; + private SysdynModel model; + private ISolverMonitor monitor; + private Solver solver; + + private double start; + private double stop; + private double step; + private double interval; + + private SimulationLocation location; + + private HashMap results; + + public InternalSolver(SysdynExperiment experiment, SysdynModel model, ISolverMonitor monitor) { + this.experiment = experiment; + this.model = model; + this.monitor = monitor; + + solver = new Solver(); + + // default values + start = 0; + stop = 500; + step = 0.1; + interval = step; + } + + @Override + public void initialize() { + // TODO: is this really really necessary? + try { + model.update(); + } + catch (DatabaseException e) { + e.printStackTrace(); + return; + } + + String omVersion = ModelicaManager.getDefaultOMVersion(); + String modelContent = ModelicaWriter.write(model.getModules(), false, omVersion); + + // update some stuff + FunctionUtils.updateFunctionFilesForExperiment(experiment); + + location = ModelicaManager.createSimulationLocation(experiment.getExperimentDir(), + model.getConfiguration().getLabel(), modelContent); + + // set solver parameters + Model representation = model.getConfiguration().getModel(); + // TODO: should probably check that the values actually make sense + // i.e. start and stop >= 0, start <= stop, stop - start >= step + if (representation.getStartTime() != null) + start = representation.getStartTime(); + if (representation.getStopTime() != null) + stop = representation.getStopTime(); + + if (representation.getSimulationStepLength() != null) + step = representation.getSimulationStepLength(); + else + step = (stop - start) / 500; + + if (representation.getOutputInterval() != null) + interval = representation.getOutputInterval(); + else + interval = step; + + solver.setStep(step); + } + + @Override + public void buildModel() { + String flat = ModelicaManager.getFlatModelText(location, monitor, FunctionUtils.getLibraryPathsForModelica(experiment)); + try { + solver.prepare(flat); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void runSolver() { + // the number of result intervals in the simulation (account for initial values) + int count = (int)((stop - start) / interval) + 1; + // the number of steps in one result interval + int steps = (int)(interval / step); + + // an array containing an accurate time stamp for each interval + double[] times = new double[count]; + // a map containing values of all variables for each interval + HashMap values = new HashMap(); + // initilize the temporary data structures + times[0] = start; + HashMap tmp = solver.values(); + for (String key : tmp.keySet()) { + values.put(key, new double[count]); + values.get(key)[0] = tmp.get(key); + } + + // run the simulation + for (int interval = 1; interval < count; interval++) { + for (int i = 0; i < steps; i++) { + solver.step(); + } + times[interval] = times[interval-1] + steps * step; + tmp = solver.values(); + for (String key : tmp.keySet()) { + values.get(key)[interval] = tmp.get(key); + } + } + + results = new HashMap(); + for (String name : values.keySet()) { + results.put(name, new SysdynDataSet(name, null, times, values.get(name))); + } + } + + @Override + public void updateResults() { + InternalSolverResult result = new InternalSolverResult(null, results); + experiment.setCurrentResult(result); + experiment.resultsChanged(); + } + + @Override + public SolverType getType() { + return SolverType.INTERNAL; + } + +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolverResult.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolverResult.java new file mode 100644 index 00000000..b630012a --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolverResult.java @@ -0,0 +1,29 @@ +package org.simantics.sysdyn.solver; + +import java.io.File; +import java.util.HashMap; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.simantics.sysdyn.manager.SysdynDataSet; +import org.simantics.sysdyn.manager.SysdynResult; + +public class InternalSolverResult extends SysdynResult { + + private HashMap results; + + public InternalSolverResult(String resultName, HashMap results) { + super(resultName); + this.results = results; + } + + @Override + public SysdynDataSet getDataSet(String variable) { + return results.get(variable); + } + + @Override + public void saveToFile(File file, IProgressMonitor progressMonitor) { + // not implemented + } + +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SimulationJob.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SimulationJob.java new file mode 100644 index 00000000..d05a27ee --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SimulationJob.java @@ -0,0 +1,32 @@ +package org.simantics.sysdyn.solver; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.simantics.sysdyn.manager.SysdynConsole; +import org.simantics.sysdyn.manager.SysdynExperiment; + +public class SimulationJob extends Job { + + private String name; + private SysdynExperiment experiment; + + public SimulationJob(String name, SysdynExperiment experiment) { + super(name); + this.name = name; + this.experiment = experiment; + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + monitor.beginTask("simulate "+name, experiment.simulationSteps()); + + this.experiment.simulate(SysdynConsole.INSTANCE, monitor); + + monitor.done(); + + return Status.OK_STATUS; + } + +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SolverParameters.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SolverParameters.java new file mode 100644 index 00000000..ec32dab5 --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SolverParameters.java @@ -0,0 +1,13 @@ +package org.simantics.sysdyn.solver; + +public class SolverParameters { + public static final String START_VALUE = "startTime"; + public static final String STOP_VALUE = "stopTime"; + public static final String OUTPUT_FORMAT = "outputFormat"; + public static final String STEP_VALUE = "stepSize"; + public static final String NUMBER_OF_INTERVALS = "numberOfIntervals"; + public static final String METHOD = "method"; + public static final String TOLERANCE = "tolerance"; + public static final String VARIABLE_FILTER = "variableFilter"; + public static final String OUTPUT_INTERVAL = "outputInterval"; +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SolverSettings.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SolverSettings.java new file mode 100644 index 00000000..b3e8fb06 --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/SolverSettings.java @@ -0,0 +1,34 @@ +package org.simantics.sysdyn.solver; + +import org.eclipse.core.runtime.preferences.ConfigurationScope; +import org.osgi.service.prefs.Preferences; + +public class SolverSettings { + + public enum SolverType { + INTERNAL, OPENMODELICA, UNKNOWN + } + + public static final String QUALIFIER = "org.simantics.sysdyn.solver.preferences"; + + public static final String SOLVER_TYPE = "SOLVER_TYPE"; + public static final String SOLVER_TYPE_INTERNAL = "INTERNAL"; + public static final String SOLVER_TYPE_OPENMODELICA = "OPENMODELICA"; + + public static SolverType getSelectedSolverType() { + Preferences preferences = ConfigurationScope.INSTANCE.getNode(SolverSettings.QUALIFIER); + // default to internal solver + String type = preferences.get(SolverSettings.SOLVER_TYPE, SolverSettings.SOLVER_TYPE_INTERNAL); + + if (SOLVER_TYPE_INTERNAL.equals(type)) { + return SolverType.INTERNAL; + } + else if (SOLVER_TYPE_OPENMODELICA.equals(type)) { + return SolverType.OPENMODELICA; + } + else { + return SolverType.UNKNOWN; + } + } + +} -- 2.47.1