]> gerrit.simantics Code Review - simantics/sysdyn.git/blob
9bd2b3dbae5ff086ec76e9f7ee1a7f18beb30cb3
[simantics/sysdyn.git] /
1 /*******************************************************************************\r
2  * Copyright (c) 2010, 2012 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.Set;\r
17 \r
18 import org.simantics.db.ReadGraph;\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.manager.SysdynModel;\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.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
33 import org.simantics.sysdyn.representation.utils.UnitUtils;\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 getExpression() {\r
49         return initialEquation;\r
50     }\r
51     \r
52 \r
53     @Override\r
54     public String getEquation() {\r
55         \r
56         // Build range e.g. Stock[2,3]\r
57         String range = IndexUtils.rangeToIndexes(parent, this.getArrayRange());\r
58         \r
59         // Stock equation is always der(Stock)\r
60         StringBuilder b = new StringBuilder();\r
61         b.append("    der(")\r
62         .append(parent.getName() + range)\r
63         .append(") =");\r
64         \r
65         // Stock equation is formed automatically using incoming and outgoing flows (actually the nearest valves in those flows)\r
66         ArrayList<Valve> incoming = ((Stock)parent).getIncomingValves();\r
67         ArrayList<Valve> outgoing = ((Stock)parent).getOutgoingValves();\r
68         if(incoming.isEmpty() && outgoing.isEmpty()) {\r
69             // No connections, add 0 for each array index if any.\r
70             ArrayList<Enumeration> enumerations = parent.getArrayIndexes();\r
71             if(enumerations == null || enumerations.isEmpty()) {\r
72                 b.append(" 0.0");\r
73             } else {\r
74                 b.append(" zeros(");\r
75                 for(int i = 0; i < enumerations.size(); i++) {\r
76                     b.append(enumerations.get(i).getName() + ".size");\r
77                     if(i != enumerations.size() - 1)\r
78                         b.append(", ");\r
79                 }\r
80                 b.append(")");\r
81             }\r
82 \r
83         } else {\r
84             // incoming valves add and outgoing valves reduce the stock\r
85             for(Valve valve : outgoing)\r
86                 b.append("\n        - ").append(valve.getName() + range);\r
87             for(Valve valve : incoming)\r
88                 b.append("\n        + ").append(valve.getName() + range);\r
89         }\r
90         b.append(";\n");\r
91         return b.toString();\r
92     }\r
93     \r
94     /** \r
95      * Check whether to use fixed=true and start=... in Modelica code\r
96      * @return\r
97      */\r
98     private boolean useStartValue() {\r
99         // If no variables are used in the equation, start value is used\r
100         \r
101         // First the equation is formatted and parsed\r
102         String equation = FormatUtils.formatExpressionForModelica(parent, initialEquation);\r
103         ExpressionParser parser = new ExpressionParser(new StringReader(equation));\r
104         try {\r
105             parser.expr();\r
106             if(parser.getReferences().isEmpty()) {\r
107                 // if equation did not contain any references, start value is used\r
108                 return true;\r
109             } else {\r
110                 // Check if references are references to sheets. \r
111                 // Sheet references are allowed, since sheets contain only constants\r
112                 boolean found = false;\r
113                 Set<String> references = parser.getReferences().keySet();\r
114                 \r
115                 // Go through each reference\r
116                 for(String reference : references) {\r
117                     // We only need the first element to know that it is a Sheet (SheetName.CellOrRange)\r
118                     reference = reference.split("\\.")[0]; \r
119                     found = false;\r
120                     for(IElement element : parent.getParentConfiguration().getElements()) {\r
121                         if(element instanceof Book) {\r
122                             for(Sheet sheet : ((Book)element).getSheets()) {\r
123                                 if(reference.equals(sheet.getName())) {\r
124                                     found = true;\r
125                                     break;\r
126                                 }\r
127                             }\r
128                         }\r
129                         if(found)\r
130                             break;\r
131                     }\r
132                     \r
133                     // If there was no sheet for this reference name, return false\r
134                     if(!found)\r
135                         return false;\r
136                 }\r
137             }\r
138         } catch (ParseException e) {\r
139                 e.printStackTrace();\r
140         }\r
141         return true;\r
142     }\r
143 \r
144     @Override\r
145     public String getInitialEquation() {\r
146         // if start value is used, no initial equation is returned\r
147         if(useStartValue())\r
148             return null;\r
149         // format the initial equation for modelica execution \r
150         String equation = FormatUtils.formatExpressionForModelica(parent, initialEquation, false);\r
151         String range = IndexUtils.rangeToIndexes(parent, this.getArrayRange());\r
152         if(range == null)\r
153                 range = "";\r
154         return "    " + parent.getName() + range + " = " + equation + ";\n";\r
155     }\r
156     \r
157     \r
158     /**\r
159      * Return Double representation of the initial equation for given variable\r
160      * \r
161      * @param variable\r
162      * @return Double representing the initial equation or null if initial equation is not a double\r
163      */\r
164     public Double getStartValue() {\r
165         Double value = null;\r
166         ArrayList<IExpression> expressions = parent.getExpressions();\r
167         if(expressions.size() == 1) {\r
168                 IExpression e = expressions.get(0);\r
169             if(e.getInitialEquation() == null) {\r
170                 try {\r
171                     value = Double.parseDouble(initialEquation);\r
172                 } catch(NumberFormatException e1) {\r
173                     \r
174                 }\r
175             }\r
176         }\r
177         return value;\r
178     }\r
179 \r
180     \r
181     @Override\r
182     public String validateUnits(ReadGraph graph, SysdynModel model) {\r
183         String result = UnitUtils.matchUnits(graph, model, parent.getParentConfiguration(), parent.getUnit(), initialEquation);\r
184         if(result == null) {\r
185             String integralEquation = getEquation();\r
186             if(integralEquation.contains("="))\r
187                 result = UnitUtils.matchUnits(\r
188                         graph, \r
189                         model, \r
190                         parent.getParentConfiguration(), \r
191                         parent.getUnit(), \r
192                         "(" + integralEquation.substring(integralEquation.indexOf("=") + 1, integralEquation.lastIndexOf(";")) +") * time");\r
193         }\r
194         \r
195         return result;\r
196     }\r
197 }\r