From 9648c5fe130bc715ed2768e795612fef0a67f146 Mon Sep 17 00:00:00 2001 From: lempinen Date: Tue, 24 Jul 2012 10:02:07 +0000 Subject: [PATCH] Removing dependencies to experiment UI-concepts (i.e. Active experiment) from experiments and results. Results should be experiment-specific. The work is only half-way done. Things still to come: move simulation files from model-specific folder to experiment specific folder to allow multiple simulations on same model. Remove all references to active experiment from everywhere else than sysdyn.ui. The concept is only valid in the workbench. (refs #3530) git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@25345 ac1ea38d-2e2b-0410-8846-a27921b304fc --- org.simantics.sysdyn.ontology/graph.tg | Bin 66572 -> 66656 bytes .../ui/modelica/SysdynModelicaEditor.java | 3 +- .../expressions/ParameterExpression.java | 103 +++---- .../ui/trend/chart/CategoryDataset.java | 3 +- .../sysdyn/ui/trend/chart/PieDataset.java | 2 +- .../sysdyn/ui/trend/chart/XYDataset.java | 2 +- .../SysdynDatasetSelectionListener.java | 271 ++++++------------ org.simantics.sysdyn.ui/sysdyn.product | 4 +- .../adapter/ActiveDatasetsIndexVariable.java | 23 +- .../sysdyn/adapter/IndexVariable.java | 25 +- .../sysdyn/adapter/TimeIndexVariable.java | 32 ++- .../sysdyn/adapter/TimesIndexVariable.java | 36 ++- .../sysdyn/adapter/ValueIndexVariable.java | 76 +++-- .../sysdyn/adapter/ValuesIndexVariable.java | 27 +- .../sysdyn/manager/SysdynExperiment.java | 66 +++-- .../sysdyn/manager/SysdynGameExperiment.java | 10 +- .../simantics/sysdyn/manager/SysdynModel.java | 59 ++-- .../manager/SysdynPlaybackExperiment.java | 6 +- .../sysdyn/modelica/ModelicaWriter.java | 14 +- .../sysdyn/representation/Configuration.java | 9 + .../sysdyn/representation/Module.java | 2 +- .../sysdyn/representation/Variability.java | 2 +- .../representation/utils/FormatUtils.java | 17 +- .../utils/RepresentationUtils.java | 40 ++- 24 files changed, 430 insertions(+), 402 deletions(-) diff --git a/org.simantics.sysdyn.ontology/graph.tg b/org.simantics.sysdyn.ontology/graph.tg index b6d1deff911d8a52db031c3516591436f5c42bea..9162f738a3cb00f096d6297ce0e8a4fdea6db654 100644 GIT binary patch literal 66656 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 literal 66572 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 G^Zx() { - - @Override - public Double perform(ReadGraph graph) throws DatabaseException { - try { - Variable valuesVariable = variable.browsePossible(graph, "#values#"); - double[] res = valuesVariable.getValue(graph); - if(res != null && res.length > 0) - return res[0]; - else - return null; - } catch (DatabaseException e) { - throw new DatabaseException(e.getMessage()); - } - } - }); - if(value != null) - data.put("equation", value.toString()); - else - super.readData(expression, data); - - } catch (DatabaseException e) { - super.readData(expression, data); + ExperimentState state = ((SysdynGameExperiment)experiment).getSysdynExperimentState(); + if(ExperimentState.RUNNING.equals(state) || ExperimentState.STOPPED.equals(state)) { + try { + value = SimanticsUI.getSession().syncRequest(new Read() { + + @Override + public Double perform(ReadGraph graph) throws DatabaseException { + try { + Variable valuesVariable = variable.browsePossible(graph, "#value#"); + double[] res = valuesVariable.getValue(graph); + if(res != null && res.length == 1) + return res[0]; + else + return null; + } catch (DatabaseException e) { + throw new DatabaseException(e.getMessage()); + } + } + }); + if(value != null) + data.put("equation", value.toString()); + } catch (DatabaseException e) {} } + super.readData(expression, data); + } } @@ -114,31 +115,35 @@ public class ParameterExpression extends BasicExpression { final String currentText = this.expression.getExpression(); final String oldEquation = (String)data.get("equation"); if(oldEquation == null || - (currentText != null && expressionType != null)) { - if(ExpressionUtils.isParameter(currentText)) { - Boolean success = false; - try { - success = SimanticsUI.getSession().syncRequest(new WriteResultRequest() { - - @Override - public Boolean perform(WriteGraph graph) - throws DatabaseException { - try { - Variable valuesVariable = variable.browsePossible(graph, "#values#"); - if(valuesVariable == null) - return false; - valuesVariable.setValue(graph, new double[] {Double.parseDouble(currentText)}); - return true; - } catch (Exception e) { - return false; - } - } - - }); - } catch (DatabaseException e) { - } - - if(success) { + (currentText != null && expressionType != null)) { + if(ExpressionUtils.isParameter(currentText)) { + Boolean savedIntoFMU = false; + + ExperimentState state = ((SysdynGameExperiment)experiment).getSysdynExperimentState(); + // Set value to control only if the simulation is running or stopped, not before initialization + if(ExperimentState.RUNNING.equals(state) || ExperimentState.STOPPED.equals(state)) { + try { + savedIntoFMU = SimanticsUI.getSession().syncRequest(new WriteResultRequest() { + + @Override + public Boolean perform(WriteGraph graph) + throws DatabaseException { + try { + Variable valuesVariable = variable.browsePossible(graph, "#value#"); + if(valuesVariable == null) + return false; + valuesVariable.setValue(graph, new double[] {Double.parseDouble(currentText)}); + return true; + } catch (Exception e) { + return false; + } + } + + }); + } catch (DatabaseException e) {} + } + + if(savedIntoFMU) { data.put("equation", currentText); return; } else { diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/CategoryDataset.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/CategoryDataset.java index d03a9125..7cf7a94f 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/CategoryDataset.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/CategoryDataset.java @@ -99,7 +99,7 @@ public class CategoryDataset extends AbstractDataset { @Override public Dataset getDataset() { - if(seriesList == null || seriesList.isEmpty()) + if(seriesList == null || seriesList.isEmpty() || SimanticsUI.getSession() == null) return null; if(dataset == null) { @@ -125,7 +125,6 @@ public class CategoryDataset extends AbstractDataset { try { // Get a variable for the series Variable v = Variables.getVariable(graph, realizationURI + rvi); - System.out.println(v.getName(graph)); // Get values Variable dsVariable = v.browsePossible(graph, "#" + Functions.ACTIVE_DATASETS + "#"); if(dsVariable == null) diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/PieDataset.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/PieDataset.java index fb14bf8a..4e88b6ef 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/PieDataset.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/PieDataset.java @@ -113,7 +113,7 @@ public class PieDataset extends AbstractDataset { @Override public Dataset getDataset() { - if(seriesList == null || seriesList.isEmpty()) + if(seriesList == null || seriesList.isEmpty() || SimanticsUI.getSession() == null) return null; if(dataset == null) { diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/XYDataset.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/XYDataset.java index 1b2e24de..fc865f1a 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/XYDataset.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/chart/XYDataset.java @@ -105,7 +105,7 @@ public class XYDataset extends AbstractDataset { if(rvi != null && !rvi.isEmpty()) { try { Variable domainVariable = Variables.getVariable(graph, realizationURI + rvi); - Variable valuesVariable = domainVariable.browsePossible(graph, "#values#"); + Variable valuesVariable = domainVariable.browsePossible(graph, "#" + Functions.VALUES +"#"); if(valuesVariable != null) { double[][] valuesArray = valuesVariable.getValue(graph); if(valuesArray.length > 0) diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/viewUtils/SysdynDatasetSelectionListener.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/viewUtils/SysdynDatasetSelectionListener.java index 5b356766..62b678ac 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/viewUtils/SysdynDatasetSelectionListener.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/viewUtils/SysdynDatasetSelectionListener.java @@ -13,8 +13,6 @@ package org.simantics.sysdyn.ui.viewUtils; import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -25,22 +23,20 @@ import org.eclipse.ui.IWorkbenchPart; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; -import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.common.procedure.adapter.DisposableListener; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.SelectionHints; import org.simantics.db.layer0.exception.MissingVariableException; +import org.simantics.db.layer0.request.PossibleActiveVariableFromVariable; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; +import org.simantics.db.request.Read; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.modeling.ModelingUtils; -import org.simantics.simulation.ontology.SimulationResource; +import org.simantics.sysdyn.Functions; import org.simantics.sysdyn.JFreeChartResource; import org.simantics.sysdyn.SysdynResource; -import org.simantics.sysdyn.adapter.VariableRVIUtils; import org.simantics.sysdyn.manager.SysdynDataSet; -import org.simantics.sysdyn.manager.SysdynModel; -import org.simantics.sysdyn.manager.SysdynModelManager; -import org.simantics.sysdyn.manager.SysdynResult; import org.simantics.sysdyn.ui.trend.PinTrend; import org.simantics.ui.SimanticsUI; import org.simantics.utils.ui.ISelectionUtils; @@ -71,7 +67,14 @@ public abstract class SysdynDatasetSelectionListener implements ISelectionListen */ protected abstract void selectionChanged(ReadGraph graph, Resource resource); - HashMap resultListeners = new HashMap(); + + + public void dispose() { + if(listener != null) + listener.dispose(); + } + + DisposableListener> listener; @Override public void selectionChanged(IWorkbenchPart part, final ISelection selection) { @@ -80,189 +83,116 @@ public abstract class SysdynDatasetSelectionListener implements ISelectionListen return; if(selection instanceof IStructuredSelection) { - // Remove all previously added result listeners from model - if(!resultListeners.isEmpty()) { - for(SysdynModel model : resultListeners.keySet()) - model.removeResultListener(resultListeners.get(model)); - resultListeners.clear(); - } - Session session = SimanticsUI.peekSession(); if (session == null) return; + + if(listener != null) + listener.dispose(); + + listener = new DisposableListener>() { + + @Override + public void execute(ArrayList vars) { + if(vars != null) + selectionChanged(vars); + } - session.asyncRequest(new ReadRequest() { @Override - public void run(ReadGraph graph) throws DatabaseException { + public void exception(Throwable t) { + t.printStackTrace(); + } + }; - // Model browser provides variables - Collection vars = ISelectionUtils.filterSetSelection(selection, Variable.class); + try { + session.syncRequest(new Read>() { + @Override + public ArrayList perform(ReadGraph graph) throws DatabaseException { + + // Model browser provides variables + Collection vars = ISelectionUtils.filterSetSelection(selection, Variable.class); + + if(vars.isEmpty()) { + // Selection did not contain variables + Set ress = ISelectionUtils.filterSetSelection(selection, Resource.class); + List runtimes = ISelectionUtils.getPossibleKeys(selection, SelectionHints.KEY_VARIABLE_RESOURCE, Resource.class); + if(!runtimes.isEmpty()) { + // Selection is most probably in a diagram + Resource runtime = runtimes.get(0); + + // Get variables for selected resources + for(Resource resource : ress) { + Variable variable = getVariable(graph, resource, runtime); + if(variable != null) + vars.add(variable); + } - if(vars.isEmpty()) { - // Selection did not contain variables - Set ress = ISelectionUtils.filterSetSelection(selection, Resource.class); - List runtimes = ISelectionUtils.getPossibleKeys(selection, SelectionHints.KEY_VARIABLE_RESOURCE, Resource.class); - if(!runtimes.isEmpty()) { - // Selection is most probably in a diagram - Resource runtime = runtimes.get(0); + // If there is no vars and only one selection, it can be a chart + if(vars.isEmpty() && ress.size() == 1) { + Resource r = ress.iterator().next(); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + if(graph.isInstanceOf(r, jfree.ChartElement)) { + if(graph.hasStatement(r, jfree.ChartElement_component)) { + r = graph.getSingleObject(r, jfree.ChartElement_component); + selectionChanged(graph, r); + return null; + } + } + } - // Get variables for selected resources - for(Resource resource : ress) { - Variable variable = getVariable(graph, resource, runtime); - if(variable != null) - vars.add(variable); - } - - // If there is no vars and only one selection, it can be a chart - if(vars.isEmpty() && ress.size() == 1) { - Resource r = ress.iterator().next(); - JFreeChartResource jfree = JFreeChartResource.getInstance(graph); - if(graph.isInstanceOf(r, jfree.ChartElement)) { - if(graph.hasStatement(r, jfree.ChartElement_component)) { - r = graph.getSingleObject(r, jfree.ChartElement_component); + } else { + // Selection is a jfreechart + if(ress.size() == 1) { + Resource r = ress.iterator().next(); + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + if(graph.isInstanceOf(r, jfree.Chart)) { selectionChanged(graph, r); - return; + return null; } } } - - } else { - // Selection is a jfreechart - if(ress.size() == 1) { - Resource r = ress.iterator().next(); - JFreeChartResource jfree = JFreeChartResource.getInstance(graph); - if(graph.isInstanceOf(r, jfree.Chart)) { - selectionChanged(graph, r); - return; - } - } } - } - - // Update datasets and add result listeners to models - updateDatasets(graph, vars); - addResultListeners(graph, vars); - } - }); - } - } - - - /** - * Adds result listeners to models. In model browser it is possible to select - * variables from different models. This method adds listeners to all of those. - * - * @param graph ReadGraph graph - * @param variables Selected variables - * @throws DatabaseException - */ - private void addResultListeners(ReadGraph graph, final Collection variables) throws DatabaseException { - if(variables.size() < 1) return; - - // Get models - HashSet models = new HashSet(); - for(Variable variable : variables) { - Resource model = Variables.getModel(graph, variable); - if(model != null) { - models.add(getSysdynModel(graph, model)); - } - } - // Create a result listener - Runnable listener = new Runnable() { - @Override - public void run() { - Session session = SimanticsUI.peekSession(); - if (session == null) - return; + // Update datasets and add result listeners to models + return getDatasets(graph, vars); - session.asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - updateDatasets(graph, variables); } - }); + }, listener); + } catch (DatabaseException e) { + e.printStackTrace(); } - }; - - // Add the result listener to all models and to resultListeners list - for(SysdynModel model : models) { - model.addResultListener(listener); - resultListeners.put(model, listener); } } + + /** * Updates datasets for the selected variables * @param graph ReadGraph * @param variables Selected variables * @throws DatabaseException */ - private void updateDatasets(ReadGraph graph, Collection variables) throws DatabaseException { + private ArrayList getDatasets(ReadGraph graph, Collection variables) throws DatabaseException { ArrayList datasets = new ArrayList(); for(Variable variable : variables) { + Variable v = graph.syncRequest(new PossibleActiveVariableFromVariable(variable)); + if(v == null) + continue; // Get all active datasets for the variable and add them to the result - Collection activeDataSets = loadAllActive(graph, variable); - if(activeDataSets != null && !activeDataSets.isEmpty()) - datasets.addAll(activeDataSets); - } - - selectionChanged(datasets); - } - - - /** - * Get all active datasets for a variable (and all of its dimensions) - * @param g ReadGraph - * @param variable Selected variable - * @return Active datasets for the selected variable - * @throws DatabaseException - */ - protected Collection loadAllActive(ReadGraph g, Variable variable) throws DatabaseException { - ArrayList dataSets = new ArrayList(); - - // Get variable's rvi and change it to modelica format - String rvi; - try { - rvi = Variables.getRVI(g, variable).replace("/", "."); - } catch (DatabaseException e) { - return dataSets; - } - - // Remove the first '.' - if(rvi.length() > 1) - rvi = rvi.substring(1); - - - HashMap rvis = VariableRVIUtils.getActiveRVIs(g, variable); - - Resource modelResource = Variables.getModel(g, variable); - SysdynModel model = getSysdynModel(g, modelResource); - - if(model == null) - return dataSets; - - // Finally, find all active datasets for the found rvis - Collection activeResults = model.getActiveResults(); - for(SysdynResult sysdynResult : activeResults) { - for(String currvi : rvis.keySet()) { - if(currvi != null && currvi.length() > 0) { - SysdynDataSet sds = sysdynResult.getDataSet(currvi.substring(1).replace("/", ".")); - if(sds != null) { - try { - sds.name = rvis.get(currvi).substring(1).replace("/", "."); - } catch (NullPointerException e) { - e.printStackTrace(); - } - dataSets.add(sds); - } + Variable dsVariable = v.browsePossible(graph, "#" + Functions.ACTIVE_DATASETS + "#"); + Object object = null; + if(dsVariable != null) + object = dsVariable.getValue(graph); + + if(object != null && object instanceof ArrayList) + for(Object o : (ArrayList)object) { + if(o instanceof SysdynDataSet) + datasets.add((SysdynDataSet)o); } - } } - return dataSets; + return datasets; } @@ -282,24 +212,13 @@ public abstract class SysdynDatasetSelectionListener implements ISelectionListen Resource resource = ModelingUtils.getPossibleElementCorrespondendence(g, element); if(resource == null || !g.isInstanceOf(resource, sr.Variable)) return null; String variableURI = g.getPossibleRelatedValue(runtime, dr.RuntimeDiagram_HasVariable); - try { - Variable compositeVariable = Variables.getVariable(g, variableURI); - return compositeVariable.browsePossible(g, resource); - } catch (MissingVariableException e) { - return null; + if(variableURI != null) { + try { + Variable compositeVariable = Variables.getVariable(g, variableURI); + return compositeVariable.browsePossible(g, resource); + } catch (MissingVariableException e) {} } - } - - /** - * Get SysdynModel representing the model resource - * @param g ReadGraph - * @param model Model resource - * @return SysdynModel representing model - * @throws DatabaseException - */ - private SysdynModel getSysdynModel(ReadGraph g, Resource model) throws DatabaseException { - Resource configuration = g.getPossibleObject(model, SimulationResource.getInstance(g).HasConfiguration); - return SysdynModelManager.getInstance(g.getSession()).getModel(g, configuration); + return null; } } diff --git a/org.simantics.sysdyn.ui/sysdyn.product b/org.simantics.sysdyn.ui/sysdyn.product index 1e756d0e..809df311 100644 --- a/org.simantics.sysdyn.ui/sysdyn.product +++ b/org.simantics.sysdyn.ui/sysdyn.product @@ -1,7 +1,8 @@ - + + @@ -26,6 +27,7 @@ + org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6 diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ActiveDatasetsIndexVariable.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ActiveDatasetsIndexVariable.java index 37ea8618..c8df2821 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ActiveDatasetsIndexVariable.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ActiveDatasetsIndexVariable.java @@ -1,6 +1,7 @@ package org.simantics.sysdyn.adapter; import java.util.ArrayList; +import java.util.Collection; import org.simantics.db.ReadGraph; import org.simantics.db.WriteGraph; @@ -19,19 +20,25 @@ public class ActiveDatasetsIndexVariable extends IndexVariable< ArrayList getValue() { - ArrayList result = new ArrayList(); - SysdynResult sr = model.getSysdynResult(); + ArrayList datasets = new ArrayList(); + + if(experiment == null) + return datasets; + + Collection results = experiment.getActiveResults(); ArrayList variableNamesWithIndexes = getVariableNamesWithIndexNumbers(); ArrayList variableNames = getVariableNames(); for(int i = 0; i < variableNamesWithIndexes.size(); i++) { - SysdynDataSet ds = sr.getDataSet(variableNamesWithIndexes.get(i)); - if(ds != null) { - ds.name = variableNames.get(i); - result.add(ds); - } + for(SysdynResult result : results) { + SysdynDataSet ds = result.getDataSet(variableNamesWithIndexes.get(i)); + if(ds != null) { + ds.name = variableNames.get(i); + datasets.add(ds); + } + } } - return result; + return datasets; } @Override diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/IndexVariable.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/IndexVariable.java index 747e3786..38a3e999 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/IndexVariable.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/IndexVariable.java @@ -46,7 +46,7 @@ public abstract class IndexVariable extends AbstractPropertyVariable { protected VariableSubscriptionManager getSubscriptionManager() { - return this.model; + return this.experiment; } public String getIndexes() { @@ -61,11 +61,13 @@ public abstract class IndexVariable extends AbstractPropertyVariable { * @return */ protected VariableValueSubscription registerSubscription(ExternalRead request, Listener procedure) { - // Other properties are requested from model (they listen to new simulation results) - VariableValueSubscription subscription = new VariableValueSubscription(request, this, procedure); - subscriptionManager.addVariableValueSubscription(subscription); - subscription.update(); - return subscription; + // Other properties are requested from model (they listen to new simulation results) + VariableValueSubscription subscription = new VariableValueSubscription(request, this, procedure); + if(subscriptionManager != null) { + subscriptionManager.addVariableValueSubscription(subscription); + } + subscription.update(); + return subscription; } /** @@ -74,7 +76,8 @@ public abstract class IndexVariable extends AbstractPropertyVariable { */ protected void unregisterSubscription(VariableValueSubscription subscription) { subscription.setListener(null); - subscriptionManager.removeVariableValueSubscription(subscription); + if(subscriptionManager != null) + subscriptionManager.removeVariableValueSubscription(subscription); } @@ -168,14 +171,12 @@ public abstract class IndexVariable extends AbstractPropertyVariable { model = SysdynModelManager.getInstance(graph.getSession()).getModel(graph, configuration); } - System.out.println(parent.getName(graph)); Variable var = parent.getParent(graph); Resource represents = var.getRepresents(graph); Resource experiment = null; while(represents != null && !graph.isInstanceOf(represents, MOD.StructuralModel)) { - System.out.println(var.getName(graph)); - if(graph.isInstanceOf(represents, SIMU.Experiment)) { + if(graph.isInstanceOf(represents, SIMU.Experiment)) { experiment = represents; break; } @@ -184,8 +185,8 @@ public abstract class IndexVariable extends AbstractPropertyVariable { represents = var.getRepresents(graph); } - if(experiment != null) { - IProject project = Simantics.peekProject(); + IProject project = Simantics.peekProject(); + if(experiment != null && project != null) { IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); IExperiment e = expMan.getExperiment(NameUtils.getSafeName(graph, experiment)); if(e instanceof SysdynExperiment) diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/TimeIndexVariable.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/TimeIndexVariable.java index f4227bfa..94e5eebd 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/TimeIndexVariable.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/TimeIndexVariable.java @@ -1,6 +1,7 @@ package org.simantics.sysdyn.adapter; import java.util.ArrayList; +import java.util.Collection; import org.simantics.db.ReadGraph; import org.simantics.db.WriteGraph; @@ -18,19 +19,24 @@ public class TimeIndexVariable extends IndexVariable { @Override public double[] getValue() { - SysdynResult sr = model.getSysdynResult(); - ArrayList variableNames = getVariableNamesWithIndexNumbers(); - - double[] result = new double[variableNames.size()]; - for(int i = 0; i < variableNames.size(); i++) { - SysdynDataSet ds = sr.getDataSet(variableNames.get(i)); - if(ds != null && ds.times != null && ds.times.length > 0) { - result[i] = ds.times[ds.times.length-1]; - } else { - result[i] = 0; - } - } - return result; + if(experiment == null) + return new double[0]; + + Collection results = experiment.getActiveResults(); + ArrayList variableNames = getVariableNamesWithIndexNumbers(); + + double[] result = new double[variableNames.size()]; + for(int i = 0; i < variableNames.size(); i++) { + for(SysdynResult r : results) { + SysdynDataSet ds = r.getDataSet(variableNames.get(i)); + if(ds != null && ds.times != null && ds.times.length > 0) { + result[i] = ds.times[ds.times.length-1]; + } else { + result[i] = 0; + } + } + } + return result; } @Override diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/TimesIndexVariable.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/TimesIndexVariable.java index d9b6f6ce..1076ad74 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/TimesIndexVariable.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/TimesIndexVariable.java @@ -1,6 +1,7 @@ package org.simantics.sysdyn.adapter; import java.util.ArrayList; +import java.util.Collection; import org.simantics.db.ReadGraph; import org.simantics.db.WriteGraph; @@ -19,21 +20,26 @@ public class TimesIndexVariable extends IndexVariable { @Override public double[][] getValue() { - SysdynResult sr = model.getSysdynResult(); - ArrayList variableNames = getVariableNamesWithIndexNumbers(); - - double[][] result = new double[variableNames.size()][]; - for(int i = 0; i < variableNames.size(); i++) { - SysdynDataSet ds = sr.getDataSet(variableNames.get(i)); - if(ds != null && ds.times != null) { - result[i] = new double[ds.times.length]; - for(int j = 0; j < ds.times.length; j++) { - result[i][j] = ds.times[j]; - } - } else { - result[i] = new double[0]; - } - } + if(experiment == null) + return new double[0][0]; + + Collection results = experiment.getActiveResults(); + ArrayList variableNames = getVariableNamesWithIndexNumbers(); + + double[][] result = new double[variableNames.size()][]; + for(int i = 0; i < variableNames.size(); i++) { + for(SysdynResult r : results) { + SysdynDataSet ds = r.getDataSet(variableNames.get(i)); + if(ds != null && ds.times != null) { + result[i] = new double[ds.times.length]; + for(int j = 0; j < ds.times.length; j++) { + result[i][j] = ds.times[j]; + } + } else { + result[i] = new double[0]; + } + } + } return result; } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValueIndexVariable.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValueIndexVariable.java index 3ad80df4..558f086d 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValueIndexVariable.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValueIndexVariable.java @@ -1,6 +1,7 @@ package org.simantics.sysdyn.adapter; import java.util.ArrayList; +import java.util.Collection; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; @@ -10,6 +11,7 @@ import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variable; 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.sysdyn.manager.SysdynDataSet; import org.simantics.sysdyn.manager.SysdynGameExperiment; @@ -19,37 +21,46 @@ public class ValueIndexVariable extends IndexVariable { public ValueIndexVariable(ReadGraph graph, Variable parent, String indexes) throws DatabaseException { - super(graph, parent, indexes); + super(graph, parent, indexes); } @Override public double[] getValue() { - FMUControlJNI control = null; - if(experiment instanceof SysdynGameExperiment) { - control = ((SysdynGameExperiment)this.experiment).getFMUControl(); + if(experiment == null) + return new double[0]; + + FMUControlJNI control = null; + if(experiment instanceof SysdynGameExperiment) { + SysdynGameExperiment exp = (SysdynGameExperiment)experiment; + ExperimentState state = exp.getSysdynExperimentState(); + // Get value from control only if the simulation is running or stopped, not before initialization + if(ExperimentState.RUNNING.equals(state) || ExperimentState.STOPPED.equals(state)) + control = ((SysdynGameExperiment)this.experiment).getFMUControl(); } - - SysdynResult sr = model.getSysdynResult(); - ArrayList variableNames = getVariableNamesWithIndexNumbers(); - - double[] result = new double[variableNames.size()]; - for(int i = 0; i < variableNames.size(); i++) { - if(control != null) { - try { - result[i] = control.getRealValue(variableNames.get(i)); - } catch (FMUJNIException e) { - result[i] = 0; - } - } else { - SysdynDataSet ds = sr.getDataSet(variableNames.get(i)); - if(ds != null && ds.values != null && ds.values.length > 0) { - result[i] = ds.values[ds.values.length-1]; - } else { - result[i] = 0; - } - } - } - return result; + + Collection results = experiment.getActiveResults(); + ArrayList variableNames = getVariableNamesWithIndexNumbers(); + + double[] result = new double[variableNames.size()]; + for(int i = 0; i < variableNames.size(); i++) { + for(SysdynResult r : results) { + if(control != null) { + try { + result[i] = control.getRealValue(variableNames.get(i)); + } catch (FMUJNIException e) { + result[i] = 0; + } + } else { + SysdynDataSet ds = r.getDataSet(variableNames.get(i)); + if(ds != null && ds.values != null && ds.values.length > 0) { + result[i] = ds.values[ds.values.length-1]; + } else { + result[i] = 0; + } + } + } + } + return result; } @Override @@ -65,9 +76,16 @@ public class ValueIndexVariable extends IndexVariable { FMUControlJNI control = null; if(experiment instanceof SysdynGameExperiment) { // Support only game experiments for now.. - control = ((SysdynGameExperiment)this.experiment).getFMUControl(); - if(control == null) - return; + + SysdynGameExperiment exp = (SysdynGameExperiment)experiment; + ExperimentState state = exp.getSysdynExperimentState(); + // Set value to control only if the simulation is running or stopped, not before initialization + if(!(ExperimentState.RUNNING.equals(state) || ExperimentState.STOPPED.equals(state))) + return; + + control = ((SysdynGameExperiment)this.experiment).getFMUControl(); + if(control == null) + return; diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValuesIndexVariable.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValuesIndexVariable.java index 7fe4bd1c..9485369f 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValuesIndexVariable.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValuesIndexVariable.java @@ -1,6 +1,7 @@ package org.simantics.sysdyn.adapter; import java.util.ArrayList; +import java.util.Collection; import org.simantics.db.ReadGraph; import org.simantics.db.WriteGraph; @@ -18,22 +19,24 @@ public class ValuesIndexVariable extends IndexVariable { @Override public double[][] getValue() { - SysdynResult sr = model.getSysdynResult(); + Collection results = experiment.getActiveResults(); ArrayList variableNames = getVariableNamesWithIndexNumbers(); - + double[][] result = new double[variableNames.size()][]; for(int i = 0; i < variableNames.size(); i++) { - SysdynDataSet ds = sr.getDataSet(variableNames.get(i)); - if(ds != null && ds.values != null) { - result[i] = new double[ds.values.length]; - for(int j = 0; j < ds.values.length; j++) { - result[i][j] = ds.values[j]; - } - } else { - result[i] = new double[0]; - } + for(SysdynResult r : results) { + SysdynDataSet ds = r.getDataSet(variableNames.get(i)); + if(ds != null && ds.values != null) { + result[i] = new double[ds.values.length]; + for(int j = 0; j < ds.values.length; j++) { + result[i][j] = ds.values[j]; + } + } else { + result[i] = new double[0]; + } + } } - return result; + return result; } @Override 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 03432319..30d161ee 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java @@ -18,6 +18,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -73,6 +75,9 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, protected String previousModelStructure; protected Process process; protected boolean canceled = false; + protected ExperimentState sysdynExperimentState; + + private SysdynResult result; public static SysdynExperiment INSTANCE; @@ -85,6 +90,19 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, return INSTANCE; } + public SysdynResult getCurrentResult() { + if(this.result == null) + this.result = new SysdynResult(); + 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 @@ -106,12 +124,12 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, } }); - setStateToDatabase(ExperimentState.INITIALIZING); + setSysdynExperimentState(ExperimentState.INITIALIZING); } @Override public void saveState() { - if(sysdynModel.getSysdynResult() == null) return; + if(result == null) return; try { session.syncRequest(new WriteRequest() { @@ -137,7 +155,7 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, l0.PartOf, model, sr.Result_resultFile, file.getAbsolutePath()); graph.claim(experiment, sr.Experiment_result, res); - sysdynModel.getSysdynResult().saveToFile(file); + result.saveToFile(file); } }); } catch (DatabaseException e) { @@ -177,13 +195,14 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, /** * 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) { + protected String getModelicaCode(IModelicaMonitor monitor, boolean isGame) { String modelText = null; try { // Write all configurations once - modelText = ModelicaWriter.write(sysdynModel.getModules()); + modelText = ModelicaWriter.write(sysdynModel.getModules(), isGame); } catch (Exception e) { // Stop experiment and show console /*setExperimentStopped(experiment); =>*/ simulate(false); @@ -315,9 +334,9 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, result.read(simulationLocation.outputFile, outIntervalInt); result.readInits(simulationLocation.initFile); result.filter(); - sysdynModel.getSysdynResult().setResult(result); + getCurrentResult().setResult(result); progressMonitor.worked(1); - sysdynModel.resultChanged(); + resultsChanged(); simulate(false); @@ -400,7 +419,7 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, progressMonitor.subTask("Write modelica classes"); // Write Modelica files - String modelText = getModelicaCode(monitor); + String modelText = getModelicaCode(monitor, false); if(modelText == null) return; @@ -570,16 +589,28 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, } protected void localStateChange() { - setStateToDatabase(getState()); - switch(state) { - case DISPOSED: - onExperimentDisposed(); - break; - } + setSysdynExperimentState(getState()); + switch(state) { + case DISPOSED: + onExperimentDisposed(); + break; + default: + break; + } } - protected void setStateToDatabase(final ExperimentState state) { + /** + * 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 @@ -592,6 +623,8 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, 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: @@ -609,6 +642,7 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, } graph.claim(model, SR.HasExperimentState, st); + graph.claim(experiment, SR.HasExperimentState, st); }}); } }); @@ -721,7 +755,7 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, /** * Modified copy from AprosExperiment */ - public void fireValuesChanged() { + public void resultsChanged() { long time = System.nanoTime(); if(time - previousVariableUpdateTime > 100000000) { updateSubscriptions(); 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 a65beafa..2cb85d4c 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java @@ -155,7 +155,7 @@ public class SysdynGameExperiment extends SysdynExperiment { progressMonitor.subTask("Write modelica classes"); // Write Modelica files - String modelText = getModelicaCode(monitor); + String modelText = getModelicaCode(monitor, true); if(modelText == null) return; @@ -207,8 +207,8 @@ public class SysdynGameExperiment extends SysdynExperiment { results.get(subscription[k]).add(initialValues[k]); } - sysdynModel.getSysdynResult().setResult(new GameResult(this.results, this.subscription)); - sysdynModel.resultChanged(); + getCurrentResult().setResult(new GameResult(this.results, this.subscription)); + resultsChanged(); } catch (FMUJNIException e) { System.err.println("SysdynGameExperiment initialization failed:\n\t" + e.getMessage()); @@ -288,10 +288,10 @@ public class SysdynGameExperiment extends SysdynExperiment { } monitor.subTask("Display results"); - sysdynModel.getSysdynResult().setResult(new GameResult(SysdynGameExperiment.this.results, SysdynGameExperiment.this.subscription)); + getCurrentResult().setResult(new GameResult(SysdynGameExperiment.this.results, SysdynGameExperiment.this.subscription)); monitor.worked(1); - sysdynModel.resultChanged(); + resultsChanged(); monitor.worked(1); changeState(ExperimentState.STOPPED); 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 40125cb0..a52351f8 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java @@ -24,6 +24,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; +import org.simantics.Simantics; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; @@ -36,16 +37,17 @@ import org.simantics.db.procedure.Listener; import org.simantics.db.request.Read; import org.simantics.db.service.VirtualGraphSupport; import org.simantics.layer0.Layer0; -import org.simantics.modelica.data.SimulationResult; import org.simantics.objmap.IMapping; import org.simantics.objmap.IMappingListener; 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; import org.simantics.simulation.project.ExperimentRuns; import org.simantics.simulation.project.IExperimentActivationListener; +import org.simantics.simulation.project.IExperimentManager; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.sysdyn.Activator; import org.simantics.sysdyn.SysdynResource; @@ -76,15 +78,12 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti private Set modules = new HashSet(); - private SysdynResult sysdynResult; - private ArrayList activeResults; + private ArrayList displayedResults; private ArrayList listeningHistories = new ArrayList(); private CopyOnWriteArrayList modificationListeners = new CopyOnWriteArrayList(); - private CopyOnWriteArrayList resultListeners = - new CopyOnWriteArrayList(); - + @SuppressWarnings("rawtypes") protected THashSet variableValueSubscriptions = new THashSet(); @SuppressWarnings("rawtypes") @@ -167,14 +166,10 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti e.printStackTrace(); } - // initialize results - sysdynResult = new SysdynResult(); - sysdynResult.setResult(new SimulationResult()); - g.asyncRequest(new Read> () { @Override public ArrayList perform(ReadGraph graph) throws DatabaseException { - ArrayList activeResults = new ArrayList(); + ArrayList displayedResults = new ArrayList(); // TODO: this can be done automatically with a listener for(HistoryDatasetResult hs : listeningHistories) @@ -206,7 +201,7 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti } if(sysdynResult != null) - activeResults.add(sysdynResult); + displayedResults.add(sysdynResult); } } @@ -215,7 +210,7 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti e.printStackTrace(); } - return activeResults; + return displayedResults; } }, new Listener> () { @@ -223,10 +218,7 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti @Override public void execute(ArrayList result) { // Add the current result if there is one - if(result != null && getSysdynResult() != null) - result.add(0, getSysdynResult() ); - - activeResults = result; + displayedResults = result; resultChanged(); } @@ -311,33 +303,18 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti }); } - public SysdynResult getSysdynResult() { - return sysdynResult; - } - - public void addResultListener(Runnable listener) { - synchronized(resultListeners) { - resultListeners.add(listener); - } - } - - public void removeResultListener(Runnable listener) { - synchronized(resultListeners) { - resultListeners.remove(listener); - } - } - /** * Fires an update to all result listeners and subscriptions * after results have changed */ public void resultChanged() { - synchronized(resultListeners) { - for(Runnable listener : resultListeners) { - listener.run(); - } + IProject project = Simantics.peekProject(); + IExperimentManager manager = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment active = manager.getActiveExperiment(); + if(active != null && active instanceof SysdynExperiment) { + ((SysdynExperiment)active).resultsChanged(); } - + updateSubscriptions(); } @@ -449,11 +426,11 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti * @param graph ReadGraph * @return all active SysdynResults (last update with getAndUpdateActiveResults()) */ - public Collection getActiveResults() { - if(activeResults == null) + public Collection getDisplayedResults() { + if(displayedResults == null) return new ArrayList(); else - return activeResults; + return displayedResults; } /** 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 9e92d760..29102b9c 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java @@ -77,7 +77,7 @@ public class SysdynPlaybackExperiment extends SysdynExperiment implements IDynam private void setTime(double time) { this.time = time; - fireValuesChanged(); + resultsChanged(); } public double getTime() { @@ -275,11 +275,11 @@ public class SysdynPlaybackExperiment extends SysdynExperiment implements IDynam } @Override - public void fireValuesChanged() { + public void resultsChanged() { for(Runnable listener : timeListeners) { listener.run(); } - super.fireValuesChanged(); + super.resultsChanged(); } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java index ea24ec70..b144738e 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java @@ -26,7 +26,6 @@ import org.simantics.sysdyn.representation.Module; import org.simantics.sysdyn.representation.ModuleType; import org.simantics.sysdyn.representation.Stock; import org.simantics.sysdyn.representation.Variable; -import org.simantics.sysdyn.representation.utils.RepresentationUtils; /** * ModelicaWriter writes Sysdyn model representations (objmap) into Modelica code. @@ -38,11 +37,12 @@ public class ModelicaWriter { /** * Write a collection of configurations into a single Modelica code + * @param isGame * * @param Configurations Configurations, one main configuration and possible modules * @return Complete Modelica code of a model */ - public static String write(Collection configurations) { + public static String write(Collection configurations, boolean isGame) { StringBuilder b = new StringBuilder(); // Super class for enumerations @@ -51,8 +51,10 @@ public class ModelicaWriter { b.append(" parameter Integer elements[:];\n"); b.append("end Enumeration_class;\n\n"); - for(Configuration conf : configurations) + for(Configuration conf : configurations) { + conf.setIsGameConfiguration(isGame); writeConfiguration(conf, "SpreadSheetBook", b); + } b.append(getGlobalSpreadSheets(configurations)); @@ -86,8 +88,6 @@ public class ModelicaWriter { private static void writeConfiguration(Configuration configuration, String spreadSheetClass, StringBuilder b) { String app; - boolean game = RepresentationUtils.isGameExperimentActive(); - // Lists for storing different configuration elements ArrayList variables = new ArrayList(); ArrayList inputs = new ArrayList(); @@ -159,7 +159,7 @@ public class ModelicaWriter { // Time variable for FMU (game) simulations - if(game) { + if(configuration.isGameConfiguration()) { if(configuration.getModel() != null) // Parameter for model root. Values changed in FMU simulator b.append(" parameter Real time = 0;\n"); @@ -230,7 +230,7 @@ public class ModelicaWriter { } } - if(game && !modules.isEmpty()) { + if(configuration.isGameConfiguration() && !modules.isEmpty()) { b.append("// Time values for module\n"); for(Module m : modules) { b.append(" " + m.getName() + ".time = time;\n"); diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Configuration.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Configuration.java index 00d0efb3..e5d8d053 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Configuration.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Configuration.java @@ -54,6 +54,15 @@ public class Configuration { composition = true) private ArrayList elements = new ArrayList(); + private boolean isGameConfiguration = false; + + public void setIsGameConfiguration(boolean isGame) { + this.isGameConfiguration = isGame; + } + + public boolean isGameConfiguration() { + return this.isGameConfiguration; + } /** * Get all elements of this configuration. Also all sheets from books are included. diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Module.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Module.java index 902a385c..699085c6 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Module.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Module.java @@ -226,7 +226,7 @@ public class Module implements IElement { public String getParameterOverrideString() { String result = ""; - if(RepresentationUtils.isGameExperimentActive()) { + if(RepresentationUtils.isPartOfGameExperiment(this)) { for(ParameterOverride po : getParameterOverrides()) { IndependentVariable var = po.getVariable(); if(!Variability.CONTINUOUS.equals(Variability.getVariability(var, false, parentConfiguration))) { diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Variability.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Variability.java index e12969f8..27504514 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Variability.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Variability.java @@ -156,7 +156,7 @@ public enum Variability { * @return Variabilty of a variable */ static public Variability getVariability(IndependentVariable variable) { - if(RepresentationUtils.isGameExperimentActive() && !(variable instanceof Stock)) { + if(RepresentationUtils.isPartOfGameExperiment(variable) && !(variable instanceof Stock)) { /* * Game experiments cannot use as many parameter variables as normal experiments. diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/FormatUtils.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/FormatUtils.java index 41fd95e5..70d43a56 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/FormatUtils.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/FormatUtils.java @@ -64,7 +64,7 @@ public class FormatUtils { private static String addGameExperimentAdditions(Variable variable, String expression) { if(variable == null || !(variable instanceof IndependentVariable)) return expression; - if(!RepresentationUtils.isGameExperimentActive()) + if(!RepresentationUtils.isPartOfGameExperiment(variable)) return expression; if(Variability.getVariability((IndependentVariable)variable).equals(Variability.CONTINUOUS)) { @@ -72,12 +72,19 @@ public class FormatUtils { if(reference != null) { String condition; + boolean array = reference.getArrayIndexes() != null && + reference.getArrayIndexes().getEnumerations() != null && + !reference.getArrayIndexes().getEnumerations().isEmpty(); + + String refName = reference.getName(); if(reference.getType().equals("Boolean")) { - condition= "if initial() or " + reference.getName() + " or not " + - reference.getName() + " then ("; + condition= "if initial() or " + refName + " or not " + + refName + " then ("; } else { - condition= "if initial() or " + reference.getName() + " < 0 or " + - reference.getName() + " >= 0 then ("; + if(array) + refName = "sum(" + refName + ")"; + condition= "if initial() or " + refName + " < 0 or " + + refName + " >= 0 then ("; } String conditionEnd = ") else pre(" + variable.getName() +")"; diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/RepresentationUtils.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/RepresentationUtils.java index dd460ae0..f6da9d93 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/RepresentationUtils.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/RepresentationUtils.java @@ -26,9 +26,8 @@ import org.simantics.sysdyn.representation.IElement; import org.simantics.sysdyn.representation.IndependentVariable; import org.simantics.sysdyn.representation.Module; import org.simantics.sysdyn.representation.Stock; +import org.simantics.sysdyn.representation.Variability; import org.simantics.sysdyn.representation.Variable; -import org.simantics.sysdyn.representation.expressions.IExpression; -import org.simantics.sysdyn.representation.expressions.ParameterExpression; public class RepresentationUtils { @@ -54,6 +53,34 @@ public class RepresentationUtils { return false; } + /** + * Find out if a variable is part of a game configuration. (This means that the variable is a + * part of a game experiment) + * @param variable + * @return + */ + public static boolean isPartOfGameExperiment(Variable variable) { + Configuration conf = variable.getParentConfiguration(); + if(conf != null) + return conf.isGameConfiguration(); + else + return false; + } + + /** + * Find out if a module is part of a game configuration. (This means that the module is a + * part of a game experiment) + * @param variable + * @return + */ + public static boolean isPartOfGameExperiment(Module module) { + Configuration conf = module.getParentConfiguration(); + if(conf != null) + return conf.isGameConfiguration(); + else + return false; + } + /** * Retrieves the first reference to a game variable (parameter variable) in the given @@ -111,6 +138,13 @@ public class RepresentationUtils { if(v.getName().equals(variable.getName())) { return null;// Reference to self. } else { + if(Variability.PARAMETER.equals(Variability.getVariability(v, false, null))) { + return v; + } else { + return null; + } + + /* if(v.getExpressions() == null || v.getExpressions().getExpressions().size() > 1) return null; @@ -118,7 +152,7 @@ public class RepresentationUtils { if(e instanceof ParameterExpression) return v; - + */ } } } -- 2.47.1