import org.simantics.db.management.ISessionContext;\r
import org.simantics.modeling.ModelingResources;\r
import org.simantics.sysdyn.SysdynResource;\r
-import org.simantics.sysdyn.utils.ConfigurationUtils;\r
+import org.simantics.sysdyn.utils.LoopUtils;\r
import org.simantics.ui.SimanticsUI;\r
import org.simantics.utils.datastructures.Pair;\r
import org.simantics.utils.datastructures.Triple;\r
\r
auto = new Button(commentGroup, support, SWT.RADIO);\r
auto.setText("Auto");\r
- auto.setSelectionFactory(new CommentRadioSelectionFactory("$$AUTO$$"));\r
- auto.addSelectionListener(new CommentSelectionListener(context, "$$AUTO$$"));\r
+ auto.setSelectionFactory(new CommentRadioSelectionFactory(AUTO));\r
+ auto.addSelectionListener(new CommentSelectionListener(context, AUTO));\r
\r
balancing = new Button(commentGroup, support, SWT.RADIO);\r
balancing.setText("B");\r
other = new Button(commentGroup, support, SWT.RADIO);\r
other.setText("other");\r
other.setSelectionFactory(new OtherCommentSelectionFactory(new String[] {null, "B", "R", AUTO}));\r
+ other.addSelectionListener(new CommentSelectionListener(context, ""));\r
\r
loopComment = new TrackedText(commentGroup, support, SWT.BORDER);\r
loopComment.setTextFactory(new OtherCommentStringPropertyFactory());\r
\r
LoopTab.this.resource = input;\r
Map<String, Object> map = new HashMap<String, Object>();\r
- List<List<Resource>> loops = ConfigurationUtils.getAllLoopsInDiagram(graph, input);\r
+ List<List<Resource>> loops = LoopUtils.getAllLoopsInDiagram(graph, input);\r
map.put("", null);\r
for (List<Resource> loop : loops) {\r
- map.put(ConfigurationUtils.cycleToString(graph, loop), loop);\r
+ map.put(LoopUtils.cycleToString(graph, loop), loop);\r
}\r
return map;\r
}\r
}\r
\r
// See if the defined loop still exists.\r
- List<List<Resource>> loops = ConfigurationUtils.getAllLoopsInDiagram(graph, input);\r
+ List<List<Resource>> loops = LoopUtils.getAllLoopsInDiagram(graph, input);\r
Resource first = itemList.get(0);\r
for (List<Resource> loop : loops) {\r
// If the loops are of different size, continue.\r
if (!match)\r
continue;\r
\r
- return ConfigurationUtils.cycleToString(graph, loop);\r
+ return LoopUtils.cycleToString(graph, loop);\r
}\r
\r
// No match found, hence empty\r
import org.simantics.databoard.Bindings;\r
import org.simantics.db.ReadGraph;\r
import org.simantics.db.Resource;\r
+import org.simantics.db.common.utils.ListUtils;\r
import org.simantics.db.exception.DatabaseException;\r
import org.simantics.db.exception.ServiceException;\r
import org.simantics.db.request.Read;\r
import org.simantics.layer0.Layer0;\r
+import org.simantics.modeling.ModelingResources;\r
import org.simantics.sysdyn.SysdynResource;\r
import org.simantics.sysdyn.elementaryCycles.ElementaryCyclesSearch;\r
import org.simantics.ui.SimanticsUI;\r
* @author Tuomas Miettinen\r
*\r
*/\r
-public class ConfigurationUtils {\r
+public class LoopUtils {\r
\r
private static class ElementaryLoopItem {\r
public int mapping;\r
}\r
}\r
\r
+ public enum LoopType {\r
+ REINFORCING,\r
+ BALANCING,\r
+ UNDEFINED\r
+ };\r
+ \r
/**\r
* Get all the loops within the diagram where the resource belongs to.\r
* @param r Resource that is studied\r
HashMap<Resource, ElementaryLoopItem> elementaryLoopItems = new HashMap<Resource, ElementaryLoopItem>();\r
for (Resource variable : variables) {\r
ArrayList<Resource> dependingVariables = new ArrayList<Resource>();\r
- // Add forward dependencies and flows.\r
+ // Add forward dependencies and flows from valves.\r
Collection<Resource> dependencies = g.getObjects(variable, sr.Variable_isTailOf);\r
for (Resource dependency : dependencies) {\r
Resource head = g.getPossibleObject(dependency, sr.Variable_HasHead);\r
- if (head != null \r
- && !g.isInstanceOf(head, sr.Module)\r
- && !g.isInstanceOf(head, sr.Cloud)) {\r
+ // Skip dependencies and flows to modules and clouds.\r
+ if (head == null \r
+ || g.isInstanceOf(head, sr.Module)\r
+ || g.isInstanceOf(head, sr.Cloud))\r
+ continue;\r
+ \r
+ if ((g.isInstanceOf(dependency, sr.Flow) && g.isInstanceOf(variable, sr.Valve))\r
+ || g.isInstanceOf(dependency, sr.Dependency)) {\r
+ // Add all dependencies\r
+ // Add (only) such flows that start from a valve.\r
dependingVariables.add(head);\r
}\r
}\r
- // Add backward flows.\r
+ // Add backward flows from stocks.\r
Collection<Resource> backwardFlows = g.getObjects(variable, sr.Variable_isHeadOf);\r
for (Resource flow : backwardFlows) {\r
if (g.isInstanceOf(flow, sr.Flow)) {\r
Resource tail = g.getPossibleObject(flow, sr.Variable_HasTail);\r
- if (tail != null && !g.isInstanceOf(tail, sr.Cloud)) {\r
+ if (tail != null && g.isInstanceOf(tail, sr.Stock)) {\r
+ // Add (only) such flows that start from a stock.\r
dependingVariables.add(tail);\r
}\r
}\r
}\r
return sb.toString();\r
}\r
+ \r
+ /**\r
+ * Get the type of the loop, i.e. whether the loop is reinforcing or balancing.\r
+ * The type is determined based on the dependency arrows and flows on the diagram;\r
+ * the loop is balancing if there is odd number of dependencies with negative\r
+ * polarity (Polarity = "-"). Note:\r
+ * 1) each flow of which tail is a valve is considered a dependency with positive \r
+ * (+) polarity.\r
+ * 2) each flow of which tail is a stock is considered a dependency with negative \r
+ * (-) polarity which GOES TO THE OPPOSITE DIRECTION.\r
+ * 3) the polarity of a supplementary dependency arrow overrides a flow.\r
+ * 4) the loops are defined as a list of Resources. If the set of dependencies\r
+ * between is ambiguous, the implementation may choose any possible dependency. \r
+ * 5) empty and null polarity are considered positive (+) polarities. \r
+ * @param graph\r
+ * @param resource The loop component\r
+ * @return the type of the loop. If the type cannot be determined,\r
+ * LoopType.UNDEFINED is returned\r
+ * @throws DatabaseException\r
+ */\r
+ public static LoopType getLoopType(ReadGraph graph, Resource resource) throws DatabaseException {\r
+ SysdynResource sr = SysdynResource.getInstance(graph); \r
+ ModelingResources mod = ModelingResources.getInstance(graph);\r
+ Resource loopResource = graph.getPossibleObject(resource, sr.Loop_Items);\r
+ \r
+ if (loopResource == null)\r
+ return LoopType.UNDEFINED;\r
+\r
+ boolean oddNumberOfNegativeCausalities = false;\r
+ List<Resource> loop = ListUtils.toPossibleList(graph, loopResource);\r
+ for (int i = 0; i < loop.size(); ++i) {\r
+ boolean skipBackwardFlows = false;\r
+ \r
+ // Go through forward dependencies and flows\r
+ Collection<Resource> forwardDependencies = graph.getObjects(loop.get(i), sr.Variable_isTailOf);\r
+ for (Resource dependency : forwardDependencies) {\r
+ Resource dependingVariable = graph.getSingleObject(dependency, sr.Variable_HasHead);\r
+ if (dependingVariable.equals(loop.get((i + 1) % loop.size()))) {\r
+ if (graph.isInstanceOf(dependency, sr.Flow)) {\r
+ /*\r
+ * Forward flows never affect the loop type. Allow dependency arrows \r
+ * override flows; thus don't touch skipBackwardFlows and continue.\r
+ * continue also because we may have a flow from stock, which\r
+ * is the wrong dependency and we need to keep searching.\r
+ */\r
+ continue;\r
+ }\r
+ skipBackwardFlows = true;\r
+ \r
+ Resource dependencyConnection = graph.getSingleObject(dependency, mod.ConnectionToDiagramConnection);\r
+ String polarity = (String)graph.getPossibleRelatedValue(dependencyConnection, sr.DependencyConnection_polarity, Bindings.STRING);\r
+ if ("-".equals(polarity)) {\r
+ oddNumberOfNegativeCausalities = !oddNumberOfNegativeCausalities;\r
+ } else if (polarity != null \r
+ && !"".equals(polarity)\r
+ && !"+".equals(polarity)) {\r
+ // There's something other than + in one of the dependencies\r
+ return LoopType.UNDEFINED;\r
+ }\r
+ // "+" doesn't affect loop type, consider null and "" as a "+".\r
+ break;\r
+ }\r
+ }\r
+ \r
+ if (skipBackwardFlows)\r
+ continue;\r
+ \r
+ // Backward flows from stocks.\r
+ Collection<Resource> backwardFlows = graph.getObjects(loop.get(i), sr.Variable_isHeadOf);\r
+ for (Resource flow : backwardFlows) {\r
+ if (graph.isInstanceOf(flow, sr.Flow)) {\r
+ Resource dependingVariable = graph.getSingleObject(flow, sr.Variable_HasTail);\r
+ if (dependingVariable.equals(loop.get((i + 1) % loop.size()))) {\r
+ if (graph.isInstanceOf(dependingVariable, sr.Stock)) {\r
+ // Basically, we should always end up here since all other\r
+ // possibilities have already been gone through.\r
+ oddNumberOfNegativeCausalities = !oddNumberOfNegativeCausalities;\r
+ break;\r
+ }\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ return oddNumberOfNegativeCausalities ? LoopType.BALANCING : LoopType.REINFORCING;\r
+ }\r
}\r