1 /*******************************************************************************
\r
2 * Copyright (c) 2010, 2012 Association for Decentralized Information Management in
\r
4 * All rights reserved. This program and the accompanying materials
\r
5 * are made available under the terms of the Eclipse Public License v1.0
\r
6 * which accompanies this distribution, and is available at
\r
7 * http://www.eclipse.org/legal/epl-v10.html
\r
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.sysdyn.representation.expressions;
\r
14 import org.simantics.db.ReadGraph;
\r
15 import org.simantics.objmap.annotations.GraphType;
\r
16 import org.simantics.objmap.annotations.RelatedValue;
\r
17 import org.simantics.sysdyn.SysdynResource;
\r
18 import org.simantics.sysdyn.manager.SysdynModel;
\r
19 import org.simantics.sysdyn.representation.IndependentVariable;
\r
20 import org.simantics.sysdyn.representation.Variability;
\r
21 import org.simantics.sysdyn.representation.utils.FormatUtils;
\r
22 import org.simantics.sysdyn.representation.utils.IndexUtils;
\r
23 import org.simantics.sysdyn.representation.utils.UnitUtils;
\r
26 * Representation of a delay expression. The order of the
\r
32 * LV3=INTEG(RT2-DELAY3,DL*input)
\r
34 * LV2=INTEG(RT1-RT2,LV3)
\r
36 * LV1=INTEG(input-RT1,LV3)
\r
40 * LV3=INTEG(RT2-DELAY3I,initial value*DL)
\r
42 * LV2=INTEG(RT1-RT2,LV3)
\r
44 * LV1=INTEG(input-RT1,LV3)
\r
47 * @author Teemu Lempinen
\r
50 @GraphType(SysdynResource.URIs.DelayExpression)
\r
51 public class DelayExpression extends Expression {
\r
53 @RelatedValue(SysdynResource.URIs.DelayExpression_initialValue)
\r
54 private String initialValue;
\r
56 @RelatedValue(SysdynResource.URIs.DelayExpression_delayTime)
\r
57 private String delayTime;
\r
59 @RelatedValue(SysdynResource.URIs.DelayExpression_order)
\r
60 private Integer order;
\r
62 @RelatedValue(SysdynResource.URIs.DelayExpression_expression)
\r
63 private String equation;
\r
66 public String getDeclarationAddition() {
\r
68 String delayTime = FormatUtils.formatExpressionForModelica(parent, this.delayTime);
\r
69 String initialValue = FormatUtils.formatExpressionForModelica(parent, this.initialValue);
\r
70 Variability delayTimeVariability = Variability.getVariability((IndependentVariable)parent, delayTime);
\r
71 Variability initialVariability = Variability.CONTINUOUS;
\r
72 if(initialValue != null && initialValue.length() > 0) {
\r
74 * By default, initial value variability is continuous.
\r
75 * If initial value has been set, it can be some other.
\r
77 initialVariability = Variability.getVariability(parent, initialValue);
\r
81 StringBuilder declaration = new StringBuilder();
\r
83 String range = parent.getRange();
\r
85 // Delay declaration
\r
86 declaration.append(" " + parent.getName() + "_delayClass " + parent.getName() + "_delayClass_instance");
\r
88 // Change enumeration sizes from the delay class. Supports overridden enumerations in modules.
\r
89 if(range.length() > 0 || !initialVariability.equals(Variability.CONTINUOUS) || !delayTimeVariability.equals(Variability.CONTINUOUS)) {
\r
90 declaration.append("(");
\r
92 boolean started = false;
\r
93 if(range.length() > 0) {
\r
95 String[] ranges = range.substring(1, range.length() - 1).split(",");
\r
96 for(int i = 0; i < ranges.length; i++ ) {
\r
97 String r = ranges[i];
\r
98 declaration.append(r.replace(".size", "size") + " = " + r);
\r
99 if(i < ranges.length - 1) {
\r
100 declaration.append(", ");
\r
105 // If initial value is not continuous, it is set in the module declaration
\r
106 if(!initialVariability.equals(Variability.CONTINUOUS)) {
\r
108 declaration.append(", ");
\r
110 declaration.append("initialValue = " + initialValue);
\r
113 // If delay time is not continuous, it is set in the module declaration
\r
114 if(!delayTimeVariability.equals(Variability.CONTINUOUS)) {
\r
116 declaration.append(", ");
\r
117 declaration.append("delayTime = " + delayTime);
\r
120 declaration.append(")");
\r
122 declaration.append(";\n");
\r
124 // Write the delay class
\r
125 declaration.append(getDelayClass(range, order));
\r
126 return declaration.toString();
\r
130 * Creates a class that is used to implement the delay. Class contains
\r
131 * a basic delay structure with "stocks and flows". The number of
\r
132 * stocks and flows is determined by the order of the delay
\r
134 * @param variable The variable for which the delay is created
\r
135 * @param range Array range
\r
136 * @param n Order of the delay
\r
139 private String getDelayClass(String range, int n) {
\r
140 StringBuilder sb = new StringBuilder();
\r
142 sb.append("class " + parent.getName() + "_delayClass\n");
\r
144 // Enumeration sizes as parameters. Sizes correspond the enumeration sizes of variable
\r
145 if(range.length() > 0) {
\r
146 range = range.replaceAll(".size", "size");
\r
147 for(String r : range.substring(1, range.length() - 1).split(",")) {
\r
148 sb.append("\t parameter Integer " + r + ";\n");
\r
152 String dt = FormatUtils.formatExpressionForModelica(parent,delayTime);
\r
153 Variability delayTimeVariability = Variability.getVariability(parent, dt);
\r
154 if(!delayTimeVariability.equals(Variability.CONTINUOUS)) {
\r
155 // Auxiliary variable
\r
156 sb.append("\t" + delayTimeVariability.getText() + " Real" + range + " DL = delayTime/" + n + ";\n");
\r
158 sb.append("\t" + delayTimeVariability.getText() + " Real" + range + " delayTime;\n");
\r
160 // Continuous auxiliary variable
\r
161 sb.append("\tReal" + range + " DL;\n");
\r
162 // Continuous delay time
\r
163 sb.append("\tReal" + range + " delayTime;\n");
\r
167 // Get initial value variability
\r
168 Variability initialValueVariability = Variability.CONTINUOUS;
\r
169 String initEquation = FormatUtils.formatExpressionForModelica(parent, this.initialValue);
\r
170 if(initialValue != null && initialValue.length() > 0) {
\r
171 initialValueVariability = Variability.getVariability(parent, initEquation);
\r
174 // Declare initial value (continuous or other)
\r
175 String ivv = !initialValueVariability.equals(Variability.CONTINUOUS) ? initialValueVariability.getText() + " " : "";
\r
176 sb.append("\t" + ivv + "Real" + range + " initialValue;\n");
\r
179 sb.append("\tReal" + range + " delay0;\n");
\r
181 // Stocks and valves. Valves are the delayed values of the variable
\r
182 for(int i = 1; i <= n; i++) {
\r
183 if(initialValueVariability.equals(Variability.CONTINUOUS) || delayTimeVariability.equals(Variability.CONTINUOUS))
\r
184 // Continuous initial value or delay time
\r
185 sb.append("\tReal" + range + " LV" + i + "(" + (range.length() > 0 ? "each " : "") + "fixed=false);\n");
\r
187 // initial value and delay time are not continuous
\r
188 sb.append("\tReal" + range + " LV" + i +
\r
189 "(" + (range.length() > 0 ? "each " : "") + "fixed=true, start=initialValue " + (range.isEmpty() ? "*" : ".*") + " DL);\n");
\r
190 sb.append("\tReal" + range + " delay" + i + ";\n");
\r
193 // If initial value or delay time are continuous, use initial equation block
\r
194 if(initialValueVariability.equals(Variability.CONTINUOUS) || delayTimeVariability.equals(Variability.CONTINUOUS)) {
\r
195 sb.append("initial equation\n");
\r
197 // Each stock gets the same initial value
\r
198 for(int i = 1; i <= n; i++)
\r
199 sb.append("\tLV" + i +" = DL " + (range.isEmpty() ? "*" : ".*") + " initialValue;\n");
\r
203 sb.append("equation\n");
\r
205 if(delayTimeVariability.equals(Variability.CONTINUOUS))
\r
206 sb.append("\tDL = delayTime/" + n + ";\n");
\r
208 // Valves and stocks
\r
209 for(int i = 1; i <= n; i++) {
\r
210 sb.append("\tder(LV" + i + ") = - delay" + i + " + delay" + (i - 1) + ";\n");
\r
211 sb.append("\tdelay" + i + " = LV" + i + " " + (range.isEmpty() ? "/" : "./") + "DL;\n");
\r
214 sb.append("end " + parent.getName() + "_delayClass;\n");
\r
215 return sb.toString();
\r
219 public String getEquation() {
\r
220 StringBuilder sb = new StringBuilder();
\r
222 String equation = FormatUtils.formatExpressionForModelica(parent, this.equation);
\r
223 String delayTime = FormatUtils.formatExpressionForModelica(parent, this.delayTime);
\r
224 String initialValue = FormatUtils.formatExpressionForModelica(parent, this.initialValue);
\r
226 // First "valve" in the delay
\r
227 sb.append(" " + parent.getName() + "_delayClass_instance.delay0 = " + equation + ";\n");
\r
229 // Delay time (if continuous)
\r
230 Variability delayTimeVariability = Variability.getVariability(parent, delayTime);
\r
231 if(delayTimeVariability.equals(Variability.CONTINUOUS)) {
\r
232 sb.append(" " + parent.getName() + "_delayClass_instance.delayTime = " + delayTime + ";\n");
\r
236 if(initialValue == null || initialValue.length() == 0) {
\r
237 // No initial value set, use delay0 (the first "valve")
\r
238 sb.append(" " + parent.getName() + "_delayClass_instance.initialValue = " + parent.getName() + "_delayClass_instance.delay0;\n");
\r
240 // Continuous initial value
\r
241 Variability initialVariability = Variability.getVariability(parent, initialValue);
\r
242 if(initialVariability.equals(Variability.CONTINUOUS)) {
\r
243 sb.append(" " + parent.getName() + "_delayClass_instance.initialValue = " + initialValue + ";\n");
\r
247 // The value of the actual variable
\r
248 String range = IndexUtils.rangeToIndexes(parent, this.getArrayRange());
\r
249 sb.append(" " + parent.getName() + (range.equals("[:]") ? "" : range) + " = " + parent.getName() + "_delayClass_instance.delay" + order + ";\n");
\r
250 return sb.toString();
\r
254 public String getExpression() {
\r
255 return "This + is + not + a + parameter + at + any + time";
\r
260 public String validateUnits(ReadGraph graph, SysdynModel model) {
\r
261 if(parent.getUnit() == null)
\r
262 return "Unit not defined for " + parent.getName();
\r
264 String result = UnitUtils.matchUnits(graph, model, parent.getParentConfiguration(), parent.getUnit(), equation);
\r
266 result = UnitUtils.matchUnits(graph, model, parent.getParentConfiguration(), parent.getUnit(), initialValue);
\r
268 result = UnitUtils.matchUnits(graph, model, parent.getParentConfiguration(), UnitUtils.getTimeUnit(graph, model), delayTime);
\r