1 /*******************************************************************************
\r
2 * Copyright (c) 2010 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 java.io.StringReader;
\r
15 import java.util.ArrayList;
\r
16 import java.util.Iterator;
\r
17 import java.util.Set;
\r
19 import org.simantics.objmap.annotations.GraphType;
\r
20 import org.simantics.objmap.annotations.RelatedValue;
\r
21 import org.simantics.sysdyn.expressionParser.ExpressionParser;
\r
22 import org.simantics.sysdyn.expressionParser.ParseException;
\r
23 import org.simantics.sysdyn.representation.ArrayIndexes;
\r
24 import org.simantics.sysdyn.representation.Book;
\r
25 import org.simantics.sysdyn.representation.Enumeration;
\r
26 import org.simantics.sysdyn.representation.IElement;
\r
27 import org.simantics.sysdyn.representation.IndependentVariable;
\r
28 import org.simantics.sysdyn.representation.Sheet;
\r
29 import org.simantics.sysdyn.representation.Stock;
\r
30 import org.simantics.sysdyn.representation.Valve;
\r
31 import org.simantics.sysdyn.representation.utils.FormatUtils;
\r
32 import org.simantics.sysdyn.representation.utils.IndexUtils;
\r
35 * Class representing a stock expression in a variable
\r
37 * @author Teemu Lempinen
\r
40 @GraphType("http://www.simantics.org/Sysdyn-1.1/StockExpression")
\r
41 public class StockExpression extends Expression {
\r
43 @RelatedValue("http://www.simantics.org/Sysdyn-1.1/HasInitialEquation")
\r
44 private String initialEquation;
\r
47 public String getDeclaration(IndependentVariable variable) {
\r
49 // See if the start parameter is used Stock(start = x, fixed = y)
\r
50 String value = null;
\r
51 if(useStartValue(variable))
\r
52 value = FormatUtils.formatExpressionForModelica(variable, initialEquation);
\r
55 // Build the enumeration indexes, if there are enumerations. Stock[enumIndexes, enum2Indexes, ...]
\r
56 ArrayIndexes ai = variable.getArrayIndexes();
\r
57 ArrayList<Enumeration> enumerations = null;
\r
59 enumerations = ai.getEnumerations();
\r
62 if(enumerations != null && enumerations.size() > 0) {
\r
63 StringBuilder sb = new StringBuilder();
\r
65 Iterator<Enumeration> iterator = enumerations.iterator();
\r
66 while(iterator.hasNext()) {
\r
67 sb.append(iterator.next().getName() + ".size");
\r
68 if(iterator.hasNext()) {
\r
73 range = sb.toString();
\r
77 // each is required when a single value is used for all dimensions e.g. Stock[30](each start = 0)
\r
78 if (value == null) {
\r
79 // start parameter is not used, everything needs to be fixed=false
\r
80 if(ai != null && !ai.getEnumerations().isEmpty())
\r
82 return " " + variable.getType() + " " + variable.getName() + range + "(" + each + " fixed=false);\n";
\r
84 // start parameter is used
\r
86 if(getStartValue(variable) != null) {
\r
87 // a single number is used as the initial equation -> (each start, each fixed) if there are dimensions
\r
88 if(ai != null && !ai.getEnumerations().isEmpty())
\r
90 return " " + variable.getType() + " " + variable.getName() + range + "(" + each+ " start=" + value + ", " + each + " fixed=true);\n";
\r
92 // a function or array constructor {.., .., ..} is used as the initial equation -> (start, each fixed) if there are dimensions
\r
93 if(ai != null && !ai.getEnumerations().isEmpty())
\r
95 return " " + variable.getType() + " " + variable.getName() + range + "(start=" + value + ", " + each + " fixed=true);\n";
\r
101 public String getEquation(IndependentVariable variable) {
\r
103 // Build range e.g. Stock[2,3]
\r
104 String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());
\r
106 // Stock equation is always der(Stock)
\r
107 StringBuilder b = new StringBuilder();
\r
109 .append(variable.getName() + range)
\r
112 // Stock equation is formed automatically using incoming and outgoing flows (actually the nearest valves in those flows)
\r
113 ArrayList<Valve> incoming = ((Stock)variable).getIncomingValves();
\r
114 ArrayList<Valve> outgoing = ((Stock)variable).getOutgoingValves();
\r
115 if(incoming.isEmpty() && outgoing.isEmpty()) {
\r
116 // No connections, add 0 for each array index if any.
\r
117 ArrayIndexes ai = variable.getArrayIndexes();
\r
118 ArrayList<Enumeration> enumerations = null;
\r
120 enumerations = ai.getEnumerations();
\r
122 if(ai == null || enumerations == null || enumerations.isEmpty()) {
\r
125 b.append(" zeros(");
\r
126 for(int i = 0; i < enumerations.size(); i++) {
\r
127 b.append(enumerations.get(i).getEnumerationIndexes().size());
\r
128 if(i != enumerations.size() - 1)
\r
135 // incoming valves add and outgoing valves reduce the stock
\r
136 for(Valve valve : outgoing)
\r
137 b.append("\n - ").append(valve.getName() + range);
\r
138 for(Valve valve : incoming)
\r
139 b.append("\n + ").append(valve.getName() + range);
\r
142 return b.toString();
\r
146 * Check whether to use fixed=true and start=... in Modelica code
\r
149 private boolean useStartValue(IndependentVariable variable) {
\r
150 // If no variables are used in the equation, start value is used
\r
152 // First the equation is formatted and parsed
\r
153 String equation = FormatUtils.formatExpressionForModelica(variable, initialEquation);
\r
154 ExpressionParser parser = new ExpressionParser(new StringReader(equation));
\r
157 if(parser.getReferences().isEmpty()) {
\r
158 // if equation did not contain any references, start value is used
\r
161 // Check if references are references to sheets.
\r
162 // Sheet references are allowed, since sheets contain only constants
\r
163 boolean found = false;
\r
164 Set<String> references = parser.getReferences().keySet();
\r
166 // Go through each reference
\r
167 for(String reference : references) {
\r
168 // We only need the first element to know that it is a Sheet (SheetName.CellOrRange)
\r
169 reference = reference.split("\\.")[0];
\r
171 for(IElement element : variable.getParentConfiguration().getElements()) {
\r
172 if(element instanceof Book) {
\r
173 for(Sheet sheet : ((Book)element).getSheets()) {
\r
174 if(reference.equals(sheet.getName())) {
\r
184 // If there was no sheet for this reference name, return false
\r
189 } catch (ParseException e) {
\r
195 public String getInitialEquation(IndependentVariable variable) {
\r
196 // if start value is used, no initial equation is returned
\r
197 if(useStartValue(variable))
\r
199 // format the initial equation for modelica execution
\r
200 String equation = FormatUtils.formatExpressionForModelica(variable, initialEquation);
\r
201 String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());
\r
204 return " " + variable.getName() + range + " = " + equation + ";\n";
\r
209 * Return Double representation of the initial equation for given variable
\r
212 * @return Double representing the initial equation or null if initial equation is not a double
\r
214 private Double getStartValue(IndependentVariable variable) {
\r
215 Double value = null;
\r
216 ArrayList<IExpression> expressions = variable.getExpressions().getExpressions();
\r
217 if(expressions.size() == 1) {
\r
218 IExpression e = expressions.get(0);
\r
219 if(e.getInitialEquation(variable) == null) {
\r
221 value = Double.parseDouble(initialEquation);
\r
222 } catch(NumberFormatException e1) {
\r