From 46a96fec2e91d849d35a28a145403972608f7b6e Mon Sep 17 00:00:00 2001 From: villberg Date: Mon, 12 Dec 2016 11:18:53 +0000 Subject: [PATCH] refs #6860 Sysdyn update site on top of Simantics Desktop Share project "org.simantics.sysdyn.omsolver" into "https://www.simantics.org/svn/simantics" git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/branches/git@33415 ac1ea38d-2e2b-0410-8846-a27921b304fc --- org.simantics.sysdyn.omsolver/.classpath | 7 + org.simantics.sysdyn.omsolver/.project | 28 ++ .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 15 + .../build.properties | 4 + .../simantics/sysdyn/omsolver/Activator.java | 70 +++ .../sysdyn/omsolver/GameExperiment.java | 415 ++++++++++++++++++ .../omsolver/GameExperimentFactory.java | 14 + .../sysdyn/omsolver/ModelicaSolver.java | 93 ++++ 9 files changed, 653 insertions(+) create mode 100644 org.simantics.sysdyn.omsolver/.classpath create mode 100644 org.simantics.sysdyn.omsolver/.project create mode 100644 org.simantics.sysdyn.omsolver/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.simantics.sysdyn.omsolver/META-INF/MANIFEST.MF create mode 100644 org.simantics.sysdyn.omsolver/build.properties create mode 100644 org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/Activator.java create mode 100644 org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/GameExperiment.java create mode 100644 org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/GameExperimentFactory.java create mode 100644 org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/ModelicaSolver.java diff --git a/org.simantics.sysdyn.omsolver/.classpath b/org.simantics.sysdyn.omsolver/.classpath new file mode 100644 index 00000000..b862a296 --- /dev/null +++ b/org.simantics.sysdyn.omsolver/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.simantics.sysdyn.omsolver/.project b/org.simantics.sysdyn.omsolver/.project new file mode 100644 index 00000000..29ec02dc --- /dev/null +++ b/org.simantics.sysdyn.omsolver/.project @@ -0,0 +1,28 @@ + + + org.simantics.sysdyn.omsolver + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/org.simantics.sysdyn.omsolver/.settings/org.eclipse.jdt.core.prefs b/org.simantics.sysdyn.omsolver/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..295926d9 --- /dev/null +++ b/org.simantics.sysdyn.omsolver/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/org.simantics.sysdyn.omsolver/META-INF/MANIFEST.MF b/org.simantics.sysdyn.omsolver/META-INF/MANIFEST.MF new file mode 100644 index 00000000..c0ab4deb --- /dev/null +++ b/org.simantics.sysdyn.omsolver/META-INF/MANIFEST.MF @@ -0,0 +1,15 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Open Modelica solver +Bundle-SymbolicName: org.simantics.sysdyn.omsolver +Bundle-Version: 1.0.0.qualifier +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.simantics.sysdyn;bundle-version="1.9.0", + org.eclipse.osgi;bundle-version="3.10.102", + org.simantics.fmu;bundle-version="1.1.0", + org.simantics;bundle-version="1.0.0", + org.simantics.modelica;bundle-version="1.1.0", + org.simantics.modeling;bundle-version="1.1.1", + org.simantics.simulation;bundle-version="1.1.0" +Bundle-ActivationPolicy: lazy +Bundle-Activator: org.simantics.sysdyn.omsolver.Activator diff --git a/org.simantics.sysdyn.omsolver/build.properties b/org.simantics.sysdyn.omsolver/build.properties new file mode 100644 index 00000000..41eb6ade --- /dev/null +++ b/org.simantics.sysdyn.omsolver/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/Activator.java b/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/Activator.java new file mode 100644 index 00000000..9391e605 --- /dev/null +++ b/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/Activator.java @@ -0,0 +1,70 @@ +package org.simantics.sysdyn.omsolver; +import java.io.File; +import java.io.IOException; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.simantics.fmu.FMUControlJNI; +import org.simantics.sysdyn.solver.SolverSettings.SolverType; +import org.simantics.sysdyn.solver.Solvers; +import org.simantics.utils.FileUtils; + +public class Activator implements BundleActivator { + + private static BundleContext context; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.context = bundleContext; + clearFMUTempDirectory(); + Solvers.registerGameExperimentFactory(SolverType.OPENMODELICA, new GameExperimentFactory()); + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + Solvers.unregisterGameExperimentFactory(SolverType.OPENMODELICA); + clearFMUTempDirectory(); + Activator.context = null; + } + + /** + * Clears fmu temp directory. This directory hosts + * fmu files for game experiments. In normal situations + * experiments clean up their temp files, but for example + * a system crash may leave files to temp directory. + */ + private void clearFMUTempDirectory() { + // Find commone "TEMP/fmu" directory + File commonDir = new File(FMUControlJNI.TEMP_FMU_COMMON_DIRECTORY); + if(commonDir != null && commonDir.isDirectory()) { + + // List all files and directories in "TEMP/fmu" + for(File child : commonDir.listFiles()) { + if(child.isDirectory()) { + // If directory is found, try to get the lock file in it + File lock = new File(child, FMUControlJNI.LOCK_FILE_NAME); + if(!lock.isFile() || lock.delete()) { + // If lock is not found, or the lock can be delted, the directory is not locked. -> Delete the rest of the directory + try { + FileUtils.deleteAll(child); + child.delete(); + } catch (IOException e) { + + } + } + } + } + } + } + +} diff --git a/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/GameExperiment.java b/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/GameExperiment.java new file mode 100644 index 00000000..9104b4ce --- /dev/null +++ b/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/GameExperiment.java @@ -0,0 +1,415 @@ +/******************************************************************************* + * Copyright (c) 2007, 2012, 2015 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 + *******************************************************************************/ +package org.simantics.sysdyn.omsolver; + +import gnu.trove.list.array.TDoubleArrayList; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.HashMap; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.simantics.Simantics; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.Session; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.utils.Logger; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.util.Layer0Utils; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.layer0.variable.Variables; +import org.simantics.db.request.Read; +import org.simantics.fmu.FMUControlJNI; +import org.simantics.fmu.FMUJNIException; +import org.simantics.modelica.IModelicaMonitor; +import org.simantics.modelica.ModelicaManager; +import org.simantics.modelica.SimulationLocation; +import org.simantics.modeling.PartialIC; +import org.simantics.sysdyn.SysdynResource; +import org.simantics.sysdyn.manager.SysdynGameExperimentBase; +import org.simantics.sysdyn.simulation.SimulationJob.HeadlessModelicaMonitor; +import org.simantics.sysdyn.solver.ISolver; + +/** + * Game experiment + * @author Teemu Lempinen + * + */ +public class GameExperiment extends SysdynGameExperimentBase { + + private ModelicaSolver solver; + public FMUControlJNI control; + private boolean loaded = false; + + private static boolean fortranLibrariesLoaded = false; + + public GameExperiment(Resource experiment, Resource model) { + super(experiment, model); + this.solver = new ModelicaSolver(this); + } + + public FMUControlJNI getFMUControl() { + return control; + } + + @Override + public void init(ReadGraph g) { + super.init(g); + + if(control == null) + control = new FMUControlJNI(); + + results = new TDoubleArrayList[results != null ? results.length : 0]; + + } + + @Override + protected void onExperimentDisposed() { + super.onExperimentDisposed(); + if(control!=null) { + try { + control.unloadFMU(); + loaded = false; + } catch (FMUJNIException e) { + e.printStackTrace(); + } + } + } + + private boolean isValidFMU(File file) { + if(!file.exists()) return false; + if(!file.isFile()) return false; + if(file.length() == 0) return false; + return true; + } + + + @Override + public synchronized void simulate(final IModelicaMonitor monitor, final IProgressMonitor progressMonitor, String modelName) throws IOException { + canceled = false; + + progressMonitor.subTask("Write modelica classes"); + + // Write Modelica files + String modelText = getModelicaCode(monitor, true, getOpenModelicaVersion()); + if(modelText == null) + return; + + omcVersion = ModelicaManager.getDefaultOMVersion(); + + monitor.message("Simulate " + modelName + " using OpenModelica " + omcVersion); + + progressMonitor.worked(1); + + // Write initial files and add init-parameters + progressMonitor.subTask("Write simulation files"); + HashMap inits = getExperimentParameters(monitor); + + + // add loadFile script to load all related functions and function libraries + String additionalScript = getAdditionalScripts(); + + // Create simulation files + SimulationLocation simulationLocation = createSimulationFiles(sysdynModel, modelText, inits, additionalScript, true); + progressMonitor.worked(1); + + // Load precompiled fmu if structure has not changed and it has not yet been loaded + File fmu = null; + if(!sysdynModel.isStructureModified()) { + if(!simulationLocation.executableFile.isFile()) { + fmu = loadModelFmu(simulationLocation); + } else { + fmu = simulationLocation.executableFile; + } + } + // 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 + if (fmu == null && (!isValidFMU(simulationLocation.executableFile) || sysdynModel.isStructureModified())) { + progressMonitor.subTask("Build model"); + buildModel(simulationLocation, monitor); + + saveModelFmu(simulationLocation); + } + + progressMonitor.worked(1); + + if(simulationLocation != null && !canceled) { + // Load fmu and initialize it for simulation + try { + if (!fortranLibrariesLoaded) { // Enable this when we update from OpenModelica 1.9.0beta4! + File omDir = ModelicaManager.getOMHome(); + File mingw = new File(omDir, "MinGW"); + File mbin = new File(mingw, "bin"); + + // Add MinGW path to java.library.path. This is a bit of a hack because + // java.library.path isn't intended to be set programmatically. + String newLibPath = System.getProperty("java.library.path") + File.pathSeparator + mbin.getAbsolutePath(); + System.setProperty("java.library.path", newLibPath); + Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths"); + fieldSysPath.setAccessible(true); + if (fieldSysPath != null) { + fieldSysPath.set(System.class.getClassLoader(), null); + } + + System.loadLibrary("libgfortran-3"); + System.out.println("Loaded libgfortran-3.dll"); + System.loadLibrary("pthreadGC2"); + System.out.println("Loaded pthreadGC2.dll"); + fortranLibrariesLoaded = true; + } + + control.loadFMUFile(simulationLocation.executableFile.getAbsolutePath()); // unzip and load fmu + loaded = true; + instantiate(); + + } catch (FMUJNIException e) { + System.err.println("SysdynGameExperiment initialization failed:\n\t" + e.getMessage()); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchFieldException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + process = null; + simulate(false); + } + + /** + * Load fmu file from database, if it exists for the model of this experiment + * + * @param simulationLocation SimulationLocation indicating where the fmu should be loaded + * @return Loaded fmu or null if it was not loaded from database + */ + private File loadModelFmu(SimulationLocation simulationLocation) { + File fmu = null; + try { + final String fmuLocation = simulationLocation.executableFile.getAbsolutePath(); + fmu = session.syncRequest(new Read() { + @Override + public File perform(ReadGraph graph) throws DatabaseException { + File result = null; + FileOutputStream fos; + try { + fos = new FileOutputStream(fmuLocation); + byte[] fileBArray = graph.getPossibleRelatedValue( + getModel(), SysdynResource.getInstance(graph).SysdynModel_fmuFile, Bindings.BYTE_ARRAY); + + if(fileBArray != null) { + fos.write(fileBArray); + fos.close(); + result = new File(fmuLocation); + } else { + fos.close(); + return null; + } + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return result; + } + }); + } catch (DatabaseException e) { + e.printStackTrace(); + } + + return fmu; + } + + /** + * Save fmu file from simulationLocation to database + * @param simulationLocation Location for finding fmu + */ + private void saveModelFmu(SimulationLocation simulationLocation) { + final String fmuLocation = simulationLocation.executableFile.getAbsolutePath(); + session.asyncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + File file = new File(fmuLocation); + byte[] fileBArray = new byte[(int)file.length()]; + FileInputStream fis; + try { + fis = new FileInputStream(file); + + fis.read(fileBArray); + graph.claimLiteral( + getModel(), + SysdynResource.getInstance(graph).SysdynModel_fmuFile, + fileBArray, Bindings.BYTE_ARRAY); + fis.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + } + + + @Override + public void rewindTo(double time) { + + if(control == null) + return; + + if(time >-0.001 && time < 0.001) { + try { + simulate(new HeadlessModelicaMonitor(), new NullProgressMonitor(), sysdynModel.getConfiguration().getLabel()); + //instantiate(); + } catch (IOException e) { + Logger.defaultLogError(e); + } + } else { + System.out.println("rewindTo"); + } + } + + @Override + public void refresh(Session session) { + try { + control.initializeSimulation(); + clearResults(); + //getInitialResultValues(); + + } catch (FMUJNIException e) { + System.err.println("SysdynGameExperiment instantiate failed: " + e.getMessage()); + } + } + + private synchronized void instantiate() { + try { + HashMap inits = getExperimentParameters(null); + + control.setStepLength(stepLength); // FIXME: fixed step lenghth + control.setTime(startTime); + control.instantiateSimulation(); // instantiate simulation + + if(!control.isInitialized()) { + control.initializeSimulation(); + } + + if(inits.get("variableFilter") == null || inits.get("variableFilter").equals(".*")) + subscription = control.getAllVariables(); + else + subscription = control.filterVariables(inits.get("variableFilter")); + + // Initialize subscription indexes map for fast result reading in getValue() + if(subscriptionIndexes == null) + subscriptionIndexes = new HashMap(); + + subscriptionIndexes.clear(); + for(int i = 0; i < subscription.length; i++) { + subscriptionIndexes.put(subscription[i], i); + } + + results = new TDoubleArrayList[subscription.length]; + + // Initialize container for current simulation results + currentValues = new double[subscription.length]; + + // subscribe all variables + control.subscribe(subscription); + + clearResults(); + //getInitialResultValues(); + + Simantics.getSession().syncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + + Resource run = Layer0Utils.getPossibleChild(graph, GameExperiment.this.experiment, getIdentifier()); + if(run == null) { + System.err.println("No run"); + return; + } + + Variable base = Variables.getVariable(graph, run); + + SysdynResource SYSDYN = SysdynResource.getInstance(graph); + + Resource ic = graph.getPossibleObject(GameExperiment.this.experiment, SYSDYN.Experiment_ic); + if(ic == null) return; + + PartialIC data = graph.getPossibleRelatedValue(ic, SYSDYN.InitialCondition_HasInitialValues, PartialIC.BINDING); + data.apply(graph, base); + + } + + }); + + } catch (FMUJNIException e) { + System.err.println("SysdynGameExperiment instantiate failed: " + e.getMessage()); + } catch (DatabaseException e) { + System.err.println("SysdynGameExperiment instantiate failed: " + e.getMessage()); + } + } + +// private synchronized void getInitialResultValues() { +// try { +// // Initialize results +// results.clear(); +// +// currentValues = control.getSubscribedResults(currentValues); +// for(int k = 0; k < subscription.length; k++) { +// results.put(subscription[k], new ArrayList()); +// results.get(subscription[k]).add(currentValues[k]); +// } +// +// ((MemoryResult)getCurrentResult()).setResult(new GameResult(this.results, this.subscription)); +// resultsChanged(); +// } catch (FMUJNIException e) { +// System.err.println("SysdynGameExperiment getInitialResultValues failed: " + e.getMessage()); +// } +// } + + @Override + public void updateSubscriptions() { + + if(!loaded) return; + + try { + if(control.isInitialized()) + currentValues = control.getSubscribedResults(currentValues); + } catch (FMUJNIException e) { + e.printStackTrace(); + } + super.updateSubscriptions(); + } + + @Override + public ISolver getSolver() { + return solver; + } + + } diff --git a/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/GameExperimentFactory.java b/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/GameExperimentFactory.java new file mode 100644 index 00000000..e9439a78 --- /dev/null +++ b/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/GameExperimentFactory.java @@ -0,0 +1,14 @@ +package org.simantics.sysdyn.omsolver; + +import org.simantics.db.Resource; +import org.simantics.sysdyn.manager.SysdynExperiment; +import org.simantics.sysdyn.manager.SysdynExperimentFactory; + +public class GameExperimentFactory implements SysdynExperimentFactory { + + @Override + public SysdynExperiment create(Resource experiment, Resource model) { + return new GameExperiment(experiment, model); + } + +} diff --git a/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/ModelicaSolver.java b/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/ModelicaSolver.java new file mode 100644 index 00000000..17528b76 --- /dev/null +++ b/org.simantics.sysdyn.omsolver/src/org/simantics/sysdyn/omsolver/ModelicaSolver.java @@ -0,0 +1,93 @@ +package org.simantics.sysdyn.omsolver; + +import org.simantics.fmu.FMUJNIException; +import org.simantics.sysdyn.solver.ISolver; +import org.simantics.sysdyn.solver.SolverSettings.SolverType; + +public class ModelicaSolver implements ISolver { + + GameExperiment exp; + + public ModelicaSolver(GameExperiment exp) { + this.exp = exp; + } + + @Override + public void initialize() throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public void buildModel() throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public void runSolver() throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public void updateResults() throws Exception { + // TODO Auto-generated method stub + + } + + @Override + public SolverType getType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public double[] getSubscribedResults(double[] array) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void prepareToStep() throws Exception { + + // initialize if not initialized + if(!exp.control.isInitialized()) { + exp.control.setTime(exp.startTime); + exp.control.initializeSimulation(); + exp.clearResults(); + // getInitialResultValues(); + } + + exp.control.setStepLength(exp.stepLength); // Set step length each time in case there has been changes + + } + + @Override + public void simulateStep() throws Exception { + exp.control.simulateStep(); + } + + @Override + public void setStepLength(double length) throws Exception { + exp.control.setStepLength(length); + } + + @Override + public double getTime() { + if(exp.control != null) { + try { + return exp.control.getTime(); + } catch (FMUJNIException e) { + } + } + return 0.0; + } + + @Override + public void setRealValue(String name, double value) throws Exception { + exp.control.setRealValue(name, value); + } + + +} -- 2.47.1