]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
6c30e6bab7bbe546f355a519986196d329889bd3
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2010 Association for Decentralized Information Management in\r
3  * Industry THTH ry.\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
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.sysdyn.representation.expressions;\r
13 \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
18 \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
34 \r
35 /**\r
36  * Class representing a stock expression in a variable\r
37  * \r
38  * @author Teemu Lempinen\r
39  *\r
40  */\r
41 @GraphType(SysdynResource.URIs.StockExpression)\r
42 public class StockExpression extends Expression {\r
43 \r
44     @RelatedValue(SysdynResource.URIs.StockExpression_initialEquation)\r
45     private String initialEquation;\r
46 \r
47     @Override\r
48     public String getDeclaration(IndependentVariable variable) {\r
49         \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
54         \r
55         \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
59         if(ai != null) \r
60                 enumerations = ai.getEnumerations();\r
61         \r
62         String range = "";\r
63         if(enumerations != null && enumerations.size() > 0) {\r
64                 StringBuilder sb = new StringBuilder();\r
65                 sb.append("[");\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
70                                 sb.append(", ");\r
71                         }\r
72                 }\r
73                 sb.append("]");\r
74                 range = sb.toString();\r
75         }\r
76         \r
77         String each = "";\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
82                 each = "each";\r
83             return "    " + variable.getType() + " " + variable.getName() + range + "(" + each + " fixed=false);\n";\r
84         } else {\r
85             // start parameter is used\r
86             \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
90                     each = "each";\r
91                 return "    " + variable.getType() + " " + variable.getName() + range + "(" + each+ " start=" + value + ", " + each + " fixed=true);\n";\r
92             } else {\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
95                     each = "each";\r
96                 return "    " + variable.getType() + " " + variable.getName() + range + "(start=" + value + ", " + each + " fixed=true);\n";\r
97             }\r
98         }\r
99     }\r
100 \r
101     @Override\r
102     public String getEquation(IndependentVariable variable) {\r
103         \r
104         // Build range e.g. Stock[2,3]\r
105         String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());\r
106         \r
107         // Stock equation is always der(Stock)\r
108         StringBuilder b = new StringBuilder();\r
109         b.append("    der(")\r
110         .append(variable.getName() + range)\r
111         .append(") =");\r
112         \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
120             if(ai != null) \r
121                 enumerations = ai.getEnumerations();\r
122             \r
123             if(ai == null || enumerations == null || enumerations.isEmpty()) {\r
124                 b.append(" 0.0");\r
125             } else {\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
130                         b.append(", ");\r
131                 }\r
132                 b.append(")");\r
133             }\r
134 \r
135         } else {\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
141         }\r
142         b.append(";\n");\r
143         return b.toString();\r
144     }\r
145     \r
146     /** \r
147      * Check whether to use fixed=true and start=... in Modelica code\r
148      * @return\r
149      */\r
150     private boolean useStartValue(IndependentVariable variable) {\r
151         // If no variables are used in the equation, start value is used\r
152         \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
156         try {\r
157             parser.expr();\r
158             if(parser.getReferences().isEmpty()) {\r
159                 // if equation did not contain any references, start value is used\r
160                 return true;\r
161             } else {\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
166                 \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
171                     found = false;\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
176                                     found = true;\r
177                                     break;\r
178                                 }\r
179                             }\r
180                         }\r
181                         if(found)\r
182                             break;\r
183                     }\r
184                     \r
185                     // If there was no sheet for this reference name, return false\r
186                     if(!found)\r
187                         return false;\r
188                 }\r
189             }\r
190         } catch (ParseException e) {\r
191         }\r
192         return true;\r
193     }\r
194 \r
195     @Override\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
199             return null;\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
203         if(range == null)\r
204                 range = "";\r
205         return "    " + variable.getName() + range + " = " + equation + ";\n";\r
206     }\r
207     \r
208     \r
209     /**\r
210      * Return Double representation of the initial equation for given variable\r
211      * \r
212      * @param variable\r
213      * @return Double representing the initial equation or null if initial equation is not a double\r
214      */\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
221                 try {\r
222                     value = Double.parseDouble(initialEquation);\r
223                 } catch(NumberFormatException e1) {\r
224                     \r
225                 }\r
226             }\r
227         }\r
228         return value;\r
229     }\r
230 \r
231 \r
232 }\r