From 073e84913268160550622f0587e8042000168f43 Mon Sep 17 00:00:00 2001 From: lempinen Date: Wed, 12 Oct 2011 11:39:46 +0000 Subject: [PATCH] First functional prototype for the simulation playback feature: Separate experiment type for playback experiments and a profile to show changes in variables git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@22681 ac1ea38d-2e2b-0410-8846-a27921b304fc --- org.simantics.sysdyn.ontology/graph.tg | Bin 69394 -> 69438 bytes .../graph/Sysdyn.pgraph | 2 + .../org/simantics/sysdyn/SysdynResource.java | 3 + org.simantics.sysdyn.ui/plugin.xml | 47 +++++ .../profiles/SimulationPlaybackStyle.java | 184 ++++++++++-------- .../ui/handlers/NewExperimentNodeHandler.java | 15 +- .../NewPlaybackExperimentNodeHandler.java | 17 ++ .../SysdynExperimentManagerListener.java | 10 +- .../ui/menu/PlaybackSliderContribution.java | 98 ++++++++++ .../simantics/sysdyn/ui/utils/ModelUtils.java | 2 +- .../sysdyn/ui/utils/ProfileEntries.java | 2 +- .../ui/validation/DependencyFunction.java | 6 - .../sysdyn/adapter/HistoryVariable.java | 63 +++++- .../sysdyn/adapter/PropertyProvider.java | 10 + .../adapter/VariableValueSubscription.java | 103 ++++++++++ .../sysdyn/manager/SysdynExperiment.java | 103 ++++++++-- .../simantics/sysdyn/manager/SysdynModel.java | 17 +- .../manager/SysdynPlaybackExperiment.java | 50 +++++ .../sysdyn/manager/SysdynResult.java | 4 +- 19 files changed, 622 insertions(+), 114 deletions(-) create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewPlaybackExperimentNodeHandler.java create mode 100644 org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/menu/PlaybackSliderContribution.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/PropertyProvider.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/VariableValueSubscription.java create mode 100644 org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java diff --git a/org.simantics.sysdyn.ontology/graph.tg b/org.simantics.sysdyn.ontology/graph.tg index 11db7b9ecb1886238ea91dd3e64d258ac166866d..ecd1bcebcac4fc74b0b874d50d5dcf47ba90f0a5 100644 GIT binary patch literal 69438 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

7H_-YcQaqyWPJdC-tftb zaHK1_k5nr)yo$#3a641T#J5ZFaA7{iX^UG|)ymG%&;{BO*J;h(&!HBJc4ut6X$#N$ zKKd{p_(#i^l@?0BEh;o0;}tO3hk0mmuc%$F9I)N=a6R6zKtzbnqMxbc3S;0R$x0eSo{MdGJguq@fRyfH= zDx--P;>AK`BpZodWkxF(o|lP80}q}e>08P={_zfrGY%w|w}M#@fWA1TR5R0&o5Db` zRxH>q8EdY0t)yw9jkOpXGh{Q2eRtNEvoB-b+dZZrM@~IIn=^@VteW}2hAj9nRc{zO zK_*0)YOLWO$l*b@A8(0pa2oMnj&Nbswqr6EO8f#K6J+m^^}=ZF!rk~?OksEPF~=?( zLt(7>n57Gmif0VgGr~VSPAUZXFvOG^4-@w?l)4w};6yccpYSr;-16 z_N0G*R|)Idjg54j*_>9R;S0wWxizq;&?3iiG#EE_JLuXS@&HlWSy?>5_mKQKDxM=` zrNZT(xGuaP>ZgD6F~J|?w%}X5CgvvpRMLS5{EGu8?0?5~^NqIvF#43$_YAD`9$W!T!OboAZ+yOkR){@pYC+yE$7oh<=!O@^3lqKlhw*j-JT= z&$uR?9DeU2|M<^@M)|1@EWf}tp|O`Qa8dfPpcR9au>q96k88^0Wn;U_gJn5Y$UoXK zq4BKZ;0_+vK8Y*kbml9o>C@aDdeiP9ywF6&i)qCrf77oqU&E_T06u><=6Mf60S6WP z)vWv-uwcafyUyg}OR)3+OlU0ObifBBj^d=A1^BP~(~S@FeQ$#I<;j90%&(D0%R_jE z$M2Ar@JGpOin~kIrp0*R1&`OWa5wE99oRkWxi}yvogMfgQ-67Dx#ZqB<4jk<`(?ta z|G^U=f zV*flB*QAN7221WOKL26mgkPKGrMvUn@y%|&RxA(ZswJG|<=IE4x+JuS*r;{1InXGG=3a^#8<@LEn z%#g|{z4GR!zqFpuG#1T+L40R%!ny3?z{CSqX9zFJD@P$0aUP8Mnr1QLP)NN$7EL1kVi= zYeWS#+P}}%pX~3v@9zmH`#-r(6b`}_&*w&bS;A+79KJtqcm#yQa2AgepeZ_5Lx^A1XY+$H7+&g-f`|Aj( zcilD1*RQVhkB#!70+wePRq4$%yEdjWl__)GdRb8!9!83|P5Q|#V?HG`c|Re~MCWsr z;EP6NB^&Jl!NB!o3^H8lj7@kZ?w2pw{IZ=)he@-cv{%gW=H8*C$8&GCRA%R1X64D! zOrwc-5WQy1=^e#(S047!D^*#ybHp||RD!v`R83n}E%{p6Wn?Fq!St8m{I}CO@J7M? zZ+}1C=6SrI$8$ZN?eQF7at`vCQ^PHkeldI0$+*NXq_$HLyT7iX}PTePP0|LJk#|K8z31|gml z?wGQvkh`0xnJ@v{DFvK)u74cET^m5eicK$kx}cjX#g`Tqj# C`{b(t diff --git a/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph b/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph index 8592edaf..7974a94b 100644 --- a/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph +++ b/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph @@ -350,6 +350,8 @@ SYSDYN.GameExperiment + + @@ -266,6 +270,25 @@ + + + + + + + + + + + + @@ -335,6 +358,22 @@ + + + + + + + + + + @@ -1015,6 +1058,10 @@ class="org.simantics.sysdyn.ui.handlers.NewModelHandler" commandId="org.simantics.sysdyn.ui.newModel"> + + diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/profiles/SimulationPlaybackStyle.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/profiles/SimulationPlaybackStyle.java index 26aa3682..1dcf494e 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/profiles/SimulationPlaybackStyle.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements2/profiles/SimulationPlaybackStyle.java @@ -1,97 +1,122 @@ package org.simantics.sysdyn.ui.elements2.profiles; -import java.awt.BasicStroke; import java.awt.Color; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; +import java.util.HashMap; +import org.simantics.databoard.Bindings; +import org.simantics.databoard.accessor.ArrayAccessor; +import org.simantics.databoard.accessor.RecordAccessor; +import org.simantics.databoard.type.Datatype; +import org.simantics.databoard.type.DoubleType; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; -import org.simantics.db.common.request.ObjectsWithType; -import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.layer0.variable.Variables; +import org.simantics.diagram.elements.TextNode; import org.simantics.diagram.profile.StyleBase; -import org.simantics.diagram.stubs.G2DResource; -import org.simantics.diagram.synchronization.graph.DiagramGraphUtil; -import org.simantics.issues.ontology.IssueResource; -import org.simantics.layer0.Layer0; +import org.simantics.diagram.stubs.DiagramResource; import org.simantics.modeling.ModelingResources; +import org.simantics.project.IProject; import org.simantics.scenegraph.INode; -import org.simantics.scenegraph.g2d.nodes.ShapeNode; +import org.simantics.scenegraph.g2d.nodes.SingleElementNode; import org.simantics.scenegraph.profile.EvaluationContext; import org.simantics.scenegraph.profile.Observer; -import org.simantics.scenegraph.profile.common.ProfileVariables; -import org.simantics.scenegraph.utils.GeometryUtils; import org.simantics.scenegraph.utils.NodeUtil; -import org.simantics.sysdyn.SysdynResource; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.sysdyn.manager.SysdynPlaybackExperiment; +import org.simantics.ui.SimanticsUI; -public class SimulationPlaybackStyle extends StyleBase { - - public static class A extends ShapeNode { - - private static final long serialVersionUID = -5273246617906214956L; - - @Override - public Rectangle2D getBoundsInLocal() { - return null; - } - - @Override - public Rectangle2D getBoundsInLocal(boolean b) { - return null; - } - - @Override - public Rectangle2D getBounds() { - return null; - } - - } +public class SimulationPlaybackStyle extends StyleBase { + HashMap timeListeners = new HashMap(); + @Override - public AffineTransform calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException { -// TODO: Get results from variable -// DiagramResource dr = DiagramResource.getInstance(graph); -// String rvi = graph.getPossibleRelatedValue(runtimeDiagram, dr.RuntimeDiagram_HasRVI, Bindings.STRING); + public Double calculateStyle(ReadGraph graph, Resource runtimeDiagram, Resource entry, Resource element, Variable configuration) throws DatabaseException { - Layer0 l0 = Layer0.getInstance(graph); - SysdynResource sr = SysdynResource.getInstance(graph); - ModelingResources mr = ModelingResources.getInstance(graph); - IssueResource issue = IssueResource.getInstance(graph); + IProject project = SimanticsUI.getProject(); + IExperimentManager em = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment experiment = em.getActiveExperiment(); + if(!(experiment instanceof SysdynPlaybackExperiment)) + return null; + ModelingResources mr = ModelingResources.getInstance(graph); + DiagramResource dr = DiagramResource.getInstance(graph); + Resource component = graph.getPossibleObject(element, mr.ElementToComponent); if (component == null) return null; - - Resource config = graph.getPossibleObject(component, l0.PartOf); - - Resource model = graph.getPossibleObject(config, l0.PartOf); - if(!graph.isInstanceOf(model, sr.SysdynModel)) - return null; - - for(Resource i : graph.syncRequest(new ObjectsWithType(model, l0.ConsistsOf, issue.Issue))) { - System.out.println(NameUtils.getSafeName(graph, graph.getSingleObject(i, issue.HasIssueContext))); - if(graph.getSingleObject(i, issue.HasIssueContext).equals(component)) { - AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, element, G2DResource.getInstance(graph).HasTransform, true); - return at; + + try { + + String dv = graph.getPossibleRelatedValue(runtimeDiagram, dr.RuntimeDiagram_HasVariable); + Variable rootVariable = graph.getPossibleAdapter(graph.getRootLibrary(), Variable.class); + if (rootVariable == null) + return null; + Variable diagramVariable = rootVariable.browsePossible(graph, dv.substring(6)); + if(diagramVariable == null) + return null; + + Variable var = diagramVariable.browsePossible(graph, component); + if(var == null) + return null; + + Double time = var.getPossiblePropertyValue(graph, Variables.DISPLAY_VALUE, Bindings.DOUBLE); + if(time == null) + return null; + + + final RecordAccessor acc = var.getInterface(graph, RecordAccessor.class); + if(acc == null) + return null; + + + ArrayAccessor timeAccessor, valueAccessor; + timeAccessor = acc.getFieldAccessor(1); + valueAccessor = acc.getFieldAccessor(2); + Datatype dt = new org.simantics.databoard.type.ArrayType(new DoubleType()); + + double[] ta = (double[]) timeAccessor.getValue(Bindings.getBinding(dt)); + double[] va = (double[]) valueAccessor.getValue(Bindings.getBinding(dt)); + if(va.length == 0 || va.length == 2) + return null; + + double min = va[0], max = va[0]; + for(double d : va) { + if(d < min) + min = d; + if(d > max) + max = d; + } + + int index = 0; + if(ta[ta.length - 1] - time > ta[ta.length / 2] ) { + index = ta.length - 1; + while(ta[index] > time) + index--; + } else { + while(ta[index] < time) + index++; } + + double value = va[index]; + + double multiplier = (value - min) / (max - min); + +// AffineTransform at = (AffineTransform) DiagramGraphUtil.getAffineTransform(graph, element, G2DResource.getInstance(graph).HasTransform, true).clone(); +// at.translate(0, 10); + return multiplier; + + } catch(Exception ignore) { + System.err.println("POIKKEUS SimulationPlaybackStyle"); + ignore.printStackTrace(); } - return null; -// String name = graph.getPossibleRelatedValue(config, l0.HasName, Bindings.STRING); -// if(name == null) -// return null; -// if(name.startsWith("A")) { -// AffineTransform at = DiagramGraphUtil.getAffineTransform(graph, element, G2DResource.getInstance(graph).HasTransform, true); -// return at; -// } else { -// return null; -// } } @Override - public void styleResultChanged(Observer observer, Resource element, AffineTransform result) { + public void styleResultChanged(Observer observer, Resource element, Double result) { if (result != null) values.put(element, result); else @@ -100,19 +125,13 @@ public class SimulationPlaybackStyle extends StyleBase { } @Override - public void applyStyleForNode(EvaluationContext observer, INode _node, AffineTransform transform) { - if (transform != null) { - A node = ProfileVariables.claimChild(_node, "", "simulationPlaybackColour", A.class, observer); - if (node == null) - return; - - Rectangle2D expandedElementBounds = GeometryUtils.expandRectangle( NodeUtil.getLocalElementBounds(_node), 0.5 ); - node.setTransform(transform); - node.setZIndex(-1000); - node.setFill(true); - node.setColor(Color.LIGHT_GRAY); - node.setStroke(new BasicStroke(0.2f)); - node.setValue("shape", expandedElementBounds); + public void applyStyleForNode(EvaluationContext observer, INode _node, Double multiplier) { + if (multiplier != null) { + TextNode n = NodeUtil.getNearestChildByClass((SingleElementNode)_node, TextNode.class); + Color c = new Color(multiplier.floatValue(), (float)(0), (float) (1 - multiplier)); + if(n != null) { + n.setBackgroundColor(c); + } } else { cleanupStyleForNode(_node); } @@ -120,8 +139,11 @@ public class SimulationPlaybackStyle extends StyleBase { @Override protected void cleanupStyleForNode(INode node) { - ProfileVariables.denyChild(node, "", "simulationPlaybackColour"); + if(node instanceof SingleElementNode) { + TextNode n = NodeUtil.getNearestChildByClass((SingleElementNode)node, TextNode.class); + if(n != null) + n.setBackgroundColor(null); + } } - } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewExperimentNodeHandler.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewExperimentNodeHandler.java index 412a4251..16bcd5ec 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewExperimentNodeHandler.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewExperimentNodeHandler.java @@ -16,6 +16,7 @@ import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.handlers.HandlerUtil; +import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.WriteRequest; @@ -24,7 +25,7 @@ import org.simantics.db.exception.DatabaseException; import org.simantics.document.DocumentResource; import org.simantics.layer0.Layer0; import org.simantics.layer0.utils.direct.GraphUtils; -import org.simantics.simulation.ontology.SimulationResource; +import org.simantics.sysdyn.SysdynResource; import org.simantics.sysdyn.ui.browser.nodes.ExperimentsFolder; import org.simantics.ui.SimanticsUI; import org.simantics.ui.utils.AdaptionUtils; @@ -51,10 +52,10 @@ public class NewExperimentNodeHandler extends AbstractHandler { DocumentResource DOC = DocumentResource.getInstance(g); Resource report = GraphUtils.create2(g, DOC.Report, DOC.HasDocumentation, "===Report==="); - String name = NameUtils.findFreshName(g, "Experiment", model, l0.ConsistsOf, "%s%d"); + String name = NameUtils.findFreshName(g, getNameSuggestion(), model, l0.ConsistsOf, "%s%d"); @SuppressWarnings("unused") - Resource experiment = GraphUtils.create2(g, SimulationResource.getInstance(g).Experiment, + Resource experiment = GraphUtils.create2(g, getExperimentType(g), l0.HasName, name, l0.HasLabel, name, DOC.HasReportFactory, report, @@ -63,5 +64,13 @@ public class NewExperimentNodeHandler extends AbstractHandler { }); return null; } + + protected Resource getExperimentType(ReadGraph g) { + return SysdynResource.getInstance(g).BasicExperiment; + } + + protected String getNameSuggestion() { + return "Experiment"; + } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewPlaybackExperimentNodeHandler.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewPlaybackExperimentNodeHandler.java new file mode 100644 index 00000000..417f3266 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/NewPlaybackExperimentNodeHandler.java @@ -0,0 +1,17 @@ +package org.simantics.sysdyn.ui.handlers; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.sysdyn.SysdynResource; + + +public class NewPlaybackExperimentNodeHandler extends NewExperimentNodeHandler { + + protected Resource getExperimentType(ReadGraph g) { + return SysdynResource.getInstance(g).PlaybackExperiment; + } + + protected String getNameSuggestion() { + return "Playback Experiment"; + } +} \ No newline at end of file diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentManagerListener.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentManagerListener.java index ba27f53a..d631a2d5 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentManagerListener.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/listeners/SysdynExperimentManagerListener.java @@ -23,11 +23,14 @@ import org.eclipse.ui.contexts.IContextService; import org.simantics.simulation.experiment.IExperiment; import org.simantics.simulation.project.IExperimentManager; import org.simantics.simulation.project.IExperimentManagerListener; +import org.simantics.sysdyn.manager.SysdynExperiment; +import org.simantics.sysdyn.manager.SysdynPlaybackExperiment; public class SysdynExperimentManagerListener implements IExperimentManagerListener{ public static final String BASIC_EXPERIMENT_CONTEXT = "org.simantics.sysdyn.ui.basicExperiment"; - + public static final String PLAYBACK_EXPERIMENT_CONTEXT = "org.simantics.sysdyn.ui.playbackExperiment"; + static Set managers = new HashSet(); @@ -63,7 +66,10 @@ public class SysdynExperimentManagerListener implements IExperimentManagerListen (IContextService)PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getService(IContextService.class); synchronized(contextActivations) { - contextActivations.add(contextService.activateContext(BASIC_EXPERIMENT_CONTEXT)); + if(experiment instanceof SysdynPlaybackExperiment) + contextActivations.add(contextService.activateContext(PLAYBACK_EXPERIMENT_CONTEXT)); + else if(experiment instanceof SysdynExperiment) + contextActivations.add(contextService.activateContext(BASIC_EXPERIMENT_CONTEXT)); } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/menu/PlaybackSliderContribution.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/menu/PlaybackSliderContribution.java new file mode 100644 index 00000000..04596c12 --- /dev/null +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/menu/PlaybackSliderContribution.java @@ -0,0 +1,98 @@ +package org.simantics.sysdyn.ui.menu; + +import org.eclipse.jface.action.ToolBarContributionItem; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Slider; +import org.eclipse.swt.widgets.ToolBar; +import org.eclipse.swt.widgets.ToolItem; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; +import org.simantics.simulation.experiment.IExperiment; +import org.simantics.simulation.project.IExperimentManager; +import org.simantics.sysdyn.SysdynResource; +import org.simantics.sysdyn.manager.SysdynPlaybackExperiment; +import org.simantics.ui.SimanticsUI; + +public class PlaybackSliderContribution extends ToolBarContributionItem { + + + @Override + public void fill(ToolBar parent, int index) + { + if (parent != null) { + + IExperimentManager manager = SimanticsUI.getProject().getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment experiment = manager.getActiveExperiment(); + if(experiment == null || !(experiment instanceof SysdynPlaybackExperiment)) + return; + final SysdynPlaybackExperiment spe = (SysdynPlaybackExperiment)experiment; + + Double[] numbers = new Double[3]; + try { + numbers = SimanticsUI.getSession().syncRequest(new Read() { + @Override + public Double[] perform(ReadGraph graph) throws DatabaseException { + Double[] numbers = new Double[3]; + Resource model = spe.getModel(); + SysdynResource sr = SysdynResource.getInstance(graph); + numbers[0] = graph.getRelatedValue(model, sr.HasStartTime); + numbers[1] = graph.getRelatedValue(model, sr.HasStopTime); + numbers[2] = graph.getPossibleRelatedValue(model, sr.HasOutputInterval); + return numbers; + } + }); + } catch (DatabaseException e1) { + e1.printStackTrace(); + } + + ToolItem ti = new ToolItem(parent, SWT.SEPARATOR); + + Composite composite = new Composite(parent, SWT.NONE); + GridLayoutFactory.fillDefaults().numColumns(2).applyTo(composite); + GridDataFactory.fillDefaults().applyTo(composite); + + Slider s = new Slider(composite, SWT.NONE); + s.setMinimum(0); + s.setMaximum(100); + s.setIncrement(1); + s.setPageIncrement(1); + s.setThumb(1); + + final Label label = new Label(composite, SWT.NONE); + GridDataFactory.fillDefaults().hint(50, SWT.DEFAULT).applyTo(label); + label.setText("0.0"); + + ti.setWidth(250); + ti.setControl(composite); + + final Double startTime = numbers[0]; + final Double endTime = numbers[1]; + + + s.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + Slider s = (Slider)e.widget; + Double time = s.getSelection() / 99.0 * (endTime - startTime) + startTime; + spe.setTime(time); + if(!label.isDisposed()) { + label.setText(time.toString()); + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + }); + } + } +} diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ModelUtils.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ModelUtils.java index 05a1b500..cfa0f15f 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ModelUtils.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ModelUtils.java @@ -116,7 +116,7 @@ public class ModelUtils { Resource report = GraphUtils.create2(g, DOC.Report, DOC.HasDocumentation, "===Report==="); - GraphUtils.create2(g, mu.SIMU.Experiment, + GraphUtils.create2(g, sr.BasicExperiment, l0.HasName, "Experiment", l0.HasLabel, "Experiment", DOC.HasReportFactory, report, diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ProfileEntries.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ProfileEntries.java index d285d393..597f07b3 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ProfileEntries.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ProfileEntries.java @@ -24,7 +24,7 @@ public class ProfileEntries { Layer0 L0 = Layer0.getInstance(graph); DiagramResource DIA = DiagramResource.getInstance(graph); - final Resource a = createWorkProfile(graph, "A"); + final Resource a = createWorkProfile(graph, "Simulation Playback"); Resource plain = Profiles.createProfile(graph, "Plain"); diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/DependencyFunction.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/DependencyFunction.java index 828f722d..edd32658 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/DependencyFunction.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/DependencyFunction.java @@ -84,7 +84,6 @@ public class DependencyFunction { return Boolean.FALSE; } } - System.out.println("NOTHING"); return Boolean.TRUE; } @@ -104,11 +103,8 @@ public class DependencyFunction { String name = graph.getRelatedValue(variable, L0.HasName, Bindings.STRING); - System.out.println("SOME CHANGE IN " + name + "(existing: " + existing.size() + ")"); - Set labels = new HashSet(); String label; - Resource issue; for(String reference : references) { label = getMissingLinkLabel(name, reference); @@ -159,7 +155,6 @@ public class DependencyFunction { } private static Resource createIssue(WriteGraph graph, Resource model, Resource source, Resource variable, String label) throws DatabaseException { - System.out.println("CREATE ISSUE: " + label); Layer0 L0 = Layer0.getInstance(graph); IssueResource ISSUE = IssueResource.getInstance(graph); @@ -178,7 +173,6 @@ public class DependencyFunction { } private static void removeIssue(WriteGraph graph, Resource model, Resource source, Resource variable, Resource issue, Collection existing) throws DatabaseException { - System.out.println("REMOVE ISSUE: " + graph.getRelatedValue(issue, Layer0.getInstance(graph).HasLabel)); graph.deny(issue, Layer0.getInstance(graph).PartOf); graph.deny(source, IssueResource.getInstance(graph).Manages, issue); existing.remove(issue); diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/HistoryVariable.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/HistoryVariable.java index 1b0dfe75..76c98f91 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/HistoryVariable.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/HistoryVariable.java @@ -17,6 +17,7 @@ import java.util.Map; import org.simantics.databoard.Accessors; import org.simantics.databoard.Bindings; +import org.simantics.databoard.Datatypes; import org.simantics.databoard.accessor.Accessor; import org.simantics.databoard.accessor.RecordAccessor; import org.simantics.databoard.accessor.error.AccessorConstructionException; @@ -24,25 +25,34 @@ import org.simantics.databoard.accessor.error.AccessorException; import org.simantics.databoard.binding.error.RuntimeBindingConstructionException; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; +import org.simantics.db.common.request.ParametrizedPrimitiveRead; import org.simantics.db.common.uri.UnescapedChildMapOfResource; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.exception.MissingVariableException; +import org.simantics.db.layer0.variable.ConstantPropertyVariable; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; +import org.simantics.db.procedure.Listener; +import org.simantics.db.request.ExternalRead; import org.simantics.layer0.Layer0; import org.simantics.simulation.ontology.SimulationResource; import org.simantics.structural.stubs.StructuralResource2; import org.simantics.sysdyn.SysdynResource; import org.simantics.sysdyn.manager.SysdynDataSet; +import org.simantics.sysdyn.manager.SysdynExperiment; import org.simantics.sysdyn.manager.SysdynModel; import org.simantics.sysdyn.manager.SysdynModelManager; +import org.simantics.sysdyn.manager.SysdynPlaybackExperiment; import org.simantics.sysdyn.manager.SysdynResult; -public class HistoryVariable extends ChildVariable { +public class HistoryVariable extends ChildVariable implements PropertyProvider { + SysdynExperiment experiment; + public HistoryVariable(Variable parent, Resource resource) { super(parent, resource); + experiment = SysdynExperiment.INSTANCE; } @@ -143,5 +153,54 @@ public class HistoryVariable extends ChildVariable { } else { return super.browseChildren(graph); } - } + } + + + @Override + public Variable getPossibleExtraProperty(ReadGraph graph, final String name) throws DatabaseException { + if(Variables.DISPLAY_VALUE.equals(name)) { + return graph.syncRequest(new ParametrizedPrimitiveRead(this) { + VariableValueSubscription subscription; + @Override + public void register(Listener procedure) { + subscription = registerSubscription(this, procedure, name); + } + @Override + public void unregistered() { + unregisterSubscription(subscription); + subscription = null; + } + }); + } + return super.getPossibleExtraProperty(graph, name); + } + + protected VariableValueSubscription registerSubscription(ExternalRead request, Listener procedure, String property) { + if(experiment instanceof SysdynPlaybackExperiment) { + VariableValueSubscription subscription = new VariableValueSubscription(request, this, property, procedure); + experiment.addVariableValueSubscription(subscription); + subscription.update(); + return subscription; + } else { + return null; + } + } + + protected void unregisterSubscription(VariableValueSubscription subscription) { + subscription.setListener(null); + experiment.removeVariableValueSubscription(subscription); + } + + @Override + public Variable getProperty(String name) { + if(Variables.DISPLAY_VALUE.equals(name)){ + if(experiment instanceof SysdynPlaybackExperiment) { + SysdynPlaybackExperiment exp = (SysdynPlaybackExperiment) experiment; + return new ConstantPropertyVariable(parent, name, exp.getTime(), Datatypes.DOUBLE); + } else { + return new ConstantPropertyVariable(parent, name, 0, Datatypes.DOUBLE); + } + } + return null; + } } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/PropertyProvider.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/PropertyProvider.java new file mode 100644 index 00000000..2a7bcd06 --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/PropertyProvider.java @@ -0,0 +1,10 @@ +package org.simantics.sysdyn.adapter; + +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.Variable; + +public interface PropertyProvider { + + Variable getProperty(String name) throws DatabaseException, AdaptException; +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/VariableValueSubscription.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/VariableValueSubscription.java new file mode 100644 index 00000000..e04aed72 --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/VariableValueSubscription.java @@ -0,0 +1,103 @@ +package org.simantics.sysdyn.adapter; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.simantics.databoard.adapter.AdaptException; +import org.simantics.db.Session; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.procedure.Listener; +import org.simantics.db.request.ExternalRead; +import org.simantics.db.service.QueryControl; +import org.simantics.utils.datastructures.Callback; + +public class VariableValueSubscription { + + public static final long SUBSCRIPTION_COLLECTION_INTERVAL = 2000L; + + protected ExternalRead request; + protected PropertyProvider provider; + protected String property; + protected Listener listener; + + /** + * To protect against invoking listener.exception multiple times which is + * forbidden. + */ + protected AtomicBoolean excepted = new AtomicBoolean(false); + + public VariableValueSubscription(ExternalRead request, PropertyProvider variable, String property, Listener listener) { + this.request = request; + this.provider = variable; + this.property = property; + this.listener = listener; + } + + public ExternalRead getRequest() { + return request; + } + + public void update() { + update(property); + } + + public void update(String property) { + try { + Variable value = provider.getProperty(property); + fireValue(value); + } catch (DatabaseException e) { + fireException(e); + } catch (AdaptException e) { + fireException(e); + } + } + + void fireValue(Variable value) { + if (listener != null) + listener.execute(value); + } + + void fireException(Throwable t) { + if (listener != null && excepted.compareAndSet(false, true)) + listener.exception(t); + } + + public void setListener(Listener listener) { + this.listener = listener; + } + + /** + * This makes sure that subscriptions regarding performed DB external reads + * are abolished from DB client caches when no longer needed. + * + * @param session + * @param subscriptions + */ + public static void collectSubscriptions(Session session, final VariableValueSubscription[] subscriptions, final ExternalRead... extraReads) { + if (subscriptions.length == 0 && extraReads.length == 0) + return; + + session.asyncRequest(new WriteRequest() { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + Collection> requests = new ArrayList>(subscriptions.length + extraReads.length); + for (VariableValueSubscription subscription : subscriptions) + requests.add(subscription.getRequest()); + for (ExternalRead read : extraReads) + requests.add(read); + graph.getService(QueryControl.class).gc(graph, requests); + } + }, new Callback() { + @Override + public void run(DatabaseException e) { + if (e != null) + e.printStackTrace(); + } + }); + } + +} 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 8fc4baa8..2dbe53d5 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java @@ -11,6 +11,8 @@ *******************************************************************************/ package org.simantics.sysdyn.manager; +import gnu.trove.set.hash.THashSet; + import java.io.File; import java.util.UUID; import java.util.concurrent.locks.Lock; @@ -34,26 +36,29 @@ import org.simantics.simulation.experiment.ExperimentState; import org.simantics.simulation.experiment.IDynamicExperiment; import org.simantics.simulation.ontology.SimulationResource; import org.simantics.sysdyn.SysdynResource; +import org.simantics.sysdyn.adapter.VariableValueSubscription; import org.simantics.sysdyn.simulation.SimulationScheduler; public class SysdynExperiment extends Experiment implements IDynamicExperiment { - Session session; - Runnable modificationListener; - Resource experiment; - SysdynModel sysdynModel; - boolean toggled = false; + protected Session session; + protected Runnable modificationListener; + protected SysdynModel sysdynModel; + protected boolean toggled = false; + protected THashSet variableValueSubscriptions = new THashSet(); + protected volatile VariableValueSubscription[] variableValueSubscriptionsSnapshot = null; + + public static SysdynExperiment INSTANCE; public SysdynExperiment(Resource experiment, Resource model) { - super(model); - this.experiment = experiment; - // TODO Auto-generated constructor stub + super(experiment, model); + INSTANCE = this; } - - public Resource getResource() { - return this.experiment; + + public static SysdynExperiment getInstance() { + return INSTANCE; } - + @Override public void rewindTo(double time) { // TODO Auto-generated method stub @@ -108,7 +113,7 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { } - private void startSimulation() { + protected void startSimulation() { session.asyncRequest(new ReadRequest() { @Override @@ -231,7 +236,7 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { } - private void toggleActivation(ReadGraph graph, final boolean activate) { + protected void toggleActivation(ReadGraph graph, final boolean activate) { VirtualGraphSupport support = graph.getService(VirtualGraphSupport.class); final Session session = graph.getSession(); session.asyncRequest(new WriteRequest(support.getWorkspacePersistent("experiments")) { @@ -266,6 +271,76 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { // TODO Auto-generated method stub return null; } + + /** + * Copy from AprosExperiment + * @param subscription + */ + public void addVariableValueSubscription(VariableValueSubscription subscription) { + assert subscription != null; + synchronized (variableValueSubscriptions) { + //System.out.println("ADD listener " + subscription); + variableValueSubscriptions.add(subscription); + variableValueSubscriptionsSnapshot = null; + } + } + + /** + * Copy from AprosExperiment + * @param subscription + */ + public void removeVariableValueSubscription(VariableValueSubscription subscription) { + assert subscription != null; + synchronized (variableValueSubscriptions) { + //System.out.println("REMOVE listener " + subscription); + variableValueSubscriptions.remove(subscription); + variableValueSubscriptionsSnapshot = null; + } + } + + /** + * Copy from AprosExperiment + * @return + */ + private VariableValueSubscription[] getListenerSnapshot() { + VariableValueSubscription[] snapshot = variableValueSubscriptionsSnapshot; + if (snapshot == null) { + synchronized (variableValueSubscriptions) { + snapshot = variableValueSubscriptionsSnapshot; + if (snapshot == null) { + snapshot = variableValueSubscriptionsSnapshot = variableValueSubscriptions.toArray(new VariableValueSubscription[variableValueSubscriptions.size()]); + } + } + //System.out.println("listener count: " + snapshot.length); + } + return snapshot; + } + + volatile long previousVariableUpdateTime = 0; + volatile boolean skippedVariableUpdate = true; + + + /** + * Modified copy from AprosExperiment + */ + public void fireValuesChanged() { + long time = System.nanoTime(); + if(time - previousVariableUpdateTime > 100000000) { + updateSubscriptions(); + previousVariableUpdateTime = time; + } + else + skippedVariableUpdate = true; + } + + /** + * Modified copy from AporsExperiment + */ + private void updateSubscriptions() { + for(VariableValueSubscription subscription : getListenerSnapshot()) + subscription.update(); + skippedVariableUpdate = false; + } } 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 c6f74ef0..1a3cfe71 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java @@ -46,6 +46,7 @@ import org.simantics.objmap.IMappingListener; import org.simantics.objmap.Mappings; import org.simantics.simulation.experiment.Experiment; import org.simantics.simulation.experiment.ExperimentState; +import org.simantics.simulation.experiment.IDynamicExperiment; import org.simantics.simulation.experiment.IExperiment; import org.simantics.simulation.model.IModel; import org.simantics.simulation.ontology.SimulationResource; @@ -467,10 +468,22 @@ public class SysdynModel implements IMappingListener, IModel { e.printStackTrace(); } } + - SysdynExperiment exp = new SysdynExperiment(experiment, modelResource); try { - exp.init(g); + + SysdynResource sr = SysdynResource.getInstance(g); + IDynamicExperiment exp; + if(g.isInstanceOf(experiment, sr.PlaybackExperiment)) { + exp = new SysdynPlaybackExperiment(experiment, modelResource); + ((SysdynPlaybackExperiment)exp).init(g); + } else if(g.isInstanceOf(experiment, sr.BasicExperiment)) { + exp = new SysdynExperiment(experiment, modelResource); + ((SysdynExperiment)exp).init(g); + } else { + return null; + } + ExperimentRuns.createRun(g.getSession(), experiment, exp, listener, null); if(listener != null) listener.onExperimentActivated(exp); diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java new file mode 100644 index 00000000..416ce05c --- /dev/null +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynPlaybackExperiment.java @@ -0,0 +1,50 @@ +package org.simantics.sysdyn.manager; + +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.simulation.experiment.ExperimentState; +import org.simantics.simulation.experiment.IDynamicExperiment; +import org.simantics.simulation.ontology.SimulationResource; + +public class SysdynPlaybackExperiment extends SysdynExperiment implements IDynamicExperiment { + + double time; + public static final long VARIABLE_UPDATE_INTERVAL = 500000000; + + + public SysdynPlaybackExperiment(Resource experiment, Resource model) { + super(experiment, model); + this.time = 0; + } + + volatile boolean updating = false; + + + public void setTime(double time) { + this.time = time; + fireValuesChanged(); + } + + public double getTime() { + return this.time; + } + + @Override + public void init(ReadGraph g) { + this.session = g.getSession(); + changeState(ExperimentState.STOPPED); + + session.asyncRequest(new ReadRequest() { + + @Override + public void run(ReadGraph graph) throws DatabaseException { + final Resource configuration = graph.getPossibleObject(model, SimulationResource.getInstance(graph).HasConfiguration); + sysdynModel = SysdynModelManager.getInstance(session).getModel(graph, configuration); + toggleActivation(graph, true); + startSimulation(); + } + }); + } +} diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynResult.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynResult.java index fad8674a..3b41feda 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynResult.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynResult.java @@ -20,8 +20,8 @@ import java.util.TreeMap; import org.simantics.databoard.Accessors; import org.simantics.databoard.Bindings; +import org.simantics.databoard.Datatypes; import org.simantics.databoard.Files; -import org.simantics.databoard.Historian; import org.simantics.databoard.accessor.Accessor; import org.simantics.databoard.accessor.MapAccessor; import org.simantics.databoard.accessor.RecordAccessor; @@ -83,7 +83,7 @@ public class SysdynResult { public void setResult(SimulationResult result) { try { // Create Memory Historian - Datatype recordingSessionType = Historian.getRecordingSessionType(); + Datatype recordingSessionType = Datatypes.getDatatype("RecordingSession"); RecordBinding sessionBinding = (RecordBinding) Bindings.getBinding( recordingSessionType ); RecordBinding recordingBinding = (RecordBinding) Bindings.getBinding( Recording.class ); Object session = sessionBinding.createDefault(); -- 2.47.1