From e03c920ac513422954aef00d403198aa9f154407 Mon Sep 17 00:00:00 2001 From: lempinen Date: Wed, 30 May 2012 08:49:43 +0000 Subject: [PATCH] Output interval created to ease the load for reading simulation results. Game experiments gain more from this modification than traditional simulations. Traditional simulations still initially read all results but save only part of it to memory. Reading is still slow, but displaying results is faster. (refs #3476) git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@25068 ac1ea38d-2e2b-0410-8846-a27921b304fc --- .../FMUSolution/FMUSolution.opensdf | Bin 34 -> 0 bytes .../modelica/data/CSVSimulationResult.java | 4 +- .../simantics/modelica/data/Mat4Reader.java | 21 +++++-- .../modelica/data/MatSimulationResult.java | 4 +- .../modelica/data/SimulationResult.java | 32 +++++++--- org.simantics.sysdyn.ontology/graph.tg | Bin 63802 -> 63977 bytes .../graph/Sysdyn.pgraph | 1 + .../org/simantics/sysdyn/SysdynResource.java | 6 ++ .../ui/menu/PlaybackSliderContribution.java | 5 +- .../ui/properties/ConfigurationTab.java | 10 +++ .../sysdyn/manager/HistoryDatasetResult.java | 4 +- .../sysdyn/manager/SysdynExperiment.java | 57 ++++++++++++++---- .../sysdyn/manager/SysdynGameExperiment.java | 54 +++++++++++------ .../sysdyn/manager/SysdynInitKeys.java | 1 + .../manager/SysdynPlaybackExperiment.java | 1 - .../sysdyn/representation/Model.java | 12 +++- 16 files changed, 158 insertions(+), 54 deletions(-) delete mode 100644 org.simantics.modelica/FMUSolution/FMUSolution.opensdf diff --git a/org.simantics.modelica/FMUSolution/FMUSolution.opensdf b/org.simantics.modelica/FMUSolution/FMUSolution.opensdf deleted file mode 100644 index f8442e664d8d47113b89cde8a3294c019a6f05b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34 mcmXS6NM$HyC;^g144DiJ48aV645193K-z;rmmz?`nE?QAmIa;w diff --git a/org.simantics.modelica/src/org/simantics/modelica/data/CSVSimulationResult.java b/org.simantics.modelica/src/org/simantics/modelica/data/CSVSimulationResult.java index 1c3b1e2f..8787adf9 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/data/CSVSimulationResult.java +++ b/org.simantics.modelica/src/org/simantics/modelica/data/CSVSimulationResult.java @@ -28,7 +28,7 @@ public class CSVSimulationResult extends SimulationResult { * Overridden method to support csv-formatted simulation results */ @Override - public void read(InputStream stream) { + public void read(InputStream stream, int outputInterval) { errors.clear(); // First line contains the variable names in format "name" (including quotes); @@ -42,7 +42,7 @@ public class CSVSimulationResult extends SimulationResult { // Create lists for receiving values for each variable. Names still with quotes. for(String name : names) { if(!name.isEmpty()) - valueMap.put(name, new DataSet(name, new double[numberOfTimeSteps], new double[numberOfTimeSteps])); + valueMap.put(name, new DataSet(name, new double[numberOfLines], new double[numberOfLines])); } int row = 0; diff --git a/org.simantics.modelica/src/org/simantics/modelica/data/Mat4Reader.java b/org.simantics.modelica/src/org/simantics/modelica/data/Mat4Reader.java index 0d896368..ceafe6b0 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/data/Mat4Reader.java +++ b/org.simantics.modelica/src/org/simantics/modelica/data/Mat4Reader.java @@ -108,7 +108,14 @@ public class Mat4Reader { } } - public static Map read(InputStream in) throws IOException { + /** + * + * @param in InputStream of a mat file + * @param outputInterval the interval of results to be read. 1 reads all time steps, 2 reads every other time step, etc... + * @return + * @throws IOException + */ + public static Map read(InputStream in, int outputInterval) throws IOException { Mat4Reader reader = new Mat4Reader(in); reader.readMatrix(); // Header StringMatrix names = (StringMatrix)reader.readMatrix(); // Variable names @@ -131,13 +138,17 @@ public class Mat4Reader { for(int i=0;i 0 ? sc-1 : 1-sc; //System.out.println("i=" + i + ", sc=" + sc + ", c=" + c); - for(int j=0;j= values.columns) adjusted = values.columns - 1; + v[j] = valueData[rows * adjusted + c]; + } if(sc < 0) for(int j=0;j valueMap = null; try { - valueMap = Mat4Reader.read(stream); + valueMap = Mat4Reader.read(stream, interval); } catch (IOException e) { e.printStackTrace(); return; diff --git a/org.simantics.modelica/src/org/simantics/modelica/data/SimulationResult.java b/org.simantics.modelica/src/org/simantics/modelica/data/SimulationResult.java index 725d7e71..a21a2155 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/data/SimulationResult.java +++ b/org.simantics.modelica/src/org/simantics/modelica/data/SimulationResult.java @@ -50,7 +50,7 @@ public class SimulationResult { protected List variables = new ArrayList(); protected List initials = new ArrayList(); - protected int numberOfTimeSteps = 0; + protected int numberOfLines = 0; /** * Private class used in displaying errors @@ -262,36 +262,50 @@ public class SimulationResult { } - final static Pattern p1 = Pattern.compile("DataSet: ([^ ]*)"); + + /** + * Read result file. Read all values in the result file. + * + * @param file result file + * @throws FileNotFoundException + * @throws IOException + */ + public void read(File file) throws FileNotFoundException, IOException { + read(file, 1); + } + /** * Read result file * * @param file result file + * @param interval the interval of results to be read. 1 reads all time steps, 2 reads every other time step, etc... * @throws FileNotFoundException * @throws IOException */ - public void read(File file) throws FileNotFoundException, IOException { + public void read(File file, int interval) throws FileNotFoundException, IOException { // First check the number of time steps FileReader fr = new FileReader(file); LineNumberReader lnr = new LineNumberReader(fr); lnr.skip(Long.MAX_VALUE); - numberOfTimeSteps = lnr.getLineNumber() - 1; // minus the first row, which is for names + numberOfLines = lnr.getLineNumber() - 1; // minus the first row, which is for names lnr.close(); fr.close(); InputStream is = new FileInputStream(file); - read(is); + read(is, interval); is.close(); } - + final static Pattern p1 = Pattern.compile("DataSet: ([^ ]*)"); + /** * Read result file. The basic implementation supports * plt-formatted results. Overridden to support other formats. * @param stream FileInputStream for the result file + * @param interval the interval of results to be read. 1 reads all time steps, 2 reads every other time step, etc... */ - public void read(InputStream stream) { + public void read(InputStream stream, int outputInterval) { while(true) { String line = getLine(stream); if(line == null) @@ -307,8 +321,8 @@ public class SimulationResult { return; String name = matcher.group(1); - double[] dtimes = new double[numberOfTimeSteps]; - double[] dvalues = new double[numberOfTimeSteps]; + double[] dtimes = new double[numberOfLines]; + double[] dvalues = new double[numberOfLines]; int i = 0; while(true) { String line = getLine(stream); diff --git a/org.simantics.sysdyn.ontology/graph.tg b/org.simantics.sysdyn.ontology/graph.tg index efe3183fb9e739f23e8abc2e11d436338108becb..185aa2016d61749af563452940037e17ea6eb9a0 100644 GIT binary patch literal 63977 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 literal 63802 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 Qhq)Fx*Ob#_$|>sq0PE!WQ2+n{ diff --git a/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph b/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph index 54086f8a..9584de37 100644 --- a/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph +++ b/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph @@ -33,6 +33,7 @@ SYSDYN.SharedModuleOntolofgy -- SYSDYN.SysdynModel.startTime --> L0.Double -- SYSDYN.SysdynModel.stopTime --> L0.Double -- SYSDYN.SysdynModel.simulationStepLength --> L0.Double -- SYSDYN.SysdynModel.outputInterval --> L0.Double -- SYSDYN.SysdynModel.tolerance --> L0.Double -- SYSDYN.SysdynModel.solver --> L0.String () { @Override public Double[] perform(ReadGraph graph) throws DatabaseException { - Double[] numbers = new Double[3]; + Double[] numbers = new Double[2]; Resource model = spe.getModel(); SysdynResource sr = SysdynResource.getInstance(graph); numbers[0] = graph.getRelatedValue(model, sr.SysdynModel_startTime); numbers[1] = graph.getRelatedValue(model, sr.SysdynModel_stopTime); - numbers[2] = graph.getPossibleRelatedValue(model, sr.SysdynModel_outputInterval); return numbers; } }); diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/ConfigurationTab.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/ConfigurationTab.java index f0d9b324..96dea950 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/ConfigurationTab.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/ConfigurationTab.java @@ -120,12 +120,22 @@ public class ConfigurationTab extends LabelPropertyTabContributor { label = new Label(composite, SWT.NONE); label.setText("Step length\n(empty = default)"); + TrackedText stepLength = new TrackedText(composite, support, SWT.BORDER | SWT.RIGHT); + stepLength.setTextFactory(new DoublePropertyFactory(SysdynResource.URIs.SysdynModel_simulationStepLength)); + stepLength.addModifyListener(new DoublePropertyModifier(context, SysdynResource.URIs.SysdynModel_simulationStepLength)); + stepLength.setInputValidator(new DoubleValidator()); + GridDataFactory.fillDefaults().hint(200, SWT.DEFAULT).applyTo(stepLength.getWidget()); + + label = new Label(composite, SWT.NONE); + label.setText("Output interval\n(empty = all steps)"); + TrackedText outputInterval = new TrackedText(composite, support, SWT.BORDER | SWT.RIGHT); outputInterval.setTextFactory(new DoublePropertyFactory(SysdynResource.URIs.SysdynModel_outputInterval)); outputInterval.addModifyListener(new DoublePropertyModifier(context, SysdynResource.URIs.SysdynModel_outputInterval)); outputInterval.setInputValidator(new DoubleValidator()); GridDataFactory.fillDefaults().hint(200, SWT.DEFAULT).applyTo(outputInterval.getWidget()); + label = new Label(composite, SWT.NONE); label.setText("Method"); diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/HistoryDatasetResult.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/HistoryDatasetResult.java index 9b0d515c..17d8bac1 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/HistoryDatasetResult.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/HistoryDatasetResult.java @@ -49,9 +49,9 @@ import org.simantics.utils.datastructures.Pair; */ public class HistoryDatasetResult extends SimulationResult { @Override - public void read(File file) {} // Do nothing + public void read(File file, int interval) {} // Do nothing @Override - public void read(InputStream stream) {} // Do nothing + public void read(InputStream stream, int interval) {} // Do nothing private boolean disposed; 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 c82649c3..d0e8f385 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java @@ -196,17 +196,22 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { Model model = configuration.getModel(); Double startTime = model.getStartTime(); Double stopTime = model.getStopTime(); - Double numberOfIntervals = model.getOutputInterval(); inits.put(SysdynInitKeys.START_VALUE, startTime.toString()); inits.put(SysdynInitKeys.STOP_VALUE, stopTime.toString()); String outputFormat = "\"mat\""; inits.put(SysdynInitKeys.OUTPUT_FORMAT, outputFormat); - if(numberOfIntervals != null) { - inits.put(SysdynInitKeys.STEP_VALUE, numberOfIntervals.toString()); - inits.put(SysdynInitKeys.NUMBER_OF_INTERVALS, "" + ((int)((stopTime - startTime) / numberOfIntervals))); + + Double simulationStepLength = model.getSimulationStepLength(); + if(simulationStepLength != null) { + inits.put(SysdynInitKeys.STEP_VALUE, simulationStepLength.toString()); + inits.put(SysdynInitKeys.NUMBER_OF_INTERVALS, "" + ((int)((stopTime - startTime) / simulationStepLength))); } else { inits.put(SysdynInitKeys.STEP_VALUE, "" + (stopTime - startTime) / 500); } + + Double outputInterval = model.getOutputInterval(); + inits.put(SysdynInitKeys.OUTPUT_INTERVAL, outputInterval != null ? outputInterval.toString() : inits.get(SysdynInitKeys.STEP_VALUE)); + String method = "\"" + model.getSolver() + "\""; inits.put(SysdynInitKeys.METHOD, method); if(model.getTolerance() != null) @@ -251,7 +256,7 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { ); ModelicaManager.printProcessOutput(process, monitor); - Thread resultThread = getResultThread(simulationLocation, monitor, progressMonitor); + Thread resultThread = getResultThread(simulationLocation, inits, monitor, progressMonitor); resultThread.run(); process = null; @@ -260,11 +265,12 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { /** * 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 IModelicaMonitor monitor, final IProgressMonitor progressMonitor) { + protected Thread getResultThread(final SimulationLocation simulationLocation, final HashMap inits, final IModelicaMonitor monitor, final IProgressMonitor progressMonitor) { return new Thread() { @Override public void run() { @@ -282,7 +288,23 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { result = new SimulationResult(); else result = new MatSimulationResult(); // The latest format - result.read(simulationLocation.outputFile); + + + // The interval of results saved. Every result? Every other result? etc... + int outIntervalInt = 1; + String outputInterval = inits.get(SysdynInitKeys.OUTPUT_INTERVAL); + if(outputInterval != null) { + String stepTime = inits.get(SysdynInitKeys.STEP_VALUE); + + Double step = Double.parseDouble(stepTime); + Double outInterval = Double.parseDouble(outputInterval); + + double nearest = roundUp(outInterval, step); + outIntervalInt = (int)(nearest / step); + if(outIntervalInt <= 0) outIntervalInt = 1; + } + + result.read(simulationLocation.outputFile, outIntervalInt); result.readInits(simulationLocation.initFile); result.filter(); sysdynModel.getSysdynResult().setResult(result); @@ -305,6 +327,17 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { } }; } + + protected static double roundUp(double numToRound, double multiple) { + if(multiple == 0) { + return numToRound; + } + double remainder = numToRound % multiple; + if (remainder == 0) { + return numToRound; + } + return numToRound + multiple - remainder; + } /** @@ -340,11 +373,11 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { protected void storeImportantInits(HashMap inits) { previousImportantInits.clear(); - previousImportantInits.put("start value", inits.get(SysdynInitKeys.START_VALUE)); - previousImportantInits.put("stop value", inits.get(SysdynInitKeys.STOP_VALUE)); - previousImportantInits.put("method", inits.get(SysdynInitKeys.METHOD)); - previousImportantInits.put("outputFormat", inits.get(SysdynInitKeys.OUTPUT_FORMAT)); - previousImportantInits.put("variableFilter", inits.get(SysdynInitKeys.VARIABLE_FILTER)); + previousImportantInits.put(SysdynInitKeys.START_VALUE, inits.get(SysdynInitKeys.START_VALUE)); + previousImportantInits.put(SysdynInitKeys.STOP_VALUE, inits.get(SysdynInitKeys.STOP_VALUE)); + previousImportantInits.put(SysdynInitKeys.METHOD, inits.get(SysdynInitKeys.METHOD)); + previousImportantInits.put(SysdynInitKeys.OUTPUT_FORMAT, inits.get(SysdynInitKeys.OUTPUT_FORMAT)); + previousImportantInits.put(SysdynInitKeys.VARIABLE_FILTER, inits.get(SysdynInitKeys.VARIABLE_FILTER)); } /** 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 8d82b12f..8bb2e09c 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java @@ -33,7 +33,7 @@ import org.simantics.modelica.fmi.FMUControlJNI; import org.simantics.modelica.fmi.FMUJNIException; import org.simantics.simulation.experiment.ExperimentState; import org.simantics.sysdyn.SysdynResource; -import org.simantics.utils.datastructures.Pair; +import org.simantics.utils.datastructures.Triple; /** * Game experiment @@ -47,9 +47,11 @@ public class SysdynGameExperiment extends SysdynExperiment { private HashMap> results; private double stepLength = DEFAULT_STEP_LENGTH; private double stepDuration = DEFAULT_STEP_DURATION; + private int savePer = 1; public static double DEFAULT_STEP_DURATION = 1.0; public static double DEFAULT_STEP_LENGTH = 0.1; + public static int DEFAULT_OUTPUT_INTERVAL = 1; public SysdynGameExperiment(Resource experiment, Resource model) { super(experiment, model); @@ -71,6 +73,11 @@ public class SysdynGameExperiment extends SysdynExperiment { this.stepLength = stepLength; } + public void setOutputInterval(int interval) { + this.savePer = interval; + } + + public FMUControlJNI getFMUControl() { return control; } @@ -84,23 +91,33 @@ public class SysdynGameExperiment extends SysdynExperiment { results = new HashMap>(); - g.asyncRequest(new Read>() { + g.asyncRequest(new Read>() { @Override - public Pair perform(ReadGraph graph) + public Triple perform(ReadGraph graph) throws DatabaseException { SysdynResource sr = SysdynResource.getInstance(graph); Double stepDuration = graph.getPossibleRelatedValue(experiment, sr.GameExperiment_stepDuration); - Double stepLength =graph.getPossibleRelatedValue(experiment, sr.GameExperiment_stepLength); - return new Pair(stepDuration, stepLength); + Double stepLength = graph.getPossibleRelatedValue(experiment, sr.GameExperiment_stepLength); + Double outputInterval = graph.getPossibleRelatedValue(model, sr.SysdynModel_outputInterval); + return new Triple(stepDuration, stepLength, outputInterval); } - }, new AsyncListener>() { + }, new AsyncListener>() { @Override public void execute(AsyncReadGraph graph, - Pair result) { + Triple result) { setStepDuration(result.first != null ? result.first : DEFAULT_STEP_DURATION); setStepLength(result.second != null ? result.second : DEFAULT_STEP_LENGTH); + + if(result.third == null) { + setOutputInterval(DEFAULT_OUTPUT_INTERVAL); + } else { + double nearest = roundUp(result.third, getStepLength()); + int interval = (int)(nearest / getStepLength()); + if(interval <= 0) interval = 1; + setOutputInterval(interval); + } } @Override @@ -108,6 +125,7 @@ public class SysdynGameExperiment extends SysdynExperiment { throwable.printStackTrace(); setStepDuration(DEFAULT_STEP_DURATION); setStepLength(DEFAULT_STEP_LENGTH); + setOutputInterval(DEFAULT_OUTPUT_INTERVAL); } @Override @@ -219,7 +237,6 @@ public class SysdynGameExperiment extends SysdynExperiment { @Override protected IStatus run(IProgressMonitor monitor) { - int nSteps = (int)(duration / stepLength); int work = 1 + nSteps * 3 + 2; // initialization + number of steps * number of phases per step + set result + call result listeners @@ -241,20 +258,24 @@ public class SysdynGameExperiment extends SysdynExperiment { double[] results = new double[subscription.length]; monitor.worked(1); - + + int stepNumber = 1; while(control.getTime() < (eTime - 1e-9)) { // Substract a very small number, because OpenModelica is not very precise with its Real numbers monitor.subTask("Simulate step (time = " + control.getTime() + ")"); control.simulateStep(); monitor.worked(1); - monitor.subTask("Get results (time = " + control.getTime() + ")"); - results = control.getSubscribedResults(results); - monitor.worked(1); - - monitor.subTask("Save results (time = " + control.getTime() + ")"); - for(int k = 0; k < subscription.length; k++) { - SysdynGameExperiment.this.results.get(subscription[k]).add(results[k]); + if(stepNumber % savePer == 0) { + monitor.subTask("Get results (time = " + control.getTime() + ")"); + results = control.getSubscribedResults(results); + monitor.worked(1); + + monitor.subTask("Save results (time = " + control.getTime() + ")"); + for(int k = 0; k < subscription.length; k++) { + SysdynGameExperiment.this.results.get(subscription[k]).add(results[k]); + } } + stepNumber++; monitor.worked(1); } @@ -268,7 +289,6 @@ public class SysdynGameExperiment extends SysdynExperiment { } catch (FMUJNIException e) { System.err.println("SysdynGameExperiment simulateDuration failed: \n\t" + e.getMessage()); } - return Status.OK_STATUS; } } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynInitKeys.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynInitKeys.java index 3d405ebd..65168bcb 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynInitKeys.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynInitKeys.java @@ -26,5 +26,6 @@ public class SysdynInitKeys { 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.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java index 5c8f955c..45cebeab 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java @@ -232,7 +232,6 @@ public class SysdynPlaybackExperiment extends SysdynExperiment implements IDynam SysdynResource sr = SysdynResource.getInstance(graph); numbers[0] = graph.getRelatedValue(model, sr.SysdynModel_startTime); numbers[1] = graph.getRelatedValue(model, sr.SysdynModel_stopTime); - numbers[2] = graph.getPossibleRelatedValue(model, sr.SysdynModel_outputInterval); PlaybackConfiguration config = new PlaybackConfiguration(); config.simulationDuration = numbers[1] - numbers[0] - time; diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Model.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Model.java index 3cb5be55..6e22190f 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Model.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Model.java @@ -39,6 +39,9 @@ public class Model { @RelatedValue(SysdynResource.URIs.SysdynModel_outputInterval) private Double outputInterval; + + @RelatedValue(SysdynResource.URIs.SysdynModel_simulationStepLength) + private Double stepLength; @RelatedValue(SysdynResource.URIs.SysdynModel_tolerance) private Double tolerance; @@ -83,13 +86,20 @@ public class Model { } /** - * Result output interval + * Simulation output interval * @return */ public Double getOutputInterval() { return outputInterval; } + /** + * Simulation step length + * @return + */ + public Double getSimulationStepLength() { + return stepLength; + } /** * * @return Tolerance for simulation engine -- 2.47.1