From 104d3b60262a09cdb2f98eeebf335bfa8cceae87 Mon Sep 17 00:00:00 2001 From: jkauttio Date: Tue, 21 Apr 2015 13:41:41 +0000 Subject: [PATCH] Update parameter change handling in OpenModelica experiments to avoid forgetting changes made between different simulations. Also make the check for old OpenModelica version always return false as the implementation could return an incorrect value and old OpenModelica versions are not supported any more. fixes #5776 git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@31193 ac1ea38d-2e2b-0410-8846-a27921b304fc --- .../simantics/modelica/ModelicaManager.java | 216 ++---------------- .../org/simantics/modelica/data/DataSet.java | 6 +- .../sysdyn/manager/OldSysdynExperiment.java | 93 ++------ .../sysdyn/manager/SysdynGameExperiment.java | 2 - .../simantics/sysdyn/manager/SysdynModel.java | 2 +- .../sysdyn/solver/InternalSolver.java | 2 +- 6 files changed, 34 insertions(+), 287 deletions(-) diff --git a/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java b/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java index 09cd5adb..77656b8e 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java +++ b/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java @@ -17,7 +17,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; -import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -50,7 +49,6 @@ import org.osgi.service.prefs.Preferences; import org.simantics.modelica.preferences.OpenModelicaPreferences; import org.w3c.dom.Document; import org.w3c.dom.Node; -import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** @@ -69,26 +67,6 @@ public class ModelicaManager { 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"); @@ -163,15 +141,8 @@ public class ModelicaManager { } 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; - } + // TODO: old versions are not supported anymore so any checks for them should be removed + return false; } /** @@ -303,7 +274,7 @@ public class ModelicaManager { thread.run(); } - public static SimulationLocation createSimulationLocation(File modelDir, String modelName, String modelContent, File omHome, boolean isOldOMVersion) { + public static SimulationLocation createSimulationLocation(File modelDir, String modelName, String modelContent) { if (!modelDir.isDirectory()) { return null; } @@ -328,7 +299,7 @@ public class ModelicaManager { } // full model files are (apparently) only needed for old parameter comparison routines - if (isOldOMVersion) { + if (isOldOMVersion()) { location.fullModelDir = new File(location.getModelDir(), "fullModel"); if (!location.fullModelDir.isDirectory()) { location.fullModelDir.mkdir(); @@ -337,7 +308,7 @@ public class ModelicaManager { location.fullModelScriptFile = new File(location.fullModelDir, location.getModelName() + "_full.mos"); } - location.omHome = omHome; + location.omHome = getOMHome(); return location; } @@ -532,43 +503,14 @@ public class ModelicaManager { */ public static Process runModelica(SimulationLocation location, IModelicaMonitor monitor, HashMap experimentParameters, HashMap parameterChanges) throws IOException { ArrayList commands = new ArrayList(); - try { - 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(); + + if(experimentParameters.get(RESULT_FILE_NAME) != null) { + commands.add("-r="+experimentParameters.get(RESULT_FILE_NAME)); } + // update parameter changes + updateInitFile(location, experimentParameters, parameterChanges); + // Commands to String[] String[] commandString = new String[commands.size()]; for (int i = 0; i < commands.size(); ++i) @@ -623,142 +565,14 @@ public class ModelicaManager { 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 + * @param parameterChanges Parameter variable changes */ - public static void updateInitFile(SimulationLocation simulationLocation, HashMap experimentParameters, HashMap changes) { + public static void updateInitFile(SimulationLocation simulationLocation, HashMap experimentParameters, HashMap parameterChanges) { try { XPath xpath = XPathFactory.newInstance().newXPath(); @@ -784,13 +598,13 @@ public class ModelicaManager { // // PARAMETER VARIABLES // - for(String name : changes.keySet()) { + for(String name : parameterChanges.keySet()) { Node node = (Node)xpath.evaluate ("//fmiModelDescription/ModelVariables/ScalarVariable[@name='" + name + "']/Real/@start", init, XPathConstants.NODE); if(node != null) { - node.setNodeValue(changes.get(name)); + node.setNodeValue(parameterChanges.get(name)); } } diff --git a/org.simantics.modelica/src/org/simantics/modelica/data/DataSet.java b/org.simantics.modelica/src/org/simantics/modelica/data/DataSet.java index f373b988..ff5b332b 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/data/DataSet.java +++ b/org.simantics.modelica/src/org/simantics/modelica/data/DataSet.java @@ -29,7 +29,7 @@ public class DataSet { /** * Normalize simulation results according to the given parameters by * removing extra simulation steps that are not located at the expected - * intervals. This is mostly useful when Open Modelica decides to perform + * intervals. This is mostly useful when OpenModelica decides to perform * extra simulation steps that cause misalignments when simulation results * from several runs with different parameters are combined in sensitivity * analysis experiments. @@ -42,9 +42,9 @@ public class DataSet { // TODO: this makes implicit assumptions about the values, probably not kosher int size = (int)Math.round((stopTime - startTime) / timeStep) + 1; if (times.length < size) { - // if the ogirinal data has less time steps than requested, there is no need + // if the original data has less time steps than requested, there is no need // to filter anything. generally this happens when the value of the variable - // does not change during the simulation, in which case Open Modelica + // does not change during the simulation, in which case OpenModelica // simply stores the value once. return; } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/OldSysdynExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/OldSysdynExperiment.java index 3fbd472c..a0cb37d2 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/OldSysdynExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/OldSysdynExperiment.java @@ -78,8 +78,7 @@ public class OldSysdynExperiment extends SysdynExperiment { @SuppressWarnings("rawtypes") protected volatile VariableValueSubscription[] variableValueSubscriptionsSnapshot = null; - protected String previousModelStructure; - protected HashMap previousParameters; + protected HashMap defaultParameters; protected Process process; protected boolean canceled = false; protected ExperimentState sysdynExperimentState; @@ -309,8 +308,7 @@ public class OldSysdynExperiment extends SysdynExperiment { monitor.message(e.getMessage()); monitor.showConsole(); canceled = true; - previousModelStructure = ""; - previousParameters = null; + defaultParameters = null; } } @@ -319,13 +317,13 @@ public class OldSysdynExperiment extends SysdynExperiment { * @param structureChanged * @throws IOException */ - protected void runModelica(SimulationLocation simulationLocation, IModelicaMonitor monitor, IProgressMonitor progressMonitor, HashMap experimentParameters, HashMap changes) throws IOException { + protected void runModelica(SimulationLocation simulationLocation, IModelicaMonitor monitor, IProgressMonitor progressMonitor, HashMap experimentParameters, HashMap parameterChanges) throws IOException { progressMonitor.subTask("Simulate model"); process = ModelicaManager.runModelica( simulationLocation, monitor, experimentParameters, - changes + parameterChanges ); ModelicaManager.printProcessOutput(process, monitor); @@ -434,7 +432,7 @@ public class OldSysdynExperiment extends SysdynExperiment { FunctionUtils.updateFunctionFilesForExperiment(this); - SimulationLocation location = ModelicaManager.createSimulationLocation(simulationDir, sysdynModel.getConfiguration().getLabel(), modelText, ModelicaManager.getOMHome(), ModelicaManager.isOldOMVersion()); + SimulationLocation location = ModelicaManager.createSimulationLocation(simulationDir, sysdynModel.getConfiguration().getLabel(), modelText); if (fmu) { ModelicaManager.createFMUSimulationScripts(location, inits, additionalScript); } @@ -535,32 +533,31 @@ public class OldSysdynExperiment extends SysdynExperiment { // 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); + defaultParameters = ModelicaManager.getModelParameters(flatModelText); 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)); + HashMap parameterChanges = new HashMap(); + if(!structureChanged && defaultParameters != null) { + HashMap currentParameters = ModelicaManager.getModelParameters(flatModelText); + for(String key : defaultParameters.keySet()) { + if(!defaultParameters.get(key).equals(currentParameters.get(key))) { + parameterChanges.put(key, currentParameters.get(key)); } } - previousParameters = newParameters; } progressMonitor.worked(1); if(simulationLocation != null && !canceled) { // Simulate the model - runModelica(simulationLocation, monitor, progressMonitor, experimentParameters, changes); + runModelica(simulationLocation, monitor, progressMonitor, experimentParameters, parameterChanges); } if(canceled) @@ -592,68 +589,6 @@ public class OldSysdynExperiment extends SysdynExperiment { 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 */ 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 e4f589ac..288bb1bf 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java @@ -12,7 +12,6 @@ package org.simantics.sysdyn.manager; import gnu.trove.list.array.TDoubleArrayList; -import gnu.trove.map.hash.THashMap; import java.io.File; import java.io.FileInputStream; @@ -145,7 +144,6 @@ public class SysdynGameExperiment extends SysdynGameExperimentBase { if (fmu == null && (!isValidFMU(simulationLocation.executableFile) || sysdynModel.isStructureModified())) { progressMonitor.subTask("Build model"); buildModel(simulationLocation, monitor); - previousModelStructure = modelText; saveModelFmu(simulationLocation); } 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 891983ba..fedac97a 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java @@ -278,7 +278,7 @@ public class SysdynModel implements IModel, IMappingListener, VariableSubscripti if(mapping.isDomainModified()) { try { Collection updated = mapping.updateRange(graph); - + for(Object o : updated) { if(o instanceof Model) { continue; diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolver.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolver.java index 846f3701..782285d8 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolver.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/solver/InternalSolver.java @@ -70,7 +70,7 @@ public class InternalSolver implements ISolver { FunctionUtils.updateFunctionFilesForExperiment(experiment); location = ModelicaManager.createSimulationLocation(experiment.getExperimentDir(), - model.getConfiguration().getLabel(), modelContent, null, false); + model.getConfiguration().getLabel(), modelContent); solver.setStep(step); solver.setStart(start); -- 2.47.1