From: lempinen Date: Wed, 30 Nov 2011 10:22:57 +0000 (+0000) Subject: Delay expression X-Git-Tag: simantics-1.6~89 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=c2c593a5f5aba81904143c4621a4cdb9be98d5dd;p=simantics%2Fsysdyn.git Delay expression git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@23372 ac1ea38d-2e2b-0410-8846-a27921b304fc --- diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/VariableInformationTab.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/VariableInformationTab.java index cd6af741..0aa38816 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/VariableInformationTab.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/VariableInformationTab.java @@ -11,7 +11,6 @@ *******************************************************************************/ package org.simantics.sysdyn.ui.properties; -import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; @@ -36,7 +35,13 @@ import org.simantics.sysdyn.ui.properties.widgets.ValveTextLocationGroup; import org.simantics.sysdyn.ui.properties.widgets.factories.DoublePropertyFactory; import org.simantics.sysdyn.ui.properties.widgets.factories.DoublePropertyModifier; import org.simantics.ui.utils.AdaptionUtils; +import org.simantics.utils.ui.validators.DoubleValidator; +/** + * Information tab for additional information of variables. + * @author Teemu Lempinen + * + */ public class VariableInformationTab extends LabelPropertyTabContributor implements Widget { Composite orientationComposite; WidgetSupport support; @@ -54,16 +59,19 @@ public class VariableInformationTab extends LabelPropertyTabContributor implemen informationGroup.setText("Information"); GridDataFactory.fillDefaults().grab(false, true).applyTo(informationGroup); GridLayoutFactory.fillDefaults().margins(3, 3).applyTo(informationGroup); - + + // Textual format documentation TrackedText information = new TrackedText(informationGroup, support, SWT.MULTI | SWT.BORDER); information.setTextFactory(new StringPropertyFactory(Layer0.URIs.HasDescription)); information.addModifyListener(new StringPropertyModifier(context, Layer0.URIs.HasDescription)); GridDataFactory.fillDefaults().grab(true, true).applyTo(information.getWidget()); + // Orientation information for valves orientationComposite = new Composite(composite, SWT.NONE); GridDataFactory.fillDefaults().span(1, 2).applyTo(orientationComposite); GridLayoutFactory.fillDefaults().margins(3,3).applyTo(orientationComposite); + // Range of a variable (e.g. from 0 to 10). Does not affect simulation, but the infor can be used for example in charts Group rangeGroup = new Group(composite, SWT.SHADOW_ETCHED_IN); rangeGroup.setText("Range"); GridDataFactory.fillDefaults().applyTo(rangeGroup); @@ -98,30 +106,12 @@ public class VariableInformationTab extends LabelPropertyTabContributor implemen rangeStep.setInputValidator(new DoubleValidator()); GridDataFactory.fillDefaults().grab(true, false).applyTo(rangeStep.getWidget()); - - - } - - private class DoubleValidator implements IInputValidator { - - @Override - public String isValid(String newText) { - for(int i = 0; i < newText.length(); i++){ - if(!Character.isDigit(newText.charAt(i))){ - if(newText.charAt(i) != '.') { - return "Invalid character '" + newText.charAt(i) + "'"; - } else if(newText.indexOf('.') != newText.lastIndexOf('.')) { - return "There can be only one '.'"; - } - } - } - return null; - } } @Override public void setInput(ISessionContext context, Object input) { final Resource valve = AdaptionUtils.adaptToSingle(input, Resource.class); + // is the displayed variable a valve? Boolean isValve = false; try { isValve = context.getSession().syncRequest(new Read() { @@ -136,6 +126,7 @@ public class VariableInformationTab extends LabelPropertyTabContributor implemen } catch (DatabaseException e) { e.printStackTrace(); } + // if it is a valve, display the orientation information if(isValve) { ValveOrientationGroup vog = new ValveOrientationGroup(orientationComposite, context, support, SWT.NONE); vog.setInput(context, input); diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/ExpressionTypes.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/ExpressionTypes.java index 967b1ff4..7b3b20bf 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/ExpressionTypes.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/ExpressionTypes.java @@ -11,16 +11,18 @@ *******************************************************************************/ package org.simantics.sysdyn.ui.properties.widgets; -import java.util.List; - import org.simantics.db.ReadGraph; import org.simantics.db.Resource; -import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.request.Read; import org.simantics.sysdyn.SysdynResource; import org.simantics.ui.SimanticsUI; +/** + * Expression type representations + * @author Teemu Lempinen + * + */ public class ExpressionTypes { public static enum ExpressionType {Auxiliary, Parameter, Constant, Lookup, WithLookup, Stock, Delay, Empty}; @@ -29,6 +31,7 @@ public class ExpressionTypes { ExpressionType.Auxiliary, ExpressionType.Parameter, ExpressionType.Constant, + ExpressionType.Delay, // ExpressionType.Lookup, ExpressionType.WithLookup}; @@ -36,6 +39,7 @@ public class ExpressionTypes { ExpressionType.Auxiliary, ExpressionType.Parameter, ExpressionType.Constant, + ExpressionType.Delay, ExpressionType.WithLookup}; public static ExpressionType[] stockExpressions = new ExpressionType[] { diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/ExpressionWidget.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/ExpressionWidget.java index f6e40ded..5da8f765 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/ExpressionWidget.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/ExpressionWidget.java @@ -49,6 +49,14 @@ import org.simantics.sysdyn.ui.utils.ExpressionUtils; import org.simantics.ui.SimanticsUI; import org.simantics.ui.utils.AdaptionUtils; +/** + * Widget for displaying an expression. Widget creates the IExpression for displaying + * properties for each expression type and adds validation, saving and other services + * to the active IExpression. + * + * @author Teemu Lempinen + * + */ public class ExpressionWidget implements Widget { private Resource expr; @@ -59,15 +67,25 @@ public class ExpressionWidget implements Widget { private FocusListener focusListener; private Table variableTable; private VerifyKeyListener verifyKeyListener; - private Timer updateChartTimer; + private Timer validationTimer; private static int VALIDATION_DELAY_TIME = 500; + /** + * Create a new expression widget + * @param parent + * @param support + * @param style + */ public ExpressionWidget(Composite parent, WidgetSupport support, int style) { support.register(this); this.parent = parent; this.data = new HashMap(); - updateChartTimer = new Timer(VALIDATION_DELAY_TIME, new ActionListener() { + /* + * Create a validation timer for expression fields. Validation timer + * validates the field as the modeler is typing an expression + */ + validationTimer = new Timer(VALIDATION_DELAY_TIME, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -82,22 +100,32 @@ public class ExpressionWidget implements Widget { }); } }); - updateChartTimer.setRepeats(false); + validationTimer.setRepeats(false); } @Override public void setInput(ISessionContext context, Object input) { + // Update IExpression based on the newly selected expression expr = AdaptionUtils.adaptToSingle(input, Resource.class); ExpressionType et = ExpressionTypes.getExpressionType(expr); displayExpression(et.toString(), true); } + /** + * Displays IExpression corresponding to expressionType. + * @param expressionType Expression type + * @param original Is the displayed expression for a newly selected expression (true) or did the + * expression change its type (false) + */ public void displayExpression(String expressionType, boolean original) { if(expressionType == null) { return; } + // Get up-to-date data to data-map if(this.expression != null) expression.updateData(data); + + // Create the new expression ExpressionType et = ExpressionType.valueOf(expressionType); IExpression exp = null; switch (et) { @@ -114,20 +142,25 @@ public class ExpressionWidget implements Widget { case Stock: exp = new StockExpression(); break; case Delay: - exp = new DelayExpression(); break; + exp = new DelayExpression(expr); break; default: exp = new EmptyExpression(); } if (exp != null) { + // If expression was created, remove the old one for(Control c : parent.getChildren()) { c.dispose(); } + // If a completely new expression was selected, read data if(original) exp.readData(expr, data); + // Create the visual representation of the expression type exp.createExpressionFields(parent, data); + + // Add listeners if(modifyListener != null) exp.addModifyListener(modifyListener); if(focusListener != null) @@ -142,32 +175,50 @@ public class ExpressionWidget implements Widget { } } + /** + * Get current IExpression + * @return current IExpression + */ public IExpression getExpression() { return expression; } + /** + * Set the variable table that contains information about variables that are connected + * to this expression + * @param table + */ public void setVariableTable(Table table) { this.variableTable = table; } - + /** + * Set timed field validation with default delay time + */ public void validateFieldsTimed() { validateFieldsTimed(VALIDATION_DELAY_TIME); } + /** + * Set timed field validation + * @param delay Delay time for validation + */ public void validateFieldsTimed(int delay) { - updateChartTimer.setDelay(delay); - if(!updateChartTimer.isRunning()) - updateChartTimer.start(); + validationTimer.setDelay(delay); + if(!validationTimer.isRunning()) + validationTimer.start(); else - updateChartTimer.restart(); + validationTimer.restart(); } - + /** + * Validates expression fields in current IExpression + */ public void validateFields() { if(this.variableTable == null) return; try { + // Find the variable for this experession Resource variable = SimanticsUI.getSession().syncRequest(new Read() { @Override @@ -181,10 +232,10 @@ public class ExpressionWidget implements Widget { return variable; } }); + // Validate the variable if(variable != null) ExpressionUtils.validateExpressionFields(variable, expression, variableTable); } catch (DatabaseException e) { - // TODO Auto-generated catch block e.printStackTrace(); } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/BasicExpression.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/BasicExpression.java index 18083697..96c6268e 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/BasicExpression.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/BasicExpression.java @@ -12,6 +12,7 @@ package org.simantics.sysdyn.ui.properties.widgets.expressions; import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -42,6 +43,11 @@ import org.simantics.sysdyn.SysdynResource; import org.simantics.sysdyn.ui.utils.ExpressionUtils; import org.simantics.ui.SimanticsUI; +/** + * Basic expression that is used with parameter, auxiliary and constant + * @author Teemu Lempinen + * + */ public class BasicExpression implements IExpression { private ExpressionField expression; @@ -49,6 +55,7 @@ public class BasicExpression implements IExpression { @Override public void createExpressionFields(Composite parent, Map data) { + // Create the single field GridLayoutFactory.fillDefaults().numColumns(2).applyTo(parent); String equation = data.get("equation") != null ? (String)data.get("equation") : ""; @@ -127,13 +134,16 @@ public class BasicExpression implements IExpression { throws DatabaseException { SysdynResource sr = SysdynResource.getInstance(g); Layer0 l0 = Layer0.getInstance(g); - + + // Force change to parameter, if the equation is a parameter if(ExpressionUtils.isParameter(currentText)) { if(!expressionType.equals(sr.ConstantExpression)) expressionType = sr.ParameterExpression; } else { expressionType = sr.NormalExpression; } + + // If nothing has changed, do nothing if (oldEquation != null && expression != null && g.isInstanceOf(expression, expressionType) @@ -141,8 +151,12 @@ public class BasicExpression implements IExpression { return; } + // If the current expression type is different than the target expression type, create a new expression if(!g.isInstanceOf(expression, expressionType)) { - Resource ownerList = OrderedSetUtils.getSingleOwnerList(g, expression); + Collection ownerLists = OrderedSetUtils.getOwnerLists(g, expression, l0.OrderedSet); + if(ownerLists.size() != 1) + return; + Resource ownerList = ownerLists.iterator().next(); final Resource newExpression = GraphUtils.create2(g, expressionType, sr.HasEquation, currentText); String arrayRange = g.getPossibleRelatedValue(expression, sr.HasArrayRange, Bindings.STRING); @@ -169,6 +183,7 @@ public class BasicExpression implements IExpression { } ); } else { + // Claim value for the expression g.claimLiteral(expression, sr.HasEquation, currentText); } } diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/DelayExpression.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/DelayExpression.java index dc7b724d..18b2e8cd 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/DelayExpression.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/widgets/expressions/DelayExpression.java @@ -11,82 +11,310 @@ *******************************************************************************/ package org.simantics.sysdyn.ui.properties.widgets.expressions; +import java.util.Arrays; import java.util.List; import java.util.Map; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.swt.SWT; import org.eclipse.swt.custom.VerifyKeyListener; +import org.eclipse.swt.events.FocusAdapter; +import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Spinner; +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; import org.simantics.db.Resource; +import org.simantics.db.VirtualGraph; +import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.utils.OrderedSetUtils; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.request.Read; +import org.simantics.layer0.Layer0; +import org.simantics.layer0.utils.direct.GraphUtils; +import org.simantics.sysdyn.SysdynResource; +import org.simantics.ui.SimanticsUI; +/** + * IExpression for displaying fields of DelayExpression + * @author Teemu Lempinen + * + */ public class DelayExpression implements IExpression { + private ExpressionField equation, delayTime, initialValue; + private ExpressionField lastSelectedText = equation; + private Spinner order; + private Resource expression; + + /** + * Creates a new DelayExpression + * @param expression + */ + public DelayExpression(Resource expression) { + this.expression = expression; + } + + /** + * Displays the fields for delayExpression + */ @Override - public void createExpressionFields(Composite parent, Map data) { - // TODO Auto-generated method stub - + public void createExpressionFields(Composite parent, final Map data) { + // Get possible existing data + GridLayoutFactory.fillDefaults().numColumns(2).applyTo(parent); + String eq = data.get("equation") != null ? (String)data.get("equation") : ""; + String dt = data.get("delayTime") != null ? (String)data.get("delayTime") : ""; + String iv = data.get("initialValue") != null ? (String)data.get("initialValue") : ""; + int o = data.get("order") != null ? (Integer)data.get("order") : 3; + + Label l = new Label(parent, SWT.NONE); + l.setText("expression"); + + // Equation that is delayed + equation = new ExpressionField(parent, SWT.BORDER); + equation.setExpression(eq); + GridDataFactory.fillDefaults().grab(true, true).applyTo(equation); + equation.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() { + + @Override + public void focusLost(FocusEvent e) { + lastSelectedText = equation; + } + }); + + l = new Label(parent, SWT.NONE); + l.setText("delay time"); + + // How much the equation is delayed + delayTime = new ExpressionField(parent, SWT.BORDER); + delayTime.setExpression(dt); + GridDataFactory.fillDefaults().grab(true, true).applyTo(delayTime); + + delayTime.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() { + + @Override + public void focusLost(FocusEvent e) { + lastSelectedText = delayTime; + } + }); + + l = new Label(parent, SWT.NONE); + l.setText("initial value"); + + // What is the initial value of the delay (empty == same as equation) + initialValue = new ExpressionField(parent, SWT.BORDER); + initialValue.setExpression(iv); + GridDataFactory.fillDefaults().grab(true, true).applyTo(initialValue); + + initialValue.getSourceViewer().getTextWidget().addFocusListener(new FocusAdapter() { + + @Override + public void focusLost(FocusEvent e) { + lastSelectedText = initialValue; + } + }); + + + l = new Label(parent, SWT.NONE); + l.setText("order"); + + // The order of the delay (default == 3) + order = new Spinner(parent, SWT.BORDER); + order.setMinimum(1); + order.setSelection(o); + order.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + save(expression, data); + } + }); + GridDataFactory.fillDefaults().applyTo(order); } @Override public void focus() { - // TODO Auto-generated method stub - + equation.setFocus(); } @Override public List getExpressionFields() { - // TODO Auto-generated method stub - return null; + return Arrays.asList(equation, delayTime); } @Override - public void readData(Resource variable, Map data) { - // TODO Auto-generated method stub - + public void readData(final Resource expression, Map data) { + class Auxiliary { + String equation, delayTime, initialValue; + Integer order; + } + + Auxiliary results = null; + + try { + results = SimanticsUI.getSession().syncRequest(new Read() { + + @Override + public Auxiliary perform(ReadGraph graph) throws DatabaseException { + Auxiliary results = new Auxiliary(); + SysdynResource sr = SysdynResource.getInstance(graph); + if (expression != null && graph.isInstanceOf(expression, sr.DelayExpression)) { + results.equation = graph.getPossibleRelatedValue(expression, sr.DelayExpression_expression); + results.delayTime = graph.getPossibleRelatedValue(expression, sr.DelayExpression_delayTime); + results.initialValue = graph.getPossibleRelatedValue(expression, sr.DelayExpression_initialValue); + results.order = graph.getPossibleRelatedValue(expression, sr.DelayExpression_order); + } else { + results.equation = ""; + results.delayTime = ""; + results.order = 1; + } + return results; + } + }); + } catch (DatabaseException e1) { + e1.printStackTrace(); + } + if(results.equation != null) + data.put("equation", results.equation); + if(results.delayTime != null) + data.put("delayTime", results.delayTime); + if(results.initialValue != null) + data.put("initialValue", results.initialValue); + if(results.order != null) + data.put("order", results.order); } @Override public void replaceSelection(String var) { - // TODO Auto-generated method stub - + if(lastSelectedText != null) { + IDocument doc = lastSelectedText.getDocument(); + try { + Point selection = lastSelectedText.getSelection(); + doc.replace(selection.x, selection.y, var); + lastSelectedText.setSelection(selection.x + var.length()); + } catch (BadLocationException e) { + e.printStackTrace(); + } + } } @Override - public void save(Resource variable, Map data) { - // TODO Auto-generated method stub - + public void save(Resource expr, Map data) { + this.expression = expr; + final String currentEquation = this.equation.getExpression(); + final String currentDelayTime = this.delayTime.getExpression(); + final String currentInitialValue = this.initialValue.getExpression(); + final Integer currentOrder = this.order.getSelection(); + + String oldEquation = (String)data.get("equation"); + String oldDelayTime = (String)data.get("delayTime"); + String oldInitialValue = (String)data.get("initialValue"); + Integer oldOrder = (Integer)data.get("order"); + + if((oldEquation == null || oldDelayTime == null || oldOrder == null || oldInitialValue == null) || + !oldEquation.equals(currentEquation) || !oldDelayTime.equals(currentDelayTime) || + !oldOrder.equals(currentOrder) || !oldInitialValue.equals(currentInitialValue)) { + // old value was null or value has changed -> Do save + + data.putAll(data); + data.put("equation", currentEquation); + data.put("delayTime", currentDelayTime); + data.put("initialValue", currentInitialValue); + data.put("order", currentOrder); + + SimanticsUI.getSession().asyncRequest(new WriteRequest() { + @Override + public void perform(WriteGraph g) + throws DatabaseException { + SysdynResource sr = SysdynResource.getInstance(g); + Layer0 l0 = Layer0.getInstance(g); + + if(!g.isInstanceOf(expression, sr.DelayExpression)) { + // Create a new DelayExpression, if the old expression was something else + Resource ownerList = OrderedSetUtils.getSingleOwnerList(g, expression); + final Resource newExpression = GraphUtils.create2(g, sr.DelayExpression); + String arrayRange = g.getPossibleRelatedValue(expression, sr.HasArrayRange, Bindings.STRING); + if(arrayRange != null) + g.claimLiteral(newExpression, sr.HasArrayRange, arrayRange); + + final Resource variable = g.getSingleObject(ownerList, sr.HasExpressions_Inverse); + OrderedSetUtils.replace(g, ownerList, expression, newExpression); + g.deny(expression, l0.PartOf); + g.claim(newExpression, l0.PartOf, variable); + + VirtualGraph runtime = g.getService(VirtualGraph.class); + g.syncRequest(new WriteRequest(runtime) { + @Override + public void perform(WriteGraph graph) throws DatabaseException { + SysdynResource sr = SysdynResource.getInstance(graph); + if(graph.hasStatement(variable, sr.HasActiveExpression)) + graph.deny(variable, sr.HasActiveExpression); + graph.claim(variable, sr.HasActiveExpression, newExpression); + } + } + ); + expression = newExpression; + } + + // Claim values + g.claimLiteral(expression, sr.DelayExpression_expression, currentEquation); + g.claimLiteral(expression, sr.DelayExpression_delayTime, currentDelayTime); + g.claimLiteral(expression, sr.DelayExpression_initialValue, currentInitialValue); + g.claimLiteral(expression, sr.DelayExpression_order, currentOrder); + } + }); + } + } @Override public void updateData(Map data) { - // TODO Auto-generated method stub - + if(this.equation != null && this.equation.getExpression() != null) + data.put("equation", this.equation.getExpression()); + if(this.delayTime != null && this.delayTime.getExpression() != null) + data.put("delayTime", this.delayTime.getExpression()); + if(this.initialValue != null && this.initialValue.getExpression() != null) + data.put("initialValue", this.initialValue.getExpression()); + if(this.order != null) + data.put("order", this.order.getSelection()); } @Override public void addKeyListener(KeyListener listener) { - // TODO Auto-generated method stub - + this.equation.getSourceViewer().getTextWidget().addKeyListener(listener); + this.delayTime.getSourceViewer().getTextWidget().addKeyListener(listener); + this.initialValue.getSourceViewer().getTextWidget().addKeyListener(listener); } @Override public void addModifyListener(ModifyListener listener) { - // TODO Auto-generated method stub - + this.equation.getSourceViewer().getTextWidget().addModifyListener(listener); + this.delayTime.getSourceViewer().getTextWidget().addModifyListener(listener); + this.initialValue.getSourceViewer().getTextWidget().addModifyListener(listener); } @Override public void addFocusListener(FocusListener listener) { - // TODO Auto-generated method stub - + this.equation.getSourceViewer().getTextWidget().addFocusListener(listener); + this.delayTime.getSourceViewer().getTextWidget().addFocusListener(listener); + this.initialValue.getSourceViewer().getTextWidget().addFocusListener(listener); } - @Override - public void addVerifyKeyListener(VerifyKeyListener listener) { - // TODO Auto-generated method stub - - } + @Override + public void addVerifyKeyListener(VerifyKeyListener listener) { + this.equation.getSourceViewer().getTextWidget().addVerifyKeyListener(listener); + this.delayTime.getSourceViewer().getTextWidget().addVerifyKeyListener(listener); + this.initialValue.getSourceViewer().getTextWidget().addVerifyKeyListener(listener); + } } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/SysdynSchema.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/SysdynSchema.java index 3c6a6eed..aadf2a0f 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/SysdynSchema.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/SysdynSchema.java @@ -16,6 +16,7 @@ import org.simantics.db.exception.DatabaseException; import org.simantics.objmap.schema.MappingSchemas; import org.simantics.objmap.schema.SimpleSchema; import org.simantics.sysdyn.representation.expressions.ConstantExpression; +import org.simantics.sysdyn.representation.expressions.DelayExpression; import org.simantics.sysdyn.representation.expressions.Expressions; import org.simantics.sysdyn.representation.expressions.LookupExpression; import org.simantics.sysdyn.representation.expressions.NormalExpression; @@ -54,6 +55,7 @@ public class SysdynSchema extends SimpleSchema { addLinkType(MappingSchemas.fromAnnotations(g, Book.class)); addLinkType(MappingSchemas.fromAnnotations(g, Sheet.class)); addLinkType(MappingSchemas.fromAnnotations(g, DiagramContainerDummy.class)); + addLinkType(MappingSchemas.fromAnnotations(g, DelayExpression.class)); } catch (DatabaseException e) { e.printStackTrace(); } catch (InstantiationException e) { diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/expressions/DelayExpression.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/expressions/DelayExpression.java index 1f9fe835..6aea3fc5 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/expressions/DelayExpression.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/expressions/DelayExpression.java @@ -11,9 +11,190 @@ *******************************************************************************/ package org.simantics.sysdyn.representation.expressions; +import java.util.ArrayList; +import java.util.Iterator; + import org.simantics.objmap.annotations.GraphType; +import org.simantics.objmap.annotations.RelatedValue; +import org.simantics.sysdyn.representation.ArrayIndexes; +import org.simantics.sysdyn.representation.Enumeration; +import org.simantics.sysdyn.representation.IndependentVariable; +import org.simantics.sysdyn.representation.Variable; +import org.simantics.sysdyn.representation.utils.FormatUtils; +import org.simantics.sysdyn.representation.utils.IndexUtils; +/** + * Representation of a delay expression. The order of the + * delay can be 1-n. + * + * Delay with n = 3: + * + * DELAY3=LV3/DL + * LV3=INTEG(RT2-DELAY3,DL*input) + * RT2=LV2/DL + * LV2=INTEG(RT1-RT2,LV3) + * RT1=LV1/DL + * LV1=INTEG(input-RT1,LV3) + * DL=delay time/3 + * + * DELAY3I=LV3/DL + * LV3=INTEG(RT2-DELAY3I,initial value*DL) + * RT2=LV2/DL + * LV2=INTEG(RT1-RT2,LV3) + * RT1=LV1/DL + * LV1=INTEG(input-RT1,LV3) + * DL=delay time/3 + * + * @author Teemu Lempinen + * + */ @GraphType("http://www.simantics.org/Sysdyn-1.1/DelayExpression") public class DelayExpression extends Expression { + @RelatedValue("http://www.simantics.org/Sysdyn-1.1/DelayExpression/initialValue") + private String initialValue; + + @RelatedValue("http://www.simantics.org/Sysdyn-1.1/DelayExpression/delayTime") + private String delayTime; + + @RelatedValue("http://www.simantics.org/Sysdyn-1.1/DelayExpression/order") + private Integer order; + + @RelatedValue("http://www.simantics.org/Sysdyn-1.1/DelayExpression/expression") + private String equation; + + @Override + public String getDeclaration(IndependentVariable variable) { + + // Calculate range for the variable + ArrayIndexes ai = variable.getArrayIndexes(); + ArrayList enumerations = null; + if(ai != null) + enumerations = ai.getEnumerations(); + + String range = ""; + if(enumerations != null && enumerations.size() > 0) { + StringBuilder sb = new StringBuilder(); + sb.append("["); + Iterator iterator = enumerations.iterator(); + while(iterator.hasNext()) { + sb.append(iterator.next().getName() + ".size"); + if(iterator.hasNext()) { + sb.append(", "); + } + } + sb.append("]"); + range = sb.toString(); + } + + /* Build the declaration */ + StringBuilder declaration = new StringBuilder(); + // Variable declaration + declaration.append(" " + variable.getType() + " " + variable.getName() + range + ";\n"); + // Delay declaration + declaration.append(" " + variable.getName() + "_delayClass " + variable.getName() + "_delayClass_instance"); + // Change enumeration sizes from the delay class. Supports overridden enumerations in modules. + if(range.length() > 0) { + declaration.append("("); + String[] ranges = range.substring(1, range.length() - 1).split(","); + for(int i = 0; i < ranges.length; i++ ) { + String r = ranges[i]; + declaration.append(r.replace(".size", "size") + " = " + r); + if(i < ranges.length - 1) { + declaration.append(", "); + } + } + declaration.append(")"); + } + declaration.append(";\n"); + + // Write the delay class + declaration.append(getDelayClass(variable, range, order)); + return declaration.toString(); + } + + /** + * Creates a class that is used to implement the delay. Class contains + * a basic delay structure with "stocks and flows". The number of + * stocks and flows is determined by the order of the delay + * + * @param variable The variable for which the delay is created + * @param range Array range + * @param n Order of the delay + * @return + */ + private String getDelayClass(Variable variable, String range, int n) { + StringBuilder sb = new StringBuilder(); + + sb.append("class " + variable.getName() + "_delayClass\n"); + + // Auxiliary variable + sb.append("\tReal DL;\n"); + // Delay time + sb.append("\tReal delayTime;\n"); + + // Enumeration sizes as parameters. Sizes correspond the enumeration sizes of variable + if(range.length() > 0) { + range = range.replaceAll(".size", "size"); + for(String r : range.substring(1, range.length() - 1).split(",")) { + sb.append("\t parameter Integer " + r + ";\n"); + } + } + + if(initialValue == null || initialValue.length() == 0) + // Use "random" number as initial value, if initial value is not set + sb.append("\tReal" + range + " initialValue = " + (range.length() > 0 ? "fill(-137543," + range.substring(1, range.length() - 1) + ")" : -137543) + ";\n"); + else + // Initial value + sb.append("\tReal" + range + " initialValue = " + initialValue + ";\n"); + + // First valve + sb.append("\tReal" + range + " delay0;\n"); + + // Stocks and valves. Valves are the delayed values of the variable + for(int i = 1; i <= n; i++) { + sb.append("\tReal" + range + " LV" + i + "(" + (range.length() > 0 ? "each " : "") + "fixed=false);\n"); + sb.append("\tReal" + range + " delay" + i + ";\n"); + } + + sb.append("initial equation\n"); + + // "Generic" structure selection. If the "random" number is not used in initial value, use delay0 as initial value + sb.append("\tLV" + n +" = DL * " + + (range.length() > 0 ? "(if max(initialValue) < -137543 or max(initialValue) > -137543 then initialValue else delay0)" : + "(if initialValue < -137543 or initialValue > -137543 then initialValue else delay0)") + ";\n"); + + // Each stock gets the same initial value + for(int i = 1; i < n; i++) + sb.append("\tLV" + i + " = LV" + n + ";\n"); + + sb.append("equation\n"); + sb.append("\tDL = delayTime/" + n + ";\n"); + + // Valves and stocks + for(int i = 1; i <= n; i++) { + sb.append("\tder(LV" + i + ") = - delay" + i + " + delay" + (i - 1) + ";\n"); + sb.append("\tdelay" + i + " = LV" + i + "/DL;\n"); + } + + sb.append("end " + variable.getName() + "_delayClass;\n"); + return sb.toString(); + } + + @Override + public String getEquation(IndependentVariable variable) { + String equation = FormatUtils.formatExpressionForModelica(variable, this.equation); + + // Set delay properties + StringBuilder sb = new StringBuilder(); + sb.append(" " + variable.getName() + "_delayClass_instance.delayTime = " + delayTime + ";\n"); + sb.append(" " + variable.getName() + "_delayClass_instance.delay0 = " + equation + ";\n"); + + // Use the delay in the value of variable + String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange()); + sb.append(" " + variable.getName() + (range.equals("[:]") ? "" : range) + " = " + variable.getName() + "_delayClass_instance.delay" + order + ";\n"); + return sb.toString(); + } + + }