import org.simantics.sysdyn.representation.utils.FormatUtils;\r
import org.simantics.sysdyn.representation.utils.IndexUtils;\r
\r
+/**\r
+ * Class representing a stock expression in a variable\r
+ * \r
+ * @author Teemu Lempinen\r
+ *\r
+ */\r
@GraphType("http://www.simantics.org/Sysdyn-1.1/StockExpression")\r
public class StockExpression extends Expression {\r
\r
\r
@Override\r
public String getDeclaration(IndependentVariable variable) {\r
-// Double value = getStartValue(variable);\r
+ \r
+ // See if the start parameter is used Stock(start = x, fixed = y) \r
String value = null;\r
if(useStartValue(variable))\r
value = FormatUtils.formatExpressionForModelica(variable, initialEquation);\r
\r
+ \r
+ // Build the enumeration indexes, if there are enumerations. Stock[enumIndexes, enum2Indexes, ...]\r
ArrayIndexes ai = variable.getArrayIndexes();\r
ArrayList<Enumeration> enumerations = null;\r
if(ai != null) \r
range = sb.toString();\r
}\r
\r
- String each = "";\r
+ String each = "";\r
+ // each is required when a single value is used for all dimensions e.g. Stock[30](each start = 0) \r
if (value == null) {\r
+ // start parameter is not used, everything needs to be fixed=false\r
if(ai != null && !ai.getEnumerations().isEmpty())\r
each = "each";\r
return " " + variable.getType() + " " + variable.getName() + range + "(" + each + " fixed=false);\n";\r
} else {\r
- if(ai != null && !ai.getEnumerations().isEmpty() && getStartValue(variable) != null)\r
- each = "each";\r
- return " " + variable.getType() + " " + variable.getName() + range + "(" + each+ " start=" + value + "," + each + " fixed=true);\n";\r
+ // start parameter is used\r
+ \r
+ if(getStartValue(variable) != null) {\r
+ // a single number is used as the initial equation -> (each start, each fixed) if there are dimensions\r
+ if(ai != null && !ai.getEnumerations().isEmpty())\r
+ each = "each";\r
+ return " " + variable.getType() + " " + variable.getName() + range + "(" + each+ " start=" + value + ", " + each + " fixed=true);\n";\r
+ } else {\r
+ // a function or array constructor {.., .., ..} is used as the initial equation -> (start, each fixed) if there are dimensions\r
+ if(ai != null && !ai.getEnumerations().isEmpty())\r
+ each = "each";\r
+ return " " + variable.getType() + " " + variable.getName() + range + "(start=" + value + ", " + each + " fixed=true);\n";\r
+ }\r
}\r
}\r
\r
@Override\r
public String getEquation(IndependentVariable variable) {\r
+ \r
+ // Build range e.g. Stock[2,3]\r
String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());\r
+ \r
+ // Stock equation is always der(Stock)\r
StringBuilder b = new StringBuilder();\r
b.append(" der(")\r
.append(variable.getName() + range)\r
.append(") =");\r
+ \r
+ // Stock equation is formed automatically using incoming and outgoing flows (actually the nearest valves in those flows)\r
ArrayList<Valve> incoming = ((Stock)variable).getIncomingValves();\r
ArrayList<Valve> outgoing = ((Stock)variable).getOutgoingValves();\r
if(incoming.isEmpty() && outgoing.isEmpty()) {\r
}\r
\r
} else {\r
+ // incoming valves add and outgoing valves reduce the stock\r
for(Valve valve : outgoing)\r
b.append("\n - ").append(valve.getName() + range);\r
for(Valve valve : incoming)\r
* @return\r
*/\r
private boolean useStartValue(IndependentVariable variable) {\r
+ // If no variables are used in the equation, start value is used\r
+ \r
+ // First the equation is formatted and parsed\r
String equation = FormatUtils.formatExpressionForModelica(variable, initialEquation);\r
ExpressionParser parser = new ExpressionParser(new StringReader(equation));\r
try {\r
parser.expr();\r
if(parser.getReferences().isEmpty()) {\r
+ // if equation did not contain any references, start value is used\r
return true;\r
} else {\r
+ // Check if references are references to sheets. \r
+ // Sheet references are allowed, since sheets contain only constants\r
boolean found = false;\r
Set<String> references = parser.getReferences().keySet();\r
+ \r
+ // Go through each reference\r
for(String reference : references) {\r
- // We only need the first element to know that it is a Sheet\r
+ // We only need the first element to know that it is a Sheet (SheetName.CellOrRange)\r
reference = reference.split("\\.")[0]; \r
found = false;\r
for(IElement element : variable.getParentConfiguration().getElements()) {\r
if(found)\r
break;\r
}\r
+ \r
+ // If there was no sheet for this reference name, return false\r
if(!found)\r
return false;\r
}\r
\r
@Override\r
public String getInitialEquation(IndependentVariable variable) {\r
-// try {\r
-// Double.parseDouble(initialEquation);\r
-// return null;\r
-// } catch (Exception e){\r
-// // Has an initial equation\r
-// } \r
+ // if start value is used, no initial equation is returned\r
if(useStartValue(variable))\r
return null;\r
+ // format the initial equation for modelica execution \r
String equation = FormatUtils.formatExpressionForModelica(variable, initialEquation);\r
String range = IndexUtils.rangeToIndexes(variable, this.getArrayRange());\r
if(range == null)\r
range = "";\r
return " " + variable.getName() + range + " = " + equation + ";\n";\r
-\r
}\r
\r
\r
+ /**\r
+ * Return Double representation of the initial equation for given variable\r
+ * \r
+ * @param variable\r
+ * @return Double representing the initial equation or null if initial equation is not a double\r
+ */\r
private Double getStartValue(IndependentVariable variable) {\r
Double value = null;\r
ArrayList<IExpression> expressions = variable.getExpressions().getExpressions();\r