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.SysdynResource;
\r
22 import org.simantics.sysdyn.expressionParser.ExpressionParser;
\r
23 import org.simantics.sysdyn.expressionParser.ParseException;
\r
24 import org.simantics.sysdyn.representation.ArrayIndexes;
\r
25 import org.simantics.sysdyn.representation.Book;
\r
26 import org.simantics.sysdyn.representation.Enumeration;
\r
27 import org.simantics.sysdyn.representation.IElement;
\r
28 import org.simantics.sysdyn.representation.IndependentVariable;
\r
29 import org.simantics.sysdyn.representation.Sheet;
\r
30 import org.simantics.sysdyn.representation.Stock;
\r
31 import org.simantics.sysdyn.representation.Valve;
\r
32 import org.simantics.sysdyn.representation.utils.FormatUtils;
\r
33 import org.simantics.sysdyn.representation.utils.IndexUtils;
\r
36 * Class representing a stock expression in a variable
\r
38 * @author Teemu Lempinen
\r
41 @GraphType(SysdynResource.URIs.StockExpression)
\r
42 public class StockExpression extends Expression {
\r
44 @RelatedValue(SysdynResource.URIs.StockExpression_initialEquation)
\r
45 private String initialEquation;
\r
48 public String getDeclaration(IndependentVariable variable) {
\r
50 // See if the start parameter is used Stock(start = x, fixed = y)
\r
51 String value = null;
\r
52 if(useStartValue(variable))
\r
53 value = FormatUtils.formatExpressionForModelica(variable, initialEquation);
\r
56 // Build the enumeration indexes, if there are enumerations. Stock[enumIndexes, enum2Indexes, ...]
\r
57 ArrayIndexes ai = variable.getArrayIndexes();
\r
58 ArrayList<Enumeration> enumerations = null;
\r
60 enumerations = ai.getEnumerations();
\r
63 if(enumerations != null && enumerations.size() > 0) {
\r
64 StringBuilder sb = new StringBuilder();
\r
66 Iterator<Enumeration> iterator = enumerations.iterator();
\r
67 while(iterator.hasNext()) {
\r
68 sb.append(iterator.next().getName() + ".size");
\r
69 if(iterator.hasNext()) {
\r
74 range = sb.toString();
\r
78 // each is required when a single value is used for all dimensions e.g. Stock[30](each start = 0)
\r
79 if (value == null) {
\r
80 // start parameter is not used, everything needs to be fixed=false
\r
81 if(ai != null && !ai.getEnumerations().isEmpty())
\r
83 return " " + variable.getType() + " " + variable.getName() + range + "(" + each + " fixed=false);\n";
\r
85 // start parameter is used
\r
87 if(getStartValue(variable) != null) {
\r
88 // a single number is used as the initial equation -> (each start, each fixed) if there are dimensions
\r
89 if(ai != null && !ai.getEnumerations().isEmpty())
\r
91 return " " + variable.getType() + " " + variable.getName() + range + "(" + each+ " start=" + value + ", " + each + " fixed=true);\n";
\r
93 // a function or array constructor {.., .., ..} is used as the initial equation -> (start, each fixed) if there are dimensions
\r
94 if(ai != null && !ai.getEnumerations().isEmpty())
\r
96 return " " + variable.getType() + " " + variable.getName() + range + "(start=" + value + ", " + each + " fixed=true);\n";
\r
102 public String getEquation(IndependentVariable variable) {
\r
104 // Build range e.g. Stock[2,3]
\r
105 String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());
\r
107 // Stock equation is always der(Stock)
\r
108 StringBuilder b = new StringBuilder();
\r
110 .append(variable.getName() + range)
\r
113 // Stock equation is formed automatically using incoming and outgoing flows (actually the nearest valves in those flows)
\r
114 ArrayList<Valve> incoming = ((Stock)variable).getIncomingValves();
\r
115 ArrayList<Valve> outgoing = ((Stock)variable).getOutgoingValves();
\r
116 if(incoming.isEmpty() && outgoing.isEmpty()) {
\r
117 // No connections, add 0 for each array index if any.
\r
118 ArrayIndexes ai = variable.getArrayIndexes();
\r
119 ArrayList<Enumeration> enumerations = null;
\r
121 enumerations = ai.getEnumerations();
\r
123 if(ai == null || enumerations == null || enumerations.isEmpty()) {
\r
126 b.append(" zeros(");
\r
127 for(int i = 0; i < enumerations.size(); i++) {
\r
128 b.append(enumerations.get(i).getEnumerationIndexes().size());
\r
129 if(i != enumerations.size() - 1)
\r
136 // incoming valves add and outgoing valves reduce the stock
\r
137 for(Valve valve : outgoing)
\r
138 b.append("\n - ").append(valve.getName() + range);
\r
139 for(Valve valve : incoming)
\r
140 b.append("\n + ").append(valve.getName() + range);
\r
143 return b.toString();
\r
147 * Check whether to use fixed=true and start=... in Modelica code
\r
150 private boolean useStartValue(IndependentVariable variable) {
\r
151 // If no variables are used in the equation, start value is used
\r
153 // First the equation is formatted and parsed
\r
154 String equation = FormatUtils.formatExpressionForModelica(variable, initialEquation);
\r
155 ExpressionParser parser = new ExpressionParser(new StringReader(equation));
\r
158 if(parser.getReferences().isEmpty()) {
\r
159 // if equation did not contain any references, start value is used
\r
162 // Check if references are references to sheets.
\r
163 // Sheet references are allowed, since sheets contain only constants
\r
164 boolean found = false;
\r
165 Set<String> references = parser.getReferences().keySet();
\r
167 // Go through each reference
\r
168 for(String reference : references) {
\r
169 // We only need the first element to know that it is a Sheet (SheetName.CellOrRange)
\r
170 reference = reference.split("\\.")[0];
\r
172 for(IElement element : variable.getParentConfiguration().getElements()) {
\r
173 if(element instanceof Book) {
\r
174 for(Sheet sheet : ((Book)element).getSheets()) {
\r
175 if(reference.equals(sheet.getName())) {
\r
185 // If there was no sheet for this reference name, return false
\r
190 } catch (ParseException e) {
\r
196 public String getInitialEquation(IndependentVariable variable) {
\r
197 // if start value is used, no initial equation is returned
\r
198 if(useStartValue(variable))
\r
200 // format the initial equation for modelica execution
\r
201 String equation = FormatUtils.formatExpressionForModelica(variable, initialEquation);
\r
202 String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());
\r
205 return " " + variable.getName() + range + " = " + equation + ";\n";
\r
210 * Return Double representation of the initial equation for given variable
\r
213 * @return Double representing the initial equation or null if initial equation is not a double
\r
215 private Double getStartValue(IndependentVariable variable) {
\r
216 Double value = null;
\r
217 ArrayList<IExpression> expressions = variable.getExpressions().getExpressions();
\r
218 if(expressions.size() == 1) {
\r
219 IExpression e = expressions.get(0);
\r
220 if(e.getInitialEquation(variable) == null) {
\r
222 value = Double.parseDouble(initialEquation);
\r
223 } catch(NumberFormatException e1) {
\r