From d0db128759b0d2e7773629e303f5d7fae3fd4cc8 Mon Sep 17 00:00:00 2001 From: lehtonen Date: Fri, 12 Apr 2013 01:12:44 +0000 Subject: [PATCH] Merged changes from r27124 through r27280 from trunk to branches/simantics-1.10 in preparation for the Simantics 1.10 release. refs #4189 The merged changes include fixes for the following issues:
	2013-07 (22)
		#4219	Transferable graph with resource literals can only be imported once
		#4223	Remove stdout printing option from issues to CSV export action
		#4231	Wordwrap/Horizontal scrollbar for document editor StyledText widget
		#4233	FileUtils.copyFile/copy do not close file descriptors properly
		#4234	File handle leakage in PDF export
		#4246	Problems in FastLZ stream implementations
		#4248	Query collector fails to collect some discarded parents
		#4249	Subscription collection initialization fails if a subscription item is broken (has no name)
		#4250	ContextualHelp should attempt help context resolution on diagrams even when selected element is not mapped
		#4224	Allow GraphExplorer item selection by keys / labels to use other than primary column for matching.
		#4189	Branch and release Simantics 1.10
		#4235	Drawing template changes
		#4065	Fix annotation user interfaces
		#4218	Color edit support for DnD monitors
		#4220	Change EntityRemover to not remove L0.HasProperty objects as composed properties if they are an L0.PartOf something else
		#4225	Show resource ID in issue view if there's nothing else to show for the issue context
		#4226	Make low level Layer0 validation produce fatal issues so that they don't go unnoticed.
		#4228	Allow CSV export number format specification through preferences
		#4229	Customizable clipboard logic in CopyPasteHandler
		#4230	Prevent RouteGraphNode from starting connection rerouting if there are more than one other elements selected
		#4247	Primarily look for workbench search function from active model, resort to project only secondarily.
		#4251	Allow tree columns in TreeDialog
	2013-06 (28)
		#4113	ResourceBinding cleanup
		#4181	Caching prevents some valid renames
		#4182	Dependency index gets out of sync
		#4185	undo(int numberOfOperations)
		#4186	PDF export leaks memory
		#4190	Do not allow entity names to be modified to begin with one or more dots ('.')
		#4191	AdaptationUtils.adaptToCollection fails to adapt, if class implements IAdaptable
		#4193	Selection view input throttling produces wrong tabs for user
		#4195	Deleting terminal element in symbol editor fails to remove diagram connection points from symbol
		#4202	SWTKeyEventAdapter produces wrong modifier state mask for key event when AltGr is pressed
		#4210	Simulation time HMS mode viewing fails to show time beyond 5 965 hours
		#4211	Problems with session reconnect
		#4212	setImmutable failed if cluster was not resident
		#4215	Safety fixes for monitor formatting
		#2897	As a developer, I want to use GraphExplorer as non-virtual
		#3219	Lazy updating of model browser and graph explorer are problematic
		#3994	Get Resource -> Resource map in SCL based mapping
		#4184	TreeViewer based GraphExplorer
		#4206	Save work done for team feature movie.
		#3984	Import sources for SimanticsExcel.dll
		#4197	If mouse doesn't move between subsequent diagram copy-paste operations, offset the pasted elements as when using Edit / Paste main menu
		#4203	Migration framework enhancement
		#4204	Temp file management in Simantics facade
		#4205	Refactor issues to allow reporting of L0 issues
		#4213	Make recovery work silently.
		#4214	GraphExplorerImpl image decorations should be offloaded from the UI thread into the image loader job
		#4216	BoxSelectionMode should be cancelable by pressing ESC
		#4217	Extend BasicExpression lexer to support 8-bit ASCII characters in quoted strings
	2013-05 (29)
		#4114	Flag type not verified for newly created flags
		#4132	Workspace persistent virtual graph loading robustness / safety enhancements
		#4144	Spreadsheet loses selection while editing cell
		#4145	Useless error messages when pasting PNG image on top of image node in a drawing template
		#4151	Issues are not updated in some removal cases
		#4157	Diagram loading can cause weird exceptions if editor is disposed during loading
		#4158	Manual activation of mapping messes up undo
		#4159	Removal of connected diagram reference elements corrupts database
		#4161	RouteGraph.makePersistent behaves incorrectly when the connection is simple
		#4163	Minor bug in connect tool
		#4164	Component modification metadata missing for some removed connections
		#4166	Session does not close properly
		#4169	Modelled views fail to show content at startup
		#4173	Random access values can corrupt the database session
		#4174	AwtFocusHandler.hidePopups race condition
		#4178	Move tryRemover from DeleteNodeHandler to RemoverUtil
		#4153	Exporting GraphFiles
		#4160	Minor modifications to SCL documentation
		#4165	Support session reconnect in SimanticsPlatform
		#3519	Change Sysdyn jenkins builds to bundle JRE 6
		#4142	Simantics 1.9 release
		#4147	Store SCL console command history into preferences
		#4148	Add undo into DB.scl
		#4150	Batch issue validation performance enhancements
		#4155	Allow overriding oleEditor's title.
		#4162	runTest command for SCL console
		#4167	Remove resources from index updates
		#4170	Set exported PDF Application metadata based on IProduct information
		#4179	Support multiple tg roots in migration framework
git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/branches@27281 ac1ea38d-2e2b-0410-8846-a27921b304fc --- .../graph.tg | Bin 12460 -> 12519 bytes .../graph/JFreeChart.pgraph | 2 + .../simantics/sysdyn/JFreeChartResource.java | 3 + .../org.simantics.jfreechart/adapters.xml | 7 +- .../jfreechart/chart/DeviationRenderer.java | 35 ++ .../chart/properties/ColorPicker.java | 27 +- .../simantics/modelica/ModelicaManager.java | 20 +- .../modelica/SimulationLocation.java | 1 + .../org/simantics/objmap/impl/Mapping.java | 8 +- .../objmap/impl/RangeUpdateRequest.java | 4 +- .../org.simantics.sysdyn.ontology/graph.tg | Bin 146144 -> 147560 bytes .../graph/Migration.pgraph | 38 +- .../graph/Sysdyn.pgraph | 6 + .../org/simantics/sysdyn/SysdynResource.java | 63 ++- .../org.simantics.sysdyn.ui/adapters.xml | 2 +- .../icons/bullet_gray.png | Bin 0 -> 303 bytes .../icons/bullet_green.png | Bin 0 -> 334 bytes .../org.simantics.sysdyn.ui/plugin.xml | 22 ++ .../CreateVariablesShortcutParticipant.java | 2 +- .../newComponents/NewBarChartHandler.java | 2 +- .../NewExperimentNodeHandler.java | 2 +- .../newComponents/NewFunctionHandler.java | 2 +- .../NewFunctionLibraryHandler.java | 2 +- .../newComponents/NewHistoryDataHandler.java | 2 +- .../newComponents/NewModuleNodeHandler.java | 2 +- .../newComponents/NewPieChartHandler.java | 2 +- ...sitivityAnalysisExperimentNodeHandler.java | 2 + .../NewSensitivityChartHandler.java | 105 +++++ .../NewSharedFunctionLibraryHandler.java | 2 +- .../newComponents/NewXYLineChartHandler.java | 2 +- .../sysdyn/ui/properties/ModuleInputTab.java | 3 + .../SensitivityAnalysisExperimentTab.java | 20 + .../widgets/expressions/StockExpression.java | 2 +- .../sysdyn/ui/trend/SensitivityDataset.java | 189 +++++++++ .../simantics/sysdyn/ui/trend/XYDataset.java | 369 +++++++++--------- .../sysdyn/ui/utils/ExpressionUtils.java | 4 +- .../sysdyn/ui/utils/imports/ImportUtils.java | 57 ++- .../ui/validation/EnumerationFunction.java | 2 +- .../validation/ExpressionIssueFunction.java | 2 +- .../ui/validation/IssueWithStringContext.java | 2 +- .../sysdyn/adapter/IndexVariable.java | 6 +- .../sysdyn/adapter/ValueIndexVariable.java | 3 +- .../adapter/VariableValueSubscription.java | 20 +- .../sysdyn/manager/SysdynExperiment.java | 18 +- .../sysdyn/manager/SysdynGameExperiment.java | 107 ++++- .../simantics/sysdyn/manager/SysdynModel.java | 18 +- .../SysdynSensitivityAnalysisExperiment.java | 336 +++++++++++----- .../sysdyn/refactoring/TGRefactoring.java | 2 +- .../sysdyn/representation/Sheet.java | 39 +- .../sysdyn/simulation/SimulationJob.java | 12 +- .../simulation/SimulationScheduler.java | 8 +- 51 files changed, 1182 insertions(+), 402 deletions(-) create mode 100644 simantics-1.10/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/DeviationRenderer.java create mode 100644 simantics-1.10/org.simantics.sysdyn.ui/icons/bullet_gray.png create mode 100644 simantics-1.10/org.simantics.sysdyn.ui/icons/bullet_green.png create mode 100644 simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewSensitivityChartHandler.java create mode 100644 simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/SensitivityDataset.java diff --git a/simantics-1.10/org.simantics.jfreechart.ontology/graph.tg b/simantics-1.10/org.simantics.jfreechart.ontology/graph.tg index 5cc13db42534db0cc86f976efc7ecbc3a92498b4..3abaa9be847550808ab81c7e8e16fbfe528e4f5a 100644 GIT binary patch literal 12519 zcmai)2YVFP6^1Elt1iH_BsRu&Fpd$$cEH_2q6h>CNmSR-?noL~?TDFO72GifgL}aR zx48G-JMO*rj`Iuh50dkpxd$E2LlU0nNcTPEyLImD+A8jjyuO|hBSwrQ8&QfM?q6|L zmx)(s2{)W<=uM+=jV z>%*vJT7<#`WvQVYI$f@PDd^Gs{5ckl=zM_^O&Qtbs zrmFTr=YDfLlihXA@fzRTm>p`vy!}i^NEItMR6*T~EID_xv%HZ`Kk3HY(b4QHZ3#Lf zFTw&G9(qWPrXM4#mn@8Yzp;l7 z37xlDRQ1|*4UzA)`MHcAac>jZU(_%dV5{?>iIx399MEZN@jCr1IX;6ouX>I- zt;VIHwk616c|JuTR+$lJ*1F7&AiZ&!7i~mWpCA&c)J>dPr&76pc^#&>M5ui^+3mhF2g}9EmizdIDRtp_{j#xn@Uk(SB4HHz$wv7G79YLNS z$}@n=%KE~XZ&`vNPAJ9EiG4g0o8cHLkLfA(X}S0@`2xPps=Es~sk+ze>j?Qtb^G!) z{1>Rib2*W&`F$JtB|PVUFh#> zrn)A-KS=r*p5Q346M_r}`@bg9gloH@MQ z4SbahFZVHs&n!*cIF-l3aZGJ8=_a~$lMp#CW~uVlz#l$n7qTz4cHOY+bas`xM~mwA zz;U`7Q#of$7C?L~n{w?J%k;R@{@$L{}m zuIf0&ohyBOmLiZUrk5n2zn6eZ)r5LEUP>#|nhkNN2H8=*ywKa}NA5|eV&8#hZFl8h z!VxVtiSjaby2EH_c*h1fkXnsTM{cm4?5b`I zd-p4%JoHs!0Re05YGV{ZTUKo_} zD%`77-WtxU=;Q=>I9`Kujmm1*S@K}K0%yC*O2d&VavQb*l&%QrzRb~8oxEe;hjW9f z=}xlTbQeVdCi@PY-72exv#R(W;B%YYzwg4`qw<0zPZkfS8xP=na0eVEgEEex{siJ4sA!oO7|Udf3SbVsY>b1ged=7;%w z*h>Ywm@D}x41fH*1>Rk$G!9OV){^K3PAqN`ZmgJ3w3>yJ}nM zBT~LS?a?O$IbLUTB>8YG*;)3LtX=0ebY&tK7drEJYO$~{!?jXPv!8P+<$-X^b`5*W zT8Ce+bJ;VV9`EESIhC7a)4LX2|A$foOz~Gdqtdt_&jw*oD9cF2f8Az zVyQ9hd3s&=nf-TlBggiwfm^*T?5&WK(zd#pw7-FKi(0=NXBDUMWrso^0COtdh|i28 ztLZaiA)PNoUe=nLt z>*$FJ?O{ZBjf;)vSWUVR(@mn^(SPQ^q$I$@ZSu`$ziFH@_Q1<qV*IKuVA3Aa;#C@K`2suvWgp4)NDe`okx!`~SG z+VEF~zcl=X;m-|!X82RXpBVnw@JEI}H2i_#_YJ>i_+7*A7=GLETZZ2>yvOhxhF>@Q zn&DRszhd}h!!H?rp19)Q^pAeuPX>O-@npvjIzHL)1N8e>vQx;OBa`}Rj;Fi)6CEF^ z^qw{OV97s$+F+gk4Dp?={&;GG?@)T++Z|7EaT(8T#7~n6V}4*gKd{X2SQnT19Y_2W znbc!`U>WZm$9lX^ntZV2ja z`^cnzn&av2JdAUEq&hG6ntZV2*HIg+^Y1bFV96g#ZLs8Hymynye%3nH`-!;hr{v4{ zv7dLT`fA5gk9@?X9_Jmb>u(`$A^U|4aqx07-1lda-ApF=mr#2b*-d1BkRb+MLiQ6G zYQc-iej~fl@oxIPmkjY6$RvIZwXZjPo#AT@qeklSaqeox=TZAA!&e%__?ymif0jmi1ZTSk`Z?W0^1NcaVwR5014S;#v_+7}tV(C`JsqW?9u!Fv8+-5*%SH__!w|ENEoO!U5Tto0DrdSI;w7CqGC zOv`+5-p?fy{VyGBeZ;jsSoEO<7JbxjCKJ6c9BVzqwH{dXu>auQWP8a_k2RP305Q$z zTQlaW8EXsH^975(#D%3^SoDQAQ|+MA!+s4I?l)W@mi73Y+F-pNV7(q-S&y|YU;0OV zo=o&UbFB3c*Lq;l!}AXoJ=Di!qW7s|t%tbQ18Y67=%GF$6TMFyYdyrZ9$4#vMGy6x z$VBgB$660@tq0b6V9`T;ADQTV zbFB3c*Lq;B2Npfl_mGJmz6*i19$4#vMX$}}iyrE`$wcoR$660@tp^r8%oi+rsP7^Z zy|*1}J;b#hSoE-eV9`Upuj06Gz@q<_W37j{)FYlz`ENSb<3U{4gJnGE4=j49#~E5e z_7fRmn$fpr%tbTSN;CFGGxl0D&JuVr*>7acj%7R&7nXWq(HEBfg=M_Lm`^8}^tX)K zp5b#0pKbUo!)Fl7dg8o*Wxda&_UUA@pL-nZ{XtyvSGc&=LtMtchuZ7OMDGp9S`Trp z2NpftZ{Xczd&yA0j!g7kcdYdg*Lq;l!+gP_hx#>SqW79(t%tbQ1B)KU2NpfluObt@ zR~>6T#I+t+^e{fK=%K!yO!QuHto0DrdSKDR^9vR|)UPBHy_X$pJ;b#hSoCmTfkhAX zIFs`HVed8LY=Pzc;&}l}J>pBrWIQi9*5g53j|VK{ffiWwP``*w>Mx=8sfwpLmhY=a zIhOCM6Npby`Pko+70;mdNs5nlEd3+*L=``X+9xO;L+#@g*HC+&;!4M&hrZ^L-Ri!t zKjT>9=nHXS^rabnfsb(YSPRY18h*~PtRKdM{D)or^VI%3nZ&W4V7;DTy`IOZe5~iO zim{%@D8_n%Wj@HAqvBZ4*^05AvlL@JXDY_{!J-H4dNNthCmc&0eIYK4zBHpRu&gKM zs`*L7PdS$L!g!D`>-jXb|3)TptS4BnCs@{VBDMcYrt`r%A1wJ3sC~G~$NC>;c&cLT z$DxXmKgIANijjY?V(cGS)(_g6Q9GGT#y`oi+#fl^TMTbCyv^`-!#fP`bgb_qj7P>R zabc+!7JXs#k3G@z0qgl_4qd*)@!4I+HyMr$$AoWjfT4n wDfw{LI1P2lzr(EKP}|EC>p0Fj7V$Wy(I3^TKe3O8;>=L4e)!Lg<^R0@2SXb3egFUf literal 12460 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 dH5RkR4EoD>^>^~|aGV{^H;nwvu>7C({{YvI diff --git a/simantics-1.10/org.simantics.jfreechart.ontology/graph/JFreeChart.pgraph b/simantics-1.10/org.simantics.jfreechart.ontology/graph/JFreeChart.pgraph index c83c6743..aaf0a275 100644 --- a/simantics-1.10/org.simantics.jfreechart.ontology/graph/JFreeChart.pgraph +++ b/simantics-1.10/org.simantics.jfreechart.ontology/graph/JFreeChart.pgraph @@ -111,6 +111,8 @@ JFREE.XYAreaRenderer - + + + + + \ No newline at end of file diff --git a/simantics-1.10/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/DeviationRenderer.java b/simantics-1.10/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/DeviationRenderer.java new file mode 100644 index 00000000..716bb682 --- /dev/null +++ b/simantics-1.10/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/DeviationRenderer.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2013 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.jfreechart.chart; + +import org.jfree.chart.labels.StandardXYToolTipGenerator; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; + +public class DeviationRenderer extends AbstractRenderer { + + public DeviationRenderer(ReadGraph graph, Resource resource) { + super(graph, resource); + } + + private org.jfree.chart.renderer.xy.DeviationRenderer renderer; + + @Override + public org.jfree.chart.renderer.AbstractRenderer getRenderer() { + if(renderer == null) { + renderer = new org.jfree.chart.renderer.xy.DeviationRenderer(); + renderer.setBaseToolTipGenerator(new StandardXYToolTipGenerator()); + } + return renderer; + } + +} diff --git a/simantics-1.10/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ColorPicker.java b/simantics-1.10/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ColorPicker.java index 2901c270..c51a8feb 100644 --- a/simantics-1.10/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ColorPicker.java +++ b/simantics-1.10/org.simantics.jfreechart/src/org/simantics/jfreechart/chart/properties/ColorPicker.java @@ -13,12 +13,10 @@ package org.simantics.jfreechart.chart.properties; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Device; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.ColorDialog; @@ -44,6 +42,7 @@ import org.simantics.ui.SimanticsUI; import org.simantics.ui.utils.AdaptionUtils; import org.simantics.utils.RunnableWithObject; import org.simantics.utils.datastructures.Triple; +import org.simantics.utils.ui.gfx.ColorImageDescriptor; /** * Composite for selecting a color for a chart component @@ -165,12 +164,12 @@ public class ColorPicker extends Composite implements Widget { * @param blue Blue 0-255 * @return */ - private Image getColorPickerImage(Device device, int red, int green, int blue) { - Image image = new Image(device, 20, 20); - GC gc = new GC (image); - gc.setBackground (new Color(device, red, green, blue)); - gc.fillRectangle (image.getBounds ()); - gc.dispose (); + private ImageDescriptor getColorPickerImage(Device device, int red, int green, int blue) { + ImageDescriptor image = new ColorImageDescriptor(red, green, blue, 20, 20, true); + //GC gc = new GC (image); + //gc.setBackground (new Color(device, red, green, blue)); + //gc.fillRectangle (image.getBounds ()); + //gc.dispose (); return image; } @@ -179,7 +178,7 @@ public class ColorPicker extends Composite implements Widget { * @author Teemu Lempinen * */ - private class ColorImageFactoryFactory extends ReadFactoryImpl { + private class ColorImageFactoryFactory extends ReadFactoryImpl { Button button; @@ -188,12 +187,13 @@ public class ColorPicker extends Composite implements Widget { this.button = button; } + @Override public Object getIdentity(Object inputContents) { return new Triple, Button>(inputContents, getClass(), button); } @Override - public Image perform(ReadGraph graph, Resource input) throws DatabaseException { + public ImageDescriptor perform(ReadGraph graph, Resource input) throws DatabaseException { if(button.getWidget().isDisposed()) return null; Display device = button.getWidget().getDisplay(); @@ -263,6 +263,7 @@ public class ColorPicker extends Composite implements Widget { final RGB oldRGB = getColor(graph, resource); display.asyncExec(new RunnableWithObject(oldRGB) { + @Override public void run() { // Use color dialog to select a color Shell shell = new Shell(display); @@ -280,7 +281,7 @@ public class ColorPicker extends Composite implements Widget { @Override public void perform(WriteGraph graph) throws DatabaseException { G2DResource g2d = G2DResource.getInstance(graph); - float[] components = new float[] {(float)rgb.red / 255.0f, (float)rgb.green / 255.0f, (float)rgb.blue / 255.0f, 1.0f}; + float[] components = new float[] {rgb.red / 255.0f, rgb.green / 255.0f, rgb.blue / 255.0f, 1.0f}; graph.claimLiteral(resource, getColorRelation(graph), g2d.Color, components); } }); @@ -301,7 +302,7 @@ public class ColorPicker extends Composite implements Widget { */ private class DefaultColorSelectionFactory extends ReadFactoryImpl { - private Boolean isCustom; + private final Boolean isCustom; /** * diff --git a/simantics-1.10/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java b/simantics-1.10/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java index 5364078e..2de275d8 100644 --- a/simantics-1.10/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java +++ b/simantics-1.10/org.simantics.modelica/src/org/simantics/modelica/ModelicaManager.java @@ -68,7 +68,10 @@ public class ModelicaManager { public enum OSType { APPLE, LINUX, SUN, WINDOWS, UNKNOWN } - + + public static String OMC_VERSION = "OMC_VERSION"; + public static String RESULT_FILE_NAME = "RESULT_FILE_NAME"; + /** * Get operating system type * @return OSType @@ -538,12 +541,23 @@ public class ModelicaManager { ArrayList commands = new ArrayList(); commands.add(simulationLocation.executableFile.getAbsolutePath()); + + if(experimentParameters.get(RESULT_FILE_NAME) != null) { + commands.add("-r="+experimentParameters.get(RESULT_FILE_NAME)); + } + // Write new initial values (parameters). No need to update xml if structure has changed. In that case also xml is up-to-date if(parameterChanges != null) { - String version = getOMCVersion(simulationLocation.omcHome); + String version = experimentParameters.get(OMC_VERSION); + if(version == null) + version = getOMCVersion(simulationLocation.omcHome); if(version.startsWith("1.9")) { // Handled in experiment - updateInitFile(simulationLocation, experimentParameters, parameterChanges); + if(parameterChanges.size() == 1) { + commands.add("-override"); + commands.add(parameterChanges.keySet().iterator().next() + "=" + parameterChanges.values().iterator().next()); + } else + updateInitFile(simulationLocation, experimentParameters, parameterChanges); } else { writeInits(simulationLocation, experimentParameters, monitor); } diff --git a/simantics-1.10/org.simantics.modelica/src/org/simantics/modelica/SimulationLocation.java b/simantics-1.10/org.simantics.modelica/src/org/simantics/modelica/SimulationLocation.java index 91ef37b8..98f5cdd0 100644 --- a/simantics-1.10/org.simantics.modelica/src/org/simantics/modelica/SimulationLocation.java +++ b/simantics-1.10/org.simantics.modelica/src/org/simantics/modelica/SimulationLocation.java @@ -16,6 +16,7 @@ import java.io.File; /** * * @author Teemu Lempinen + * @author Tuomas Miettinen * */ public class SimulationLocation { diff --git a/simantics-1.10/org.simantics.objmap/src/org/simantics/objmap/impl/Mapping.java b/simantics-1.10/org.simantics.objmap/src/org/simantics/objmap/impl/Mapping.java index cf4c33c9..abb726e7 100644 --- a/simantics-1.10/org.simantics.objmap/src/org/simantics/objmap/impl/Mapping.java +++ b/simantics-1.10/org.simantics.objmap/src/org/simantics/objmap/impl/Mapping.java @@ -275,12 +275,14 @@ public class Mapping implements IMapping { if(listensDomain) { RangeUpdateRequest request = new RangeUpdateRequest(link, map, this); try { - g.syncRequest(request, request); + boolean modified = g.syncRequest(request, request); + if(modified) { + updated.add(link.rangeElement); + } } catch (DatabaseException e) { throw new MappingException(e); } - // TODO check if really modified - updated.add(link.rangeElement); + } else if(link.type.updateRange(g, map, link.domainElement, link.rangeElement)) diff --git a/simantics-1.10/org.simantics.objmap/src/org/simantics/objmap/impl/RangeUpdateRequest.java b/simantics-1.10/org.simantics.objmap/src/org/simantics/objmap/impl/RangeUpdateRequest.java index 3268d9e2..4c190658 100644 --- a/simantics-1.10/org.simantics.objmap/src/org/simantics/objmap/impl/RangeUpdateRequest.java +++ b/simantics-1.10/org.simantics.objmap/src/org/simantics/objmap/impl/RangeUpdateRequest.java @@ -38,9 +38,9 @@ public class RangeUpdateRequest implements Read, SyncListener @Override public Boolean perform(ReadGraph g) throws DatabaseException { if(map != null) { - link.type.updateRange(g, map, link.domainElement, link.rangeElement); + boolean updated = link.type.updateRange(g, map, link.domainElement, link.rangeElement); map = null; - return Boolean.TRUE; + return updated; } else if(mapping != null) { mapping.domainModified(link); diff --git a/simantics-1.10/org.simantics.sysdyn.ontology/graph.tg b/simantics-1.10/org.simantics.sysdyn.ontology/graph.tg index a7b7d77e4d60bc63d49fa91846c27fd24e7fbb2d..eba5af9cb5f8cdb5a2a547e031682e6cfaab4039 100644 GIT binary patch literal 147560 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 literal 146144 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 diff --git a/simantics-1.10/org.simantics.sysdyn.ontology/graph/Migration.pgraph b/simantics-1.10/org.simantics.sysdyn.ontology/graph/Migration.pgraph index 42345d31..7d135469 100644 --- a/simantics-1.10/org.simantics.sysdyn.ontology/graph/Migration.pgraph +++ b/simantics-1.10/org.simantics.sysdyn.ontology/graph/Migration.pgraph @@ -8,14 +8,34 @@ move : L0.Template L0.NamespaceMigrationStep.Prefix.from %from L0.NamespaceMigrationStep.Prefix.to %to -MIGRATION = SYSDYN."from1.6to1.7" : L0.MigrationSequence +MIGRATION = SYSDYN.Migration : L0.Library + +MIGRATION.fromModel1 : L0.Migration + L0.Migration.format "sysdynModel" + L0.Migration.from 1 + L0.Migration.step FROM16TO17 + L0.Migration.priority 1.0 + +MIGRATION.fromModule1 : L0.Migration + L0.Migration.format "sysdynModule" + L0.Migration.from 1 + L0.Migration.step FROM16TO17 + L0.Migration.priority 1.0 + +MIGRATION.fromFunctionLibrary1 : L0.Migration + L0.Migration.format "sysdynFunctionLibrary" + L0.Migration.from 1 + L0.Migration.step FROM16TO17 + L0.Migration.priority 1.0 + +FROM16TO17 = MIGRATION."from1.6to1.7" : L0.MigrationSequence @L0.list - MIGRATION.Ontologies - MIGRATION.Spreadsheets - MIGRATION.SysdynChanges - MIGRATION.OrderedSetsToLists + FROM16TO17.Ontologies + FROM16TO17.Spreadsheets + FROM16TO17.SysdynChanges + FROM16TO17.OrderedSetsToLists -MIGRATION.Ontologies : L0.NamespaceMigrationStep +FROM16TO17.Ontologies : L0.NamespaceMigrationStep @L0.list _ @move "http://www.simantics.org/Layer0-" "1.0" "1.1" @@ -60,7 +80,7 @@ MIGRATION.Ontologies : L0.NamespaceMigrationStep _ @move"http://www.simantics.org/SelectionView-" "1.1" "1.2" -MIGRATION.Spreadsheets : L0.NamespaceMigrationStep +FROM16TO17.Spreadsheets : L0.NamespaceMigrationStep @L0.list _ @move "http://www.simantics.org/Spreadsheet-1.2/" "HasContent" "Cell/content" @@ -91,7 +111,7 @@ MIGRATION.Spreadsheets : L0.NamespaceMigrationStep _ @move "http://www.simantics.org/Spreadsheet-1.2/" "ColumnWidthsOf" "Headers/columnWidths/Inverse" -MIGRATION.SysdynChanges : L0.NamespaceMigrationStep +FROM16TO17.SysdynChanges : L0.NamespaceMigrationStep @L0.list _ @move "http://www.simantics.org/Sysdyn-1.1/" "HasTail" "Variable/HasTail" @@ -101,7 +121,7 @@ MIGRATION.SysdynChanges : L0.NamespaceMigrationStep @move "http://www.simantics.org/Sysdyn-1.1/" "SharedModuleOntolofgy" "SharedModuleOntology" -MIGRATION.OrderedSetsToLists : L0.OrderedSetToListMigrationStep +FROM16TO17.OrderedSetsToLists : L0.OrderedSetToListMigrationStep @L0.list _ : L0.OrderedSetToListMigrationStep.Change L0.OrderedSetToListMigrationStep.entityType "http://www.simantics.org/Sysdyn-1.1/Variable" diff --git a/simantics-1.10/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph b/simantics-1.10/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph index 30c5641a..109a1df9 100644 --- a/simantics-1.10/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph +++ b/simantics-1.10/org.simantics.sysdyn.ontology/graph/Sysdyn.pgraph @@ -44,6 +44,8 @@ SYSDYN.SysdynModel -- SYSDYN.SysdynModel.tolerance --> L0.Double -- SYSDYN.SysdynModel.solver --> L0.String -- SYSDYN.SysdynModel.variableFilter --> L0.String -- SYSDYN.SysdynModel.fmuFile --> L0.ByteArray -- SYSDYN.SysdynModel.exeFile --> L0.ByteArray -- SYSDYN.SensitivityAnalysisExperiment.minValue --> L0.Double -- SYSDYN.SensitivityAnalysisExperiment.maxValue --> L0.Double -- SYSDYN.SensitivityAnalysisExperiment.numValues --> L0.Integer -- SYSDYN.SensitivityAnalysisExperiment.mean --> L0.Double -- SYSDYN.SensitivityAnalysisExperiment.stdDeviation --> L0.Double - none 0 fill 1 + none 0 fill 1 \ No newline at end of file diff --git a/simantics-1.10/org.simantics.sysdyn.ui/icons/bullet_gray.png b/simantics-1.10/org.simantics.sysdyn.ui/icons/bullet_gray.png new file mode 100644 index 0000000000000000000000000000000000000000..6f58b930c6163ab61e1b45d215a26cda319f848f GIT binary patch literal 303 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPggqW?l{<(K9WF?f`|>d%8G=Se$-4 z=^$r|fr!iT)c!@^Z*=7@VV(Wq!LsTmQR$L&a*PmzL-6&|@KDjd#|Jj)+_mUq_~2Qk zcx=Vgpc&64FPkWyFP?DaB%ce5B1?;af|5dK?fuKDleV0*oRZqPNMpk~?LFVkB9%_o tNw7`0qVjO>_S@UOmfwA2|MYo-zGYNGuEs{O2%ys$JYD@<);T3K0RT;NbcX-{ literal 0 HcmV?d00001 diff --git a/simantics-1.10/org.simantics.sysdyn.ui/icons/bullet_green.png b/simantics-1.10/org.simantics.sysdyn.ui/icons/bullet_green.png new file mode 100644 index 0000000000000000000000000000000000000000..1b5409f3965b613add2b1f83b061d60abb6b4ba7 GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|*pj^6T^Rm@ z;DWu&Cj&(|3p^r=85p>QL70(Y)*K0-AbW|YuPggqW?l|4KBeAsCP1Nco-U3d7N_4% zvgSJEAkm_}FH2EOD?|B_V$K(VolfT-TCUO2X=#wya6$S;MVpJ@!R>B~FTQzK!LU8x z%@O`(KPB1zCGt%A(Z;gx2|H8JuH>8NMHz2+T{sl$cyGyKy-j(>RL?!wAFh7jBHvj+t literal 0 HcmV?d00001 diff --git a/simantics-1.10/org.simantics.sysdyn.ui/plugin.xml b/simantics-1.10/org.simantics.sysdyn.ui/plugin.xml index 46659c96..b03868c1 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/plugin.xml +++ b/simantics-1.10/org.simantics.sysdyn.ui/plugin.xml @@ -801,6 +801,23 @@ + + + + + + + + + + ()), + jfree.Dataset_renderer, renderer); + + GraphUtils.create2(g, jfree.XYPlot, + l0.HasName, "XYPlot" + UUID.randomUUID().toString(), + l0.PartOf, jfreechart, + jfree.Plot_domainAxis, domainAxis, + jfree.Plot_rangeAxis, rangeAxis, + jfree.Plot_rangeAxisList, ListUtils.create(g, Collections.singletonList(rangeAxis)), + l0.ConsistsOf, dataset, + l0.ConsistsOf, domainAxis, + l0.ConsistsOf, rangeAxis); + } + + }); + + + + return null; + } +} \ No newline at end of file diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewSharedFunctionLibraryHandler.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewSharedFunctionLibraryHandler.java index 5eba69cd..ab79d1f8 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewSharedFunctionLibraryHandler.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewSharedFunctionLibraryHandler.java @@ -17,7 +17,7 @@ import org.eclipse.jface.viewers.ISelection; import org.eclipse.ui.handlers.HandlerUtil; import org.simantics.browsing.ui.common.node.AbstractNode; import org.simantics.db.Resource; -import org.simantics.ui.utils.AdaptionUtils; +import org.simantics.utils.ui.AdaptionUtils; /** * Creates a new shared function library. diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewXYLineChartHandler.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewXYLineChartHandler.java index c2aac244..bb872cf2 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewXYLineChartHandler.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/handlers/newComponents/NewXYLineChartHandler.java @@ -32,7 +32,7 @@ import org.simantics.layer0.utils.direct.GraphUtils; import org.simantics.sysdyn.JFreeChartResource; import org.simantics.sysdyn.ui.browser.nodes.ChartsFolder; import org.simantics.ui.SimanticsUI; -import org.simantics.ui.utils.AdaptionUtils; +import org.simantics.utils.ui.AdaptionUtils; /** * Handler for creating a new XYLineChart in model browser diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/ModuleInputTab.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/ModuleInputTab.java index c4c92ac2..0b5b3d68 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/ModuleInputTab.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/ModuleInputTab.java @@ -68,6 +68,9 @@ public class ModuleInputTab extends LabelPropertyTabContributor { if(instanceOf == null) return result; Resource configuration = graph.getSingleObject(instanceOf, sr2.IsDefinedBy); for(Resource input : graph.syncRequest(new ObjectsWithType(configuration, l0.ConsistsOf, sr.Input))) { + if(!graph.getObjects(input, sr.Variable_isHeadOf).isEmpty()) + continue; // Only inputs with tail dependencies allowed. + Resource dependency = null; for(Resource dep : graph.getObjects(module, sr.Variable_isHeadOf)) { Resource refersTo = graph.getPossibleObject(dep, sr.Dependency_refersTo); diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/SensitivityAnalysisExperimentTab.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/SensitivityAnalysisExperimentTab.java index 701e0cb8..f3caa587 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/SensitivityAnalysisExperimentTab.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/SensitivityAnalysisExperimentTab.java @@ -104,6 +104,26 @@ public class SensitivityAnalysisExperimentTab extends LabelPropertyTabContributo numValues.setInputValidator(new IntegerValidator()); numValues.setColorProvider(new SysdynBasicColorProvider(new LocalResourceManager(JFaceResources.getResources(), numValues.getWidget()))); + // mean + label = new Label(composite, SWT.NONE); + label.setText("Mean"); + + TrackedText mean = new TrackedText(composite, support, SWT.BORDER); + mean.setTextFactory(new DoublePropertyFactory(SysdynResource.URIs.SensitivityAnalysisExperiment_mean)); + mean.addModifyListener(new DoublePropertyModifier(context, SysdynResource.URIs.SensitivityAnalysisExperiment_mean)); + mean.setInputValidator(new DoubleValidator()); + mean.setColorProvider(new SysdynBasicColorProvider(new LocalResourceManager(JFaceResources.getResources(), mean.getWidget()))); + + // standard deviation + label = new Label(composite, SWT.NONE); + label.setText("Standard deviation"); + + TrackedText stdDeviation = new TrackedText(composite, support, SWT.BORDER); + stdDeviation.setTextFactory(new DoublePropertyFactory(SysdynResource.URIs.SensitivityAnalysisExperiment_stdDeviation)); + stdDeviation.addModifyListener(new DoublePropertyModifier(context, SysdynResource.URIs.SensitivityAnalysisExperiment_stdDeviation)); + stdDeviation.setInputValidator(new DoubleValidator()); + stdDeviation.setColorProvider(new SysdynBasicColorProvider(new LocalResourceManager(JFaceResources.getResources(), stdDeviation.getWidget()))); + // Scrolled composite settings sc.setContent(composite); sc.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/StockExpression.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/StockExpression.java index 23ef6ea1..0c8d1c63 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/StockExpression.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/StockExpression.java @@ -138,7 +138,7 @@ public class StockExpression implements IExpression { @Override public void save(final Resource expression, Map data) { final String currentText = this.expression.getExpression(); - if(currentText != null) { + if(currentText != null && !currentText.equals(data.get("initialEquation"))) { SimanticsUI.getSession().asyncRequest(new WriteRequest() { @Override diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/SensitivityDataset.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/SensitivityDataset.java new file mode 100644 index 00000000..970185eb --- /dev/null +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/SensitivityDataset.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * Copyright (c) 2013 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.sysdyn.ui.trend; + +import java.awt.BasicStroke; +import java.awt.Paint; +import java.util.ArrayList; +import java.util.Collections; + +import javax.swing.SwingUtilities; + +import org.jfree.chart.ChartColor; +import org.jfree.chart.renderer.AbstractRenderer; +import org.jfree.chart.renderer.xy.DeviationRenderer; +import org.jfree.data.general.Dataset; +import org.jfree.data.xy.YIntervalSeries; +import org.jfree.data.xy.YIntervalSeriesCollection; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.DisposableListener; +import org.simantics.db.exception.DatabaseException; +import org.simantics.jfreechart.chart.IRenderer; +import org.simantics.ui.SimanticsUI; +import org.simantics.utils.datastructures.Pair; + +public class SensitivityDataset extends XYDataset { + + DeviationRenderer renderer; + + public SensitivityDataset(ReadGraph graph, Resource resource) throws DatabaseException { + super(graph, resource); + } + + @Override + public Dataset getDataset() { + if(dataset == null) { + dataset = new YIntervalSeriesCollection(); + } + + if(datasetListener == null || datasetListener.isDisposed()) { + SimanticsUI.getSession().asyncRequest(getDatasetRequest(), getDatasetListener()); + } + + if(timeListener == null || timeListener.isDisposed()) { + SimanticsUI.getSession().asyncRequest(getTimeRequest(), getTimeListener()); + } + return dataset; + } + + @Override + public AbstractRenderer getRenderer() { + if(renderer == null) + renderer = new DeviationRenderer(true, false); + return renderer; + } + + @Override + protected DisposableListener, IRenderer>> getDatasetListener() { + if(datasetListener == null || datasetListener.isDisposed()) { + datasetListener = new SensitivityDatasetListener(); + } + return datasetListener; + } + + private class SensitivityDatasetListener extends DisposableListener, IRenderer>> { + + @Override + public void execute(Pair, IRenderer> result) { + final ArrayList series = result.first; + + // Modify series in AWT thread to avoid synchronization problems + SwingUtilities.invokeLater(new Runnable() { + + @Override + public void run() { + + if(dataset == null || !(dataset instanceof YIntervalSeriesCollection)) + return; + + YIntervalSeriesCollection ds = (YIntervalSeriesCollection)dataset; + + DeviationRenderer dr = (DeviationRenderer)getRenderer(); + Paint[] paints = { + ChartColor.LIGHT_RED, + ChartColor.LIGHT_YELLOW, + ChartColor.LIGHT_GREEN, + ChartColor.LIGHT_BLUE, + ChartColor.LIGHT_GRAY + }; + for(int i = 0; i < paints.length; i++) { + dr.setSeriesStroke(i, new BasicStroke(2F, 1, 1)); + dr.setSeriesPaint(i, paints[i]); + dr.setSeriesFillPaint(i, paints[i]); + } + dr.setAlpha(1); + + // Remove all series + for(int i = ds.getSeriesCount() - 1; i >= 0; i-- ) { + ds.removeSeries(ds.getSeries(i)); + } + + int n = series.size(); + if(n < 1) + return; + + int length = series.get(0).values[0].length; + + YIntervalSeries median = new YIntervalSeries("Median"); + YIntervalSeries p100 = new YIntervalSeries("100%"); + YIntervalSeries p75 = new YIntervalSeries("75%"); + YIntervalSeries p50 = new YIntervalSeries("50%"); + YIntervalSeries p25 = new YIntervalSeries("25%"); + + ArrayList sorter = new ArrayList(); + for(int i = 0; i < length; i++) { + sorter.clear(); + for(int j = 0; j < n; j++) { + sorter.add(series.get(j).values[1][i]); // values is a two-dimensional array. 0 dimension == times, 1 == values + } + Collections.sort(sorter); + + median.add( + series.get(0).values[0][i], + sorter.get(sorter.size()/2), + sorter.get(sorter.size()/2), + sorter.get(sorter.size()/2) + ); + + if(n > 8) + p25.add( + series.get(0).values[0][i], + sorter.get(sorter.size()/2), + sorter.get(sorter.size() / 2 - (int)(sorter.size() * 0.25) / 2), + sorter.get(sorter.size() / 2 + (int)(sorter.size() * 0.25) / 2) + ); + + if(n > 4) + p50.add( + series.get(0).values[0][i], + sorter.get(sorter.size()/2), + sorter.get(sorter.size() / 2 - (int)(sorter.size() * 0.5) / 2), + sorter.get(sorter.size() / 2 + (int)(sorter.size() * 0.5) / 2) + ); + + if(n > 8) + p75.add( + series.get(0).values[0][i], + sorter.get(sorter.size()/2), + sorter.get(sorter.size() / 2 - (int)(sorter.size() * 0.75) / 2), + sorter.get(sorter.size() / 2 + (int)(sorter.size() * 0.75) / 2) + ); + + p100.add( + series.get(0).values[0][i], + sorter.get(sorter.size()/2), + sorter.get(0), + sorter.get(sorter.size() - 1) + ); + } + + ds.addSeries(median); + if(n > 8) + ds.addSeries(p25); + if(n > 4) + ds.addSeries(p50); + if(n > 8) + ds.addSeries(p75); + ds.addSeries(p100); + + } + }); + } + + @Override + public void exception(Throwable t) { + t.printStackTrace(); + } + + } +} diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/XYDataset.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/XYDataset.java index f6a275c2..9eac19cf 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/XYDataset.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/trend/XYDataset.java @@ -39,7 +39,7 @@ import org.simantics.db.layer0.exception.MissingVariableException; import org.simantics.db.layer0.request.PossibleActiveExperiment; import org.simantics.db.layer0.variable.Variable; import org.simantics.db.layer0.variable.Variables; -import org.simantics.db.procedure.Listener; +import org.simantics.db.common.procedure.adapter.DisposableListener; import org.simantics.db.request.Read; import org.simantics.diagram.G2DUtils; import org.simantics.jfreechart.chart.AbstractDataset; @@ -62,198 +62,217 @@ import org.simantics.utils.datastructures.Pair; */ public class XYDataset extends AbstractDataset implements org.simantics.jfreechart.chart.XYDataset{ - private IRenderer renderer; + protected IRenderer renderer; public XYDataset(ReadGraph graph, final Resource datasetResource) throws DatabaseException { super(graph, datasetResource); } - private DefaultXYDataset dataset; - private DataSetListener datasetListener; - private TimeListener timeListener; - - @Override - public Dataset getDataset() { - if(dataset == null) { - dataset = new DefaultXYDataset(); - } - + protected Dataset dataset; + protected DisposableListener, IRenderer>> datasetListener; + protected DisposableListener timeListener; + + protected DisposableListener, IRenderer>> getDatasetListener() { if(datasetListener == null || datasetListener.isDisposed()) { datasetListener = new DataSetListener(); - SimanticsUI.getSession().asyncRequest(new Read, IRenderer>>() { - - @Override - public Pair, IRenderer> perform(ReadGraph graph) throws DatabaseException { - JFreeChartResource jfree = JFreeChartResource.getInstance(graph); - - // Renderer - IRenderer renderer = null; - Resource rendererResource = graph.getPossibleObject(resource, jfree.Dataset_renderer); - if(rendererResource != null) - renderer = graph.adapt(rendererResource, IRenderer.class); - - ArrayList series = new ArrayList(); - - String realizationURI = getRealizationURI(graph); - - if(realizationURI == null) - return new Pair, IRenderer>(series, renderer); // No experiment -> No results + } + return datasetListener; + } - // Get a variable for the x-axis (if not time) - double[] domainValues = null; - Resource domainAxis = graph.getPossibleObject(resource, jfree.Dataset_mapToDomainAxis); - if(domainAxis != null) { - String rvi = graph.getPossibleRelatedValue(domainAxis, jfree.variableRVI); - if(rvi != null && !rvi.isEmpty()) { - try { - Variable domainVariable = Variables.getVariable(graph, realizationURI + rvi); - Variable valuesVariable = domainVariable.browsePossible(graph, "#" + Functions.VALUES +"#"); - if(valuesVariable != null) { - double[][] valuesArray = valuesVariable.getValue(graph); - if(valuesArray.length > 0) - domainValues = valuesArray[0]; - } - } catch(MissingVariableException e) { - //Do nothing, use time as domain axis + protected DisposableListener getTimeListener() { + if(timeListener == null || timeListener.isDisposed()) { + timeListener = new TimeListener(); + } + return timeListener; + } + + protected Read, IRenderer>> getDatasetRequest() { + return new Read, IRenderer>>() { + + @Override + public Pair, IRenderer> perform(ReadGraph graph) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + + // Renderer + IRenderer renderer = null; + Resource rendererResource = graph.getPossibleObject(resource, jfree.Dataset_renderer); + if(rendererResource != null) + renderer = graph.adapt(rendererResource, IRenderer.class); + + ArrayList series = new ArrayList(); + + String realizationURI = getRealizationURI(graph); + + if(realizationURI == null) + return new Pair, IRenderer>(series, renderer); // No experiment -> No results + + // Get a variable for the x-axis (if not time) + double[] domainValues = null; + Resource domainAxis = graph.getPossibleObject(resource, jfree.Dataset_mapToDomainAxis); + if(domainAxis != null) { + String rvi = graph.getPossibleRelatedValue(domainAxis, jfree.variableRVI); + if(rvi != null && !rvi.isEmpty()) { + try { + Variable domainVariable = Variables.getVariable(graph, realizationURI + rvi); + Variable valuesVariable = domainVariable.browsePossible(graph, "#" + Functions.VALUES +"#"); + if(valuesVariable != null) { + double[][] valuesArray = valuesVariable.getValue(graph); + if(valuesArray.length > 0) + domainValues = valuesArray[0]; } + } catch(MissingVariableException e) { + //Do nothing, use time as domain axis } } + } - Resource seriesList = graph.getPossibleObject(resource, jfree.Dataset_seriesList); + Resource seriesList = graph.getPossibleObject(resource, jfree.Dataset_seriesList); - // Get properties for all series - if(seriesList != null) { - for(Resource r : ListUtils.toList(graph, seriesList)) { - String rvi = graph.getPossibleRelatedValue(r, jfree.variableRVI); - if(rvi == null) - continue; + // Get properties for all series + if(seriesList != null) { + for(Resource r : ListUtils.toList(graph, seriesList)) { + String rvi = graph.getPossibleRelatedValue(r, jfree.variableRVI); + if(rvi == null) + continue; - try { - // Get visual properties - Integer width = graph.getPossibleRelatedValue(r, jfree.Series_lineWidth, Bindings.INTEGER); - if(width == null) width = 1; + try { + // Get visual properties + Integer width = graph.getPossibleRelatedValue(r, jfree.Series_lineWidth, Bindings.INTEGER); + if(width == null) width = 1; - Resource c = graph.getPossibleObject(r, jfree.color); - Color color = c == null ? null : G2DUtils.getColor(graph, c); - - String label = graph.getPossibleRelatedValue(r, Layer0.getInstance(graph).HasLabel); + Resource c = graph.getPossibleObject(r, jfree.color); + Color color = c == null ? null : G2DUtils.getColor(graph, c); + + String label = graph.getPossibleRelatedValue(r, Layer0.getInstance(graph).HasLabel); - // Get a variable for the series - Variable v = Variables.getVariable(graph, realizationURI + rvi); - if(v == null) - return new Pair, IRenderer>(series, renderer); + // Get a variable for the series + Variable v = Variables.getVariable(graph, realizationURI + rvi); + if(v == null) + return new Pair, IRenderer>(series, renderer); - // Get values - Variable dsVariable = v.browsePossible(graph, "#" + Functions.ACTIVE_DATASETS + "#"); - Object object = null; - if(dsVariable != null) - object = dsVariable.getValue(graph); + // Get values + Variable dsVariable = v.browsePossible(graph, "#" + Functions.ACTIVE_DATASETS + "#"); + Object object = null; + if(dsVariable != null) + object = dsVariable.getValue(graph); - if(object == null || !(object instanceof ArrayList)) - return new Pair, IRenderer>(series, renderer); + if(object == null || !(object instanceof ArrayList)) + return new Pair, IRenderer>(series, renderer); - ArrayList datasets = new ArrayList(); + ArrayList datasets = new ArrayList(); - for(Object o : (ArrayList)object) { - if(o instanceof SysdynDataSet) - datasets.add((SysdynDataSet)o); - } + for(Object o : (ArrayList)object) { + if(o instanceof SysdynDataSet) + datasets.add((SysdynDataSet)o); + } - String[] filter = graph.getPossibleRelatedValue(r, jfree.variableFilter); - if(filter != null) { - ArrayList result2 = VariableRVIUtils.getDataset(datasets, filter); - if(result2 != null) { - datasets = result2; - } + String[] filter = graph.getPossibleRelatedValue(r, jfree.variableFilter); + if(filter != null) { + ArrayList result2 = VariableRVIUtils.getDataset(datasets, filter); + if(result2 != null) { + datasets = result2; } + } + + for(SysdynDataSet dataset : datasets) { + double[] va = dataset.values; - for(SysdynDataSet dataset : datasets) { - double[] va = dataset.values; - - // Get domain axis values (time OR other variable) - double[] ta; - if(domainValues != null) { - ta = domainValues; - - // If domainAxis is other than time, parameter values size is different. - if(domainValues.length > va.length) { - double value = va[0]; - va = new double[domainValues.length]; - for(int i = 0; i < domainValues.length; i++) - va[i] = value; - } - - // If domainAxis is a parameter, the domainValues array is too short - if(domainValues.length < va.length && domainValues.length == 2 && domainValues[0] == domainValues[1]) { - double value = domainValues[0]; - ta = new double[va.length]; - for(int i = 0; i < va.length; i++) - ta[i] = value; - } - - } else { - ta = dataset.times; + // Get domain axis values (time OR other variable) + double[] ta; + if(domainValues != null) { + ta = domainValues; + + // If domainAxis is other than time, parameter values size is different. + if(domainValues.length > va.length) { + double value = va[0]; + va = new double[domainValues.length]; + for(int i = 0; i < domainValues.length; i++) + va[i] = value; } - if(ta!=null && va!=null && (va.length == ta.length)) { - // Add series if everything OK - String name = dataset.name; - if(label != null) - name = label; - if(dataset.result != null && !dataset.result.isEmpty()) - name = name + " : " + dataset.result; - series.add(new TempSeries(name, new double[][] {ta, va}, width, color)); - if(ta.length == 0 || va.length == 0) - System.out.println(dataset.name + " : " + dataset.result + ". Sizes: " + va.length + " and " + ta.length); + // If domainAxis is a parameter, the domainValues array is too short + if(domainValues.length < va.length && domainValues.length == 2 && domainValues[0] == domainValues[1]) { + double value = domainValues[0]; + ta = new double[va.length]; + for(int i = 0; i < va.length; i++) + ta[i] = value; } + + } else { + ta = dataset.times; } - } catch (MissingVariableException e) { - // Do nothing, if variable was not found. Move on to the next series + if(ta!=null && va!=null && (va.length == ta.length)) { + // Add series if everything OK + String name = dataset.name; + if(label != null) + name = label; + if(dataset.result != null && !dataset.result.isEmpty()) + name = name + " : " + dataset.result; + series.add(new TempSeries(name, new double[][] {ta, va}, width, color)); + if(ta.length == 0 || va.length == 0) + System.out.println(dataset.name + " : " + dataset.result + ". Sizes: " + va.length + " and " + ta.length); + } } + + } catch (MissingVariableException e) { + // Do nothing, if variable was not found. Move on to the next series } } - return new Pair, IRenderer>(series, renderer); } - - }, datasetListener); - } - - if(timeListener == null || timeListener.isDisposed()) { - timeListener = new TimeListener(); - SimanticsUI.getSession().asyncRequest(new Read() { - @Override - public Double perform(ReadGraph graph) throws DatabaseException { - JFreeChartResource jfree = JFreeChartResource.getInstance(graph); - // Get properties for all series - Resource series = graph.getPossibleObject(resource, jfree.Dataset_seriesList); - if(series != null) { - List seriesList = ListUtils.toList(graph, series); - if(seriesList != null) { - String realizationURI = getRealizationURI(graph); - for(Resource r : seriesList) { - String rvi = graph.getPossibleRelatedValue(r, jfree.variableRVI); - if(rvi == null) - continue; - try { - // Get a variable for the experiment run - Variable v = Variables.getVariable(graph, realizationURI); - if(v == null) - return null; - Variable timeVar = v.browsePossible(graph, "#" + Functions.TIME + "#"); - if(timeVar != null) - return timeVar.getValue(graph, Bindings.DOUBLE); - } catch (MissingVariableException e) { - // Do nothing, if variable was not found. - } + return new Pair, IRenderer>(series, renderer); + } + }; + } + + protected Read getTimeRequest() { + return new Read() { + @Override + public Double perform(ReadGraph graph) throws DatabaseException { + JFreeChartResource jfree = JFreeChartResource.getInstance(graph); + // Get properties for all series + Resource series = graph.getPossibleObject(resource, jfree.Dataset_seriesList); + if(series != null) { + List seriesList = ListUtils.toList(graph, series); + if(seriesList != null) { + String realizationURI = getRealizationURI(graph); + for(Resource r : seriesList) { + String rvi = graph.getPossibleRelatedValue(r, jfree.variableRVI); + if(rvi == null) + continue; + try { + // Get a variable for the experiment run + Variable v = Variables.getVariable(graph, realizationURI); + if(v == null) + return null; + Variable timeVar = v.browsePossible(graph, "#" + Functions.TIME + "#"); + if(timeVar != null) + return timeVar.getValue(graph, Bindings.DOUBLE); + } catch (MissingVariableException e) { + // Do nothing, if variable was not found. } } } - return null; } + return null; + } + + }; + } - }, timeListener); + @Override + public Dataset getDataset() { + if(dataset == null) { + dataset = new DefaultXYDataset(); + } + + if(datasetListener == null || datasetListener.isDisposed()) { + SimanticsUI.getSession().asyncRequest(getDatasetRequest(), getDatasetListener()); + } + + if(timeListener == null || timeListener.isDisposed()) { + SimanticsUI.getSession().asyncRequest(getTimeRequest(), getTimeListener()); } return dataset; } @@ -263,7 +282,7 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha * @author Teemu Lempinen * */ - private class TimeMarker extends ValueMarker { + protected class TimeMarker extends ValueMarker { private static final long serialVersionUID = 2018755066561629172L; public TimeMarker(double value, Paint paint, Stroke stroke) { @@ -271,18 +290,7 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha } } - private class DataSetListener implements Listener, IRenderer>> { - - private boolean disposed = false; - - public void dispose() { - disposed = true; - } - - @Override - public boolean isDisposed() { - return disposed; - } + private class DataSetListener extends DisposableListener, IRenderer>> { @Override public void execute(Pair, IRenderer> result) { @@ -295,7 +303,12 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha @Override public void run() { + if(dataset == null || !(dataset instanceof DefaultXYDataset)) + return; + + DefaultXYDataset ds = (DefaultXYDataset)dataset; org.jfree.chart.plot.XYPlot plot = ((AbstractXYItemRenderer)getRenderer()).getPlot(); + if(plot != null) { /* * Drawing supplier with a modified first yellow. The default first @@ -313,14 +326,14 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha plot.setDrawingSupplier(drawingsupplier); } // Remove all series - for(int i = dataset.getSeriesCount() - 1; i >= 0; i-- ) { - dataset.removeSeries(dataset.getSeriesKey(i)); + for(int i = ds.getSeriesCount() - 1; i >= 0; i-- ) { + ds.removeSeries(ds.getSeriesKey(i)); } // Add found series for(int i = 0; i < series.size(); i++) { TempSeries s = series.get(i); - dataset.addSeries(s.name, s.values); + ds.addSeries(s.name, s.values); getRenderer().setSeriesStroke(i, new BasicStroke((float)s.width)); getRenderer().setSeriesPaint(i, s.color); } @@ -341,10 +354,9 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha * @author Teemu Lempinen * */ - private class TimeListener implements Listener { + protected class TimeListener extends DisposableListener { private ValueMarker marker; - private boolean disposed = false; private Stroke dashStroke = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] {5.0f, 3.0f, 1.0f, 3.0f}, 0.0f); @@ -353,7 +365,7 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha } public void dispose() { - this.disposed = true; + super.dispose(); if(marker != null) { org.jfree.chart.plot.XYPlot plot = ((AbstractXYItemRenderer)getRenderer()).getPlot(); if(plot != null) @@ -361,11 +373,6 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha } } - @Override - public boolean isDisposed() { - return disposed; - } - @Override public void execute(final Double time) { // Modify in AWT thread to avoid synchronization problems @@ -421,7 +428,7 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha * @author Teemu Lempinen * */ - private class TempSeries { + protected class TempSeries { public double[][] values; public String name; public int width; @@ -472,7 +479,7 @@ public class XYDataset extends AbstractDataset implements org.simantics.jfreecha * @return realization uri for current dataset resource * @throws DatabaseException */ - private String getRealizationURI(ReadGraph graph) throws DatabaseException { + protected String getRealizationURI(ReadGraph graph) throws DatabaseException { if(resource == null) return null; diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ExpressionUtils.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ExpressionUtils.java index 7fcf67c1..c6a513d1 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ExpressionUtils.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/ExpressionUtils.java @@ -570,8 +570,8 @@ public class ExpressionUtils { return ReferenceOption.DOES_NOT_EXIST; else if(Boolean.TRUE.equals(element)) return ReferenceOption.CANNOT_BE_CONNECTED; - else if(element instanceof Variable) { - if(element instanceof Enumeration || element instanceof Sheet) + else if(element instanceof Variable || element instanceof Module) { + if(element instanceof Enumeration || element instanceof Sheet || element instanceof Module || parts.length > 1) return ReferenceOption.CANNOT_BE_CONNECTED; else return ReferenceOption.CAN_BE_CONNECTED; diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/imports/ImportUtils.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/imports/ImportUtils.java index d69272b1..c576dd7c 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/imports/ImportUtils.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/utils/imports/ImportUtils.java @@ -8,6 +8,7 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - Bug #4192 *******************************************************************************/ package org.simantics.sysdyn.ui.utils.imports; @@ -40,6 +41,10 @@ import org.simantics.db.common.request.WriteResultRequest; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.exception.ResourceNotFoundException; +import org.simantics.db.layer0.adapter.impl.DefaultPasteImportAdvisor; +import org.simantics.db.layer0.migration.MigrationState; +import org.simantics.db.layer0.migration.MigrationStateKeys; +import org.simantics.db.layer0.migration.MigrationUtils; import org.simantics.db.layer0.util.RemoverUtil; import org.simantics.db.request.Read; import org.simantics.issues.common.AllBatchIssueSources; @@ -138,18 +143,22 @@ public class ImportUtils { Activator.getDefault().getPreferenceStore().setValue(IMPORTMODELTPATH, (new File(path)).getParent()); + MigrationState state = MigrationUtils.newState(); + state.setProperty(MigrationStateKeys.BASE_URI, SysdynResource.URIs.Migration); + state.setProperty(MigrationStateKeys.UPDATE_DEPENDENCIES, Boolean.FALSE); - - HashMap> handlers = new HashMap>(); - handlers.put("sysdynModel:1", new SysdynImportFormatHandler(project, SysdynResource.URIs.from1$6to1$7, monitor)); - - Object result = ImportUtils.readFile(path, handlers); + Resource result = null; + try { + result = MigrationUtils.importMigrated(monitor, SimanticsUI.getSession(), new File(path), state, new DefaultPasteImportAdvisor(project), project); + } catch (Exception e1) { + e1.printStackTrace(); + } if(result == null || !(result instanceof Resource)) { return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Import model failed: File could not be read.", null); } else { try { - final Resource ModelRoot = (Resource) result; + final Resource ModelRoot = result; IStatus status = SimanticsUI.getSession().syncRequest(new WriteResultRequest() { @Override @@ -352,18 +361,22 @@ public class ImportUtils { Activator.getDefault().getPreferenceStore().setValue(IMPORTMODULETPATH, (new File(path)).getParent()); - // Handler for importing modules - HashMap> handlers = new HashMap>(); - handlers.put("sysdynModule:1", new SysdynImportFormatHandler(model, SysdynResource.URIs.from1$6to1$7, monitor)); + MigrationState state = MigrationUtils.newState(); + state.setProperty(MigrationStateKeys.BASE_URI, SysdynResource.URIs.Migration); + state.setProperty(MigrationStateKeys.UPDATE_DEPENDENCIES, Boolean.FALSE); - // Read module file - Object result = ImportUtils.readFile(path, handlers); + Resource result = null; + try { + result = MigrationUtils.importMigrated(monitor, SimanticsUI.getSession(), new File(path), state, new DefaultPasteImportAdvisor(model), model); + } catch (Exception e1) { + e1.printStackTrace(); + } - if(result == null || !(result instanceof Resource)) { + if(result == null) { return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Import module failed: Module could not be imported.", null); } else { - final Resource ModuleRoot = (Resource) result; + final Resource ModuleRoot = result; // Check that the imported file actually was a module. Display error message otherwise. try { subTask(monitor, "Validate model"); @@ -415,15 +428,19 @@ public class ImportUtils { // Ensure that shared functions ontology exists ensureSharedOntologies(); + + MigrationState state = MigrationUtils.newState(); + state.setProperty(MigrationStateKeys.BASE_URI, SysdynResource.URIs.Migration); + state.setProperty(MigrationStateKeys.UPDATE_DEPENDENCIES, Boolean.FALSE); - // Handler for importing function libraries - HashMap> handlers = new HashMap>(); - handlers.put("sysdynFunctionLibrary:1", new SysdynImportFormatHandler(functionLibrary, SysdynResource.URIs.from1$6to1$7, monitor, new SysdynFunctionLibraryImportAdvisor(functionLibrary))); - - // Read function library file - Object result = ImportUtils.readFile(path, handlers); + Resource result = null; + try { + result = MigrationUtils.importMigrated(monitor, SimanticsUI.getSession(), new File(path), state, new DefaultPasteImportAdvisor(functionLibrary), functionLibrary); + } catch (Exception e1) { + e1.printStackTrace(); + } - if(result == null || !(result instanceof Resource)) { + if(result == null) { return new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Import Function library failed: Function library not be imported.", null); } else { final Resource FunctionLibraryRoot = (Resource) result; diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/EnumerationFunction.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/EnumerationFunction.java index a6aab02e..96b687ca 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/EnumerationFunction.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/EnumerationFunction.java @@ -17,10 +17,10 @@ import java.util.List; import org.simantics.db.Issue; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; +import org.simantics.db.common.issue.StandardIssue; import org.simantics.db.common.utils.ListUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variable; -import org.simantics.issues.common.StandardIssue; import org.simantics.scl.reflection.annotations.SCLValue; import org.simantics.sysdyn.SysdynResource; diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ExpressionIssueFunction.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ExpressionIssueFunction.java index 782fb3cf..8a55a522 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ExpressionIssueFunction.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/ExpressionIssueFunction.java @@ -17,10 +17,10 @@ import java.util.List; import org.simantics.db.Issue; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; +import org.simantics.db.common.issue.StandardIssue; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variable; import org.simantics.issues.common.IssueUtils; -import org.simantics.issues.common.StandardIssue; import org.simantics.scl.reflection.annotations.SCLValue; import org.simantics.sysdyn.SysdynResource; diff --git a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/IssueWithStringContext.java b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/IssueWithStringContext.java index a491add4..906124fb 100644 --- a/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/IssueWithStringContext.java +++ b/simantics-1.10/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/validation/IssueWithStringContext.java @@ -19,10 +19,10 @@ import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; +import org.simantics.db.common.issue.StandardIssue; import org.simantics.db.common.utils.ListUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.variable.Variable; -import org.simantics.issues.common.StandardIssue; import org.simantics.layer0.Layer0; import org.simantics.sysdyn.SysdynResource; diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/IndexVariable.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/IndexVariable.java index f56bc881..7a336dc2 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/IndexVariable.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/IndexVariable.java @@ -104,8 +104,10 @@ public abstract class IndexVariable extends AbstractPropertyVariable { } @Override public void unregistered() { - unregisterSubscription(subscription); - subscription = null; + if(subscription != null) { + unregisterSubscription(subscription); + subscription = null; + } } @SuppressWarnings("unchecked") diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValueIndexVariable.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValueIndexVariable.java index 9ce2169b..9834ff5d 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValueIndexVariable.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/ValueIndexVariable.java @@ -36,7 +36,8 @@ public class ValueIndexVariable extends IndexVariable { for(int i = 0; i < variableNames.size(); i++) { for(SysdynResult r : results) { if(experiment instanceof SysdynGameExperiment) { - result[i] = ((SysdynGameExperiment)experiment).getCurrentValue(variableNames.get(i)); + Double d = ((SysdynGameExperiment)experiment).getCurrentValue(variableNames.get(i)); + result[i] = d != null ? d : 0; } else { SysdynDataSet ds = r.getDataSet(variableNames.get(i)); if(ds != null && ds.values != null && ds.values.length > 0) { diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/VariableValueSubscription.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/VariableValueSubscription.java index 1f918aa7..716fd588 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/VariableValueSubscription.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/VariableValueSubscription.java @@ -18,6 +18,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.simantics.db.Session; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.utils.Logger; import org.simantics.db.exception.DatabaseException; import org.simantics.db.procedure.Listener; import org.simantics.db.request.ExternalRead; @@ -48,11 +49,14 @@ public class VariableValueSubscription { return request; } - - public void update() { - T value = variable.getValue(); - fireValue(value); - } + public void update() { + try { + T value = variable.getValue(); + fireValue(value); + } catch (Throwable e) { + fireException(e); + } + } void fireValue(T value) { if (listener != null) @@ -62,8 +66,12 @@ public class VariableValueSubscription { void fireException(Throwable t) { if (listener != null && excepted.compareAndSet(false, true)) listener.exception(t); + else + // Can't invoke listener.exception multiple times, but logging + // further exceptions anyway. + Logger.defaultLogError(t); } - + public void setListener(Listener listener) { this.listener = listener; } diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java index 093baadf..46433abd 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java @@ -449,23 +449,18 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, */ public synchronized void simulate(final IModelicaMonitor monitor, final IProgressMonitor progressMonitor) throws IOException { canceled = false; - progressMonitor.subTask("Write modelica classes"); // Write Modelica files - - String modelText = getModelicaCode(monitor, false, getOpenModelicaVersion()); if(modelText == null) return; - progressMonitor.worked(1); // Write initial files and add init-parameters progressMonitor.subTask("Write simulation files"); HashMap experimentParameters = getExperimentParameters(monitor); - // add loadFile script to load all related functions and function libraries String additionalScript = getAdditionalScripts(); @@ -473,7 +468,6 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, SimulationLocation simulationLocation = createSimulationFiles(sysdynModel, modelText, experimentParameters, additionalScript, false); progressMonitor.worked(1); - // Build the model and store previous model structure and inits that affect the building // If there is no exe file OR the model structure has not changed, no need to build boolean structureChanged = hasStructureChanged(modelText); @@ -501,7 +495,6 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, e.printStackTrace(); } } - progressMonitor.worked(1); if(simulationLocation != null && !canceled) { @@ -852,6 +845,17 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment, subscription.update(); skippedVariableUpdate = false; } + + public int numberOfSimulationRunSteps() { + /* + * 1. Write modelica files + * 2. Write other simulation files + * 3. Build model OR update parameters + * 4. Run modelica + * 5. Read results + */ + return 5; + } /* Experiment methods that are not used in this experiment */ diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java index dd8ffe26..c3c2e6f0 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java @@ -11,6 +11,10 @@ *******************************************************************************/ package org.simantics.sysdyn.manager; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -19,10 +23,13 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; +import org.simantics.databoard.Bindings; import org.simantics.db.AsyncReadGraph; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Session; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; import org.simantics.db.exception.DatabaseException; import org.simantics.db.procedure.AsyncListener; import org.simantics.db.request.Read; @@ -175,13 +182,23 @@ public class SysdynGameExperiment extends SysdynExperiment { SimulationLocation simulationLocation = createSimulationFiles(sysdynModel, modelText, inits, additionalScript, true); progressMonitor.worked(1); - + // Load precompiled fmu if structure has not changed and it has not yet been loaded + File fmu = null; + if(!sysdynModel.isStructureModified()) { + if(!simulationLocation.executableFile.isFile()) { + fmu = loadModelFmu(simulationLocation); + } else { + fmu = simulationLocation.executableFile; + } + } // Build the model and store previous model structure and inits that affect the building // If there is no exe file OR the model structure has not changed, no need to build - if (!simulationLocation.executableFile.isFile() || hasStructureChanged(modelText)) { + if (fmu == null && (!simulationLocation.executableFile.isFile() || hasStructureChanged(modelText))) { progressMonitor.subTask("Build model"); buildModel(simulationLocation, modelText, monitor); previousModelStructure = modelText; + + saveModelFmu(simulationLocation); } progressMonitor.worked(1); @@ -202,6 +219,81 @@ public class SysdynGameExperiment extends SysdynExperiment { simulate(false); } + /** + * Load fmu file from database, if it exists for the model of this experiment + * + * @param simulationLocation SimulationLocation indicating where the fmu should be loaded + * @return Loaded fmu or null if it was not loaded from database + */ + private File loadModelFmu(SimulationLocation simulationLocation) { + File fmu = null; + try { + final String fmuLocation = simulationLocation.executableFile.getAbsolutePath(); + fmu = session.syncRequest(new Read() { + @Override + public File perform(ReadGraph graph) throws DatabaseException { + File result = null; + FileOutputStream fos; + try { + fos = new FileOutputStream(fmuLocation); + byte[] fileBArray = graph.getPossibleRelatedValue( + getModel(), SysdynResource.getInstance(graph).SysdynModel_fmuFile, Bindings.BYTE_ARRAY); + + if(fileBArray != null) { + fos.write(fileBArray); + fos.close(); + result = new File(fmuLocation); + } else { + fos.close(); + return null; + } + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return result; + } + }); + } catch (DatabaseException e) { + e.printStackTrace(); + } + + return fmu; + } + + /** + * Save fmu file from simulationLocation to database + * @param simulationLocation Location for finding fmu + */ + private void saveModelFmu(SimulationLocation simulationLocation) { + final String fmuLocation = simulationLocation.executableFile.getAbsolutePath(); + session.asyncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + File file = new File(fmuLocation); + byte[] fileBArray = new byte[(int)file.length()]; + FileInputStream fis; + try { + fis = new FileInputStream(file); + + fis.read(fileBArray); + graph.claimLiteral( + getModel(), + SysdynResource.getInstance(graph).SysdynModel_fmuFile, + fileBArray, Bindings.BYTE_ARRAY); + fis.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + } + @Override public void simulateDuration(double duration) { @@ -414,11 +506,12 @@ public class SysdynGameExperiment extends SysdynExperiment { } public Double getCurrentValue(String name) { - Integer index = subscriptionIndexes.get(name); - if(index != null) { - return currentValues[index]; - } else { - return null; + if(subscriptionIndexes != null && name != null) { + Integer index = subscriptionIndexes.get(name); + if(index != null) { + return currentValues[index]; + } } + return null; } } diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java index 55a72243..29f9fc72 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynModel.java @@ -53,6 +53,7 @@ import org.simantics.sysdyn.adapter.VariableValueSubscription; import org.simantics.sysdyn.representation.Configuration; import org.simantics.sysdyn.representation.IElement; import org.simantics.sysdyn.representation.IndependentVariable; +import org.simantics.sysdyn.representation.Model; import org.simantics.sysdyn.representation.Module; import org.simantics.sysdyn.representation.ParameterOverride; import org.simantics.sysdyn.representation.Sheet; @@ -271,10 +272,19 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti */ public synchronized boolean update(ReadGraph graph) throws DatabaseException { if(mapping.isDomainModified()) { - structureModified = true; + + try { - mapping.updateRange(graph); + Collection updated = mapping.updateRange(graph); + + for(Object o : updated) { + if(!(o instanceof Model)) { + setStructureModified(true); + break; + } + } + } catch (MappingException e) { SysdynConsole.INSTANCE.message( "Error: Mapping is broken! Find the problem, " + @@ -305,7 +315,7 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti } else return false; - } + } /** * Update mapping. @@ -560,7 +570,7 @@ public class SysdynModel implements IMappingListener, IModel, VariableSubscripti return structureModified; } - public void setStructureModeified(boolean structureModified) { + public void setStructureModified(boolean structureModified) { this.structureModified = structureModified; } } diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynSensitivityAnalysisExperiment.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynSensitivityAnalysisExperiment.java index c7da1528..0d3d096b 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynSensitivityAnalysisExperiment.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynSensitivityAnalysisExperiment.java @@ -11,148 +11,304 @@ *******************************************************************************/ package org.simantics.sysdyn.manager; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; +import java.util.Random; import java.util.concurrent.ScheduledExecutorService; +import org.eclipse.core.runtime.IProgressMonitor; +import org.simantics.databoard.Bindings; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; -import org.simantics.simulation.experiment.IDynamicExperiment; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; +import org.simantics.modelica.IModelicaMonitor; +import org.simantics.modelica.ModelicaKeys; +import org.simantics.modelica.ModelicaManager; +import org.simantics.modelica.SimulationLocation; +import org.simantics.modelica.data.CSVSimulationResult; +import org.simantics.modelica.data.MatSimulationResult; +import org.simantics.modelica.data.SimulationResult; +import org.simantics.sysdyn.SysdynResource; /** * Sensitivity analysis experiment * @author Tuomas Miettinen * */ -public class SysdynSensitivityAnalysisExperiment extends SysdynExperiment implements IDynamicExperiment { +public class SysdynSensitivityAnalysisExperiment extends SysdynExperiment { public enum Distribution { UNIFORM, NORMAL } - private final Distribution propabilityDistribution = DEFAULT_PROPABILITY_DISTRIBUTION; + private Distribution propabilityDistribution = DEFAULT_PROPABILITY_DISTRIBUTION; + private double minValue = DEFAULT_MIN_VALUE; + private double maxValue = DEFAULT_MAX_VALUE; + private int numValues = DEFAULT_NUM_VALUES; + private String variedParameter = "Auxiliary1"; + private double mean = DEFAULT_MEAN; + public double stdDeviation = DEFAULT_STD_DEVIATION; + public static Distribution DEFAULT_PROPABILITY_DISTRIBUTION = Distribution.UNIFORM; public static double DEFAULT_MIN_VALUE = 1.0; public static double DEFAULT_MAX_VALUE = 3.0; public static int DEFAULT_NUM_VALUES = 3; - - private final Collection timeListeners = new ArrayList(); + public static double DEFAULT_MEAN = 0.0; + public static double DEFAULT_STD_DEVIATION = 1.0; ScheduledExecutorService playbackExecutionService; - //SensitivityAnalysisConfiguration playbackConfiguration; + private ArrayList results = null; public SysdynSensitivityAnalysisExperiment(Resource experiment, Resource model) { super(experiment, model); } + @Override + protected void runModelica(SimulationLocation simulationLocation, String modelText, IModelicaMonitor monitor, IProgressMonitor progressMonitor, HashMap experimentParameters, HashMap changes) throws IOException { + results = null; + + loadConfiguration(); + if (changes == null) { + changes = new HashMap(); + } + + String version = ModelicaManager.getOMCVersion(simulationLocation.omcHome); + experimentParameters.put(ModelicaManager.OMC_VERSION, version); - /** - * Interrupts a possible ongoing playback - * - * @param time - */ -// public void setTimeInterrupting(double time) { -// stopPlayback(); -// setTime(time); -// } -// -// /** -// * Sets a new time and continues playback from that point if -// * playback was running -// * @param time -// */ -// public void setTimeAndContinue(double time) { -// if(isPlaybackRunning()) { -// stopPlayback(); -// setTime(time); -// startPlayback(500); -// } else { -// setTime(time); -// } -// } -/* - private void setTime(double time) { - this.time = time; - resultsChanged(); - } + for (int i = 0; i < numValues; ++i) { + progressMonitor.subTask("Simulation iteration " + (i+1)); - public double getTime() { - return this.time; - } + double value = 0; - public double getStartTime() { - return this.startTime; - } + if (propabilityDistribution == Distribution.UNIFORM) { + double intervalLength = (maxValue - minValue) / (numValues - 1); + value = minValue + (intervalLength * i); + } else if (propabilityDistribution == Distribution.NORMAL) { + Random random = new Random(); + do { + value = random.nextGaussian() * stdDeviation + mean; + } while (mean > minValue && mean < maxValue && (value < minValue || value > maxValue)); + } else { + break; + } + + // TODO: What if changes already include similarly named variable? + /* If the changes is altered, it affects also to the next simulation. So, + * All the parameters that are to be altered need to be defined explicitly + * before each new simulation. + */ + changes.put(variedParameter, Double.toString(value)); - public double getEndTime() { - return this.endTime; - } - public void setPlaybackDuration(long duration) { - this.playbackDuration = duration; - if(isPlaybackRunning()) { - //Restart playback with different time settings - startPlayback(); + // Specify result file name + + int indexOfDot = simulationLocation.resFile.toString().lastIndexOf('.'); + if (indexOfDot > 1) { + String resFile = simulationLocation.resFile.toString(); + String newResFile = resFile.substring(0, indexOfDot) + i + resFile.substring(indexOfDot); + experimentParameters.put(ModelicaManager.RESULT_FILE_NAME, newResFile); + } + // Simulate the model for one parameter set + runModelica(simulationLocation, modelText, monitor, progressMonitor, experimentParameters, changes, i); + progressMonitor.worked(1); } } - public long getPlaybackDuration() { - return this.playbackDuration; + private void loadConfiguration(){ + try { + session.syncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + + SysdynResource sr = SysdynResource.getInstance(graph); + maxValue = graph.getPossibleRelatedValue(experiment, sr.SensitivityAnalysisExperiment_maxValue, Bindings.DOUBLE); + minValue = graph.getPossibleRelatedValue(experiment, sr.SensitivityAnalysisExperiment_minValue, Bindings.DOUBLE); + numValues = graph.getPossibleRelatedValue(experiment, sr.SensitivityAnalysisExperiment_numValues, Bindings.INTEGER); + variedParameter = graph.getPossibleRelatedValue(experiment, sr.SensitivityAnalysisExperiment_variedParameter, Bindings.STRING); + String propabilityDistributionTemp = graph.getPossibleRelatedValue(experiment, sr.SensitivityAnalysisExperiment_propabilityDistribution, Bindings.STRING); + if (propabilityDistributionTemp.equalsIgnoreCase("uniform")) + propabilityDistribution = Distribution.UNIFORM; + else if (propabilityDistributionTemp.equalsIgnoreCase("normal")) + propabilityDistribution = Distribution.NORMAL; + else + propabilityDistribution = DEFAULT_PROPABILITY_DISTRIBUTION; + + mean = graph.getPossibleRelatedValue(experiment, sr.SensitivityAnalysisExperiment_mean, Bindings.DOUBLE); + stdDeviation = graph.getPossibleRelatedValue(experiment, sr.SensitivityAnalysisExperiment_stdDeviation, Bindings.DOUBLE); + + } + }); + } catch (DatabaseException e) { + e.printStackTrace(); + } } + + protected void runModelica(SimulationLocation simulationLocation, + String modelText, + IModelicaMonitor monitor, + IProgressMonitor progressMonitor, + HashMap experimentParameters, + HashMap changes, + int resFileIndex) throws IOException { + process = ModelicaManager.runModelica( + simulationLocation, + monitor, + experimentParameters, + changes + ); - @Override - public void init(ReadGraph g) { - super.init(g); - this.session = g.getSession(); - session.asyncRequest(new ReadRequest() { + ModelicaManager.printProcessOutput(process, monitor); - @Override - public void run(ReadGraph graph) throws DatabaseException { - changeState(ExperimentState.RUNNING); - final Resource configuration = graph.getPossibleObject(model, SimulationResource.getInstance(graph).HasConfiguration); - sysdynModel = SysdynModelManager.getInstance(session).getModel(graph, configuration); - toggleActivation(graph, true); - //getPlaybackConfiguration(graph); - startSimulationJob(); - } - }); + File resFile = new File(experimentParameters.get(ModelicaManager.RESULT_FILE_NAME)); + Thread resultThread = getResultThread(resFile, experimentParameters, monitor, progressMonitor); + resultThread.run(); + + process = null; } + + /** + * Get a thread for reading and saving reuslts from a normal simulation + * @param simulationLocation + * @param inits + * @param monitor + * @param progressMonitor + * @param resFileIndex + * @return + */ + protected Thread getResultThread(final File resFile, + final HashMap experimentParameters, + final IModelicaMonitor monitor, + final IProgressMonitor progressMonitor) { + return new Thread() { + @Override + public void run() { + try { + process.waitFor(); + if(!canceled) { + // Get and store results + SimulationResult result; + if(resFile.getName().endsWith(".csv")) + result = new CSVSimulationResult(); + else if(resFile.getName().endsWith(".plt")) + result = new SimulationResult(); + else + result = new MatSimulationResult(); // The latest format + // The interval of results saved. Every result? Every other result? etc... + int outIntervalInt = 1; + String outputInterval = experimentParameters.get(ModelicaKeys.OUTPUT_INTERVAL); + if(outputInterval != null) { + String stepTime = experimentParameters.get(ModelicaKeys.STEP_VALUE); + String stopTime = experimentParameters.get(ModelicaKeys.STOP_VALUE); + + Double step = Double.parseDouble(stepTime); + Double stop = Double.parseDouble(stopTime); + Double outInterval = Double.parseDouble(outputInterval); - private class SensitivityAnalysisConfiguration { - public double simulationDuration, simulationStepLength, intervals, endTime, startTime; - public long playbackDuration; - } + outIntervalInt = (int)getInterval(outInterval, step); + // Actually you might be able to use an outInterval one or two longer. + int maxIntervalInt = (int)Math.round(stop / step); + if (outIntervalInt > maxIntervalInt) + outIntervalInt = maxIntervalInt; + } - @Override - protected void localStateChange() { - super.localStateChange(); - } + result.initRead(resFile); + result.readTime(resFile, outIntervalInt); + //result.readInits(simulationLocation.initFile); // Parameter values are read from .mat + result.filter(); + + MemoryResult currentResult = new MemoryResult(null, null); + getCurrentResults().add(currentResult); + currentResult.setResult(result); + currentResult.setResultFile(resFile); + + resultsChanged(); - // TIME LISTENERS - public void addTimeListener(Runnable timeListener) { - if(!this.timeListeners.contains(timeListener)) - this.timeListeners.add(timeListener); - } + simulate(false); - public Collection getTimeListeners() { - return this.timeListeners; + String errorString = result.getResultReadErrors(); + if(errorString != null && !errorString.isEmpty()) + monitor.message(errorString); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }; } - - public void removeTimeListener(Runnable timeListener) { - this.timeListeners.remove(timeListener); + + public ArrayList getCurrentResults() { + if(this.results == null) { + this.results = new ArrayList(); + } + return this.results; } - + @Override - public void resultsChanged() { - for(Runnable listener : timeListeners) { - listener.run(); + public Collection getActiveResults() { + ArrayList result = new ArrayList(); + result.addAll(getCurrentResults()); + result.addAll(sysdynModel.getDisplayedResults()); + return result; + } + + @Override + public MemoryResult getCurrentResult() { + if (this.results == null || this.results.size() < 1) + return null; + /* There should be a better alternative solution for this. Currently + * the return value is next to nonsense. + */ + return this.results.get(0); + } + + @Override + public void saveState() { + if(results == null || !(results instanceof ArrayList)) + return; + //SaveResultJob saveResultJob = new SaveResultJob(SysdynSensitivityAnalysisExperiment.this, session, results); + //saveResultJob.schedule(); + } + + @Override + public int numberOfSimulationRunSteps() { + /* + * From normal experiment: + * 1. Write modelica files + * 2. Write other simulation files + * 3. Build model OR update parameters + * + * Sensitivity: + * 4 - n. Number of iterations + */ + try { + Integer numberOfIterations = session.syncRequest(new Read() { + @Override + public Integer perform(ReadGraph graph) throws DatabaseException { + SysdynResource sr = SysdynResource.getInstance(graph); + return graph.getPossibleRelatedValue(experiment, sr.SensitivityAnalysisExperiment_numValues, Bindings.INTEGER); + } + }); + return 3 + numberOfIterations; + } catch (DatabaseException e) { + e.printStackTrace(); } - super.resultsChanged(); + + return super.numberOfSimulationRunSteps(); } -*/ + } diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/refactoring/TGRefactoring.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/refactoring/TGRefactoring.java index 0c9a0e53..3e19f43c 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/refactoring/TGRefactoring.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/refactoring/TGRefactoring.java @@ -45,7 +45,7 @@ public class TGRefactoring { boolean fixed = GraphRefactoringUtils.fixIncorrectRoot(tg1.identities); IdentityStore idStore = TransferableGraphConversion.extractIdentities(tg1); TIntHashSet parentsAffected = new TIntHashSet(); - GraphRefactoringUtils.refactor(idStore, spec, parentsAffected); + GraphRefactoringUtils.refactor(tg1, idStore, spec, parentsAffected); tg1.resourceCount = idStore.getResourceCount(); tg1.identities = idStore.toArray(); // GraphRefactoringUtils.compactify(tg1, parentsAffected); diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Sheet.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Sheet.java index 92226cc8..db41a5bb 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Sheet.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/Sheet.java @@ -11,8 +11,10 @@ *******************************************************************************/ package org.simantics.sysdyn.representation; +import gnu.trove.map.hash.THashMap; +import gnu.trove.set.hash.THashSet; + import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import org.simantics.Simantics; @@ -41,8 +43,8 @@ public class Sheet extends org.simantics.sysdyn.representation.Variable { @RelatedElement(Layer0.URIs.PartOf) protected Book book; - HashMap cells = new HashMap(); - HashSet usedRanges = new HashSet(); + THashMap cells = new THashMap(); + THashSet usedRanges = new THashSet(); Resource resource; @@ -52,12 +54,10 @@ public class Sheet extends org.simantics.sysdyn.representation.Variable { @UpdateMethod public boolean updateCells(ReadGraph g, Resource r) throws DatabaseException { - cells.clear(); - usedRanges.clear(); - this.resource = null; - if(g.hasStatement(r)) { this.resource = r; + THashMap newCells = new THashMap(); + g.getObjects(r, Layer0.getInstance(g).ConsistsOf); Variable v = g.adapt(r, Variable.class); for(Variable child : v.getChildren(g)) { @@ -65,14 +65,33 @@ public class Sheet extends org.simantics.sysdyn.representation.Variable { try { SpreadsheetUtils.decodeCellAbsolute(name); Variant value = child.getPropertyValue(g, SheetVariables.CONTENT, Bindings.VARIANT); - cells.put(name, value.getValue()); + newCells.put(name, value.getValue()); } catch (CellParseException e) { } catch (MissingVariableException e) { System.out.println("missing content for: " + name); } } + + boolean update = false; + if(newCells.size() == this.cells.size()) { + // Cells are the same size. There might not be changes. Next up: content + for(String key : this.cells.keySet()) { + if(!this.cells.get(key).equals(newCells.get(key))) { + update = true; + break; + } + } + } else { + update = true; + } + + if(update) { + this.cells = newCells; + this.usedRanges.clear(); + return true; + } } - return true; + return false; } public String getStringRepresentation() { @@ -200,7 +219,7 @@ public class Sheet extends org.simantics.sysdyn.representation.Variable { } - public HashMap getCells() { + public THashMap getCells() { return cells; } diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java index f61c40c1..2823b33e 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationJob.java @@ -20,7 +20,6 @@ import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.ui.PlatformUI; import org.simantics.modelica.IModelicaMonitor; -import org.simantics.simulation.experiment.Experiment; import org.simantics.sysdyn.manager.SysdynConsole; import org.simantics.sysdyn.manager.SysdynExperiment; import org.simantics.sysdyn.manager.SysdynModel; @@ -28,10 +27,10 @@ import org.simantics.sysdyn.manager.SysdynModel; public class SimulationJob extends Job { private SysdynModel model; - private Experiment experiment; + private SysdynExperiment experiment; private IModelicaMonitor monitor; - public SimulationJob(SysdynModel model, Experiment experiment) { + public SimulationJob(SysdynModel model, SysdynExperiment experiment) { super("Simulate " + model.getConfiguration().getLabel()); this.model = model; this.experiment = experiment; @@ -45,13 +44,14 @@ public class SimulationJob extends Job { @Override protected IStatus run(IProgressMonitor monitor) { - monitor.beginTask("Simulate " + model.getConfiguration().getLabel(), 5); + monitor.beginTask("Simulate " + model.getConfiguration().getLabel(), experiment.numberOfSimulationRunSteps()); this.monitor.message("Simulate " + model.getConfiguration().getLabel()); try { model.update(); - if(experiment instanceof SysdynExperiment) + if(experiment instanceof SysdynExperiment) { ((SysdynExperiment)experiment).simulate(this.monitor, monitor); -// model.simulate(this.monitor, monitor, experiment); + model.setStructureModified(false); + } } catch (Exception e) { e.printStackTrace(); this.monitor.showConsole(); diff --git a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java index eb9ac911..0ee92dc8 100644 --- a/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java +++ b/simantics-1.10/org.simantics.sysdyn/src/org/simantics/sysdyn/simulation/SimulationScheduler.java @@ -11,15 +11,15 @@ *******************************************************************************/ package org.simantics.sysdyn.simulation; -import org.simantics.simulation.experiment.Experiment; +import org.simantics.sysdyn.manager.SysdynExperiment; import org.simantics.sysdyn.manager.SysdynModel; public class SimulationScheduler { SysdynModel model; - Experiment experiment; + SysdynExperiment experiment; SimulationJob job; - private SimulationScheduler(SysdynModel model, Experiment experiment) { + private SimulationScheduler(SysdynModel model, SysdynExperiment experiment) { this.model = model; this.experiment = experiment; this.job = new SimulationJob(model, experiment); @@ -29,7 +29,7 @@ public class SimulationScheduler { job.schedule(); } - public static synchronized SimulationScheduler start(SysdynModel model, Experiment experiment) { + public static synchronized SimulationScheduler start(SysdynModel model, SysdynExperiment experiment) { SimulationScheduler scheduler = model.getService(SimulationScheduler.class); if(scheduler == null || !scheduler.experiment.equals(experiment)) { scheduler = new SimulationScheduler(model, experiment); -- 2.47.1