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 java.io.StringReader;
\r
15 import java.util.ArrayList;
\r
16 import java.util.Set;
\r
18 import org.simantics.objmap.annotations.GraphType;
\r
19 import org.simantics.objmap.annotations.RelatedValue;
\r
20 import org.simantics.sysdyn.SysdynResource;
\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(SysdynResource.URIs.StockExpression)
\r
41 public class StockExpression extends Expression {
\r
43 @RelatedValue(SysdynResource.URIs.StockExpression_initialEquation)
\r
44 private String initialEquation;
\r
47 public String getExpression(IndependentVariable variable) {
\r
48 return initialEquation;
\r
53 public String getEquation(IndependentVariable variable) {
\r
55 // Build range e.g. Stock[2,3]
\r
56 String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());
\r
58 // Stock equation is always der(Stock)
\r
59 StringBuilder b = new StringBuilder();
\r
61 .append(variable.getName() + range)
\r
64 // Stock equation is formed automatically using incoming and outgoing flows (actually the nearest valves in those flows)
\r
65 ArrayList<Valve> incoming = ((Stock)variable).getIncomingValves();
\r
66 ArrayList<Valve> outgoing = ((Stock)variable).getOutgoingValves();
\r
67 if(incoming.isEmpty() && outgoing.isEmpty()) {
\r
68 // No connections, add 0 for each array index if any.
\r
69 ArrayIndexes ai = variable.getArrayIndexes();
\r
70 ArrayList<Enumeration> enumerations = null;
\r
72 enumerations = ai.getEnumerations();
\r
74 if(ai == null || enumerations == null || enumerations.isEmpty()) {
\r
77 b.append(" zeros(");
\r
78 for(int i = 0; i < enumerations.size(); i++) {
\r
79 b.append(enumerations.get(i).getEnumerationIndexes().size());
\r
80 if(i != enumerations.size() - 1)
\r
87 // incoming valves add and outgoing valves reduce the stock
\r
88 for(Valve valve : outgoing)
\r
89 b.append("\n - ").append(valve.getName() + range);
\r
90 for(Valve valve : incoming)
\r
91 b.append("\n + ").append(valve.getName() + range);
\r
94 return b.toString();
\r
98 * Check whether to use fixed=true and start=... in Modelica code
\r
101 private boolean useStartValue(IndependentVariable variable) {
\r
102 // If no variables are used in the equation, start value is used
\r
104 // First the equation is formatted and parsed
\r
105 String equation = FormatUtils.formatExpressionForModelica(variable, initialEquation);
\r
106 ExpressionParser parser = new ExpressionParser(new StringReader(equation));
\r
109 if(parser.getReferences().isEmpty()) {
\r
110 // if equation did not contain any references, start value is used
\r
113 // Check if references are references to sheets.
\r
114 // Sheet references are allowed, since sheets contain only constants
\r
115 boolean found = false;
\r
116 Set<String> references = parser.getReferences().keySet();
\r
118 // Go through each reference
\r
119 for(String reference : references) {
\r
120 // We only need the first element to know that it is a Sheet (SheetName.CellOrRange)
\r
121 reference = reference.split("\\.")[0];
\r
123 for(IElement element : variable.getParentConfiguration().getElements()) {
\r
124 if(element instanceof Book) {
\r
125 for(Sheet sheet : ((Book)element).getSheets()) {
\r
126 if(reference.equals(sheet.getName())) {
\r
136 // If there was no sheet for this reference name, return false
\r
141 } catch (ParseException e) {
\r
147 public String getInitialEquation(IndependentVariable variable) {
\r
148 // if start value is used, no initial equation is returned
\r
149 if(useStartValue(variable))
\r
151 // format the initial equation for modelica execution
\r
152 String equation = FormatUtils.formatExpressionForModelica(variable, initialEquation);
\r
153 String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());
\r
156 return " " + variable.getName() + range + " = " + equation + ";\n";
\r
161 * Return Double representation of the initial equation for given variable
\r
164 * @return Double representing the initial equation or null if initial equation is not a double
\r
166 public Double getStartValue(IndependentVariable variable) {
\r
167 Double value = null;
\r
168 ArrayList<IExpression> expressions = variable.getExpressions().getExpressions();
\r
169 if(expressions.size() == 1) {
\r
170 IExpression e = expressions.get(0);
\r
171 if(e.getInitialEquation(variable) == null) {
\r
173 value = Double.parseDouble(initialEquation);
\r
174 } catch(NumberFormatException e1) {
\r