]> gerrit.simantics Code Review - simantics/sysdyn.git/commitdiff
Automatic balancing / reinforcing comment (B/R) for Sysdyn loops (refs #3012).
authormiettinen <miettinen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Tue, 21 Jan 2014 11:43:46 +0000 (11:43 +0000)
committermiettinen <miettinen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Tue, 21 Jan 2014 11:43:46 +0000 (11:43 +0000)
git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@28681 ac1ea38d-2e2b-0410-8846-a27921b304fc

org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/elements/LoopFactory.java
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/properties/LoopTab.java
org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/structure/LoopGraphRequest.java
org.simantics.sysdyn/src/org/simantics/sysdyn/utils/LoopUtils.java [moved from org.simantics.sysdyn/src/org/simantics/sysdyn/utils/ConfigurationUtils.java with 58% similarity]

index e8f11057555cca39e780dd9bb298de7e239173ab..c5c8727ae005501b6463adacb75f7946434a9ced 100644 (file)
@@ -66,6 +66,7 @@ import org.simantics.scenegraph.g2d.nodes.SVGNode;
 import org.simantics.scenegraph.g2d.nodes.ShapeNode;\r
 import org.simantics.sysdyn.SysdynResource;\r
 import org.simantics.sysdyn.ui.properties.LoopTab;\r
+import org.simantics.sysdyn.utils.LoopUtils;\r
 import org.simantics.ui.SimanticsUI;\r
 import org.simantics.utils.datastructures.Callback;\r
 import org.simantics.utils.datastructures.hints.IHintContext.Key;\r
@@ -135,8 +136,20 @@ public class LoopFactory extends SysdynElementFactory {
                if (component != null) {\r
                        text = (String) graph.getPossibleRelatedValue(component, sr.Loop_Comment);\r
                }\r
-               if (text == null || LoopTab.AUTO.equals(text))\r
+               if (text == null)\r
                        text = "";\r
+               else if (LoopTab.AUTO.equals(text)) {\r
+                       switch (LoopUtils.getLoopType(graph, component)) {\r
+                       case BALANCING:\r
+                               text = "B";\r
+                               break;\r
+                       case REINFORCING:\r
+                               text = "R";\r
+                               break;\r
+                       default:\r
+                               text = "";\r
+                       }\r
+               }\r
                return text;\r
        }\r
 \r
index 0b770e37c4c873f0cfd356e54ff4162e7f598f50..b8fb2f06a36c8e4e85416a1fe3a82ca2f585f72f 100644 (file)
@@ -43,7 +43,7 @@ import org.simantics.db.exception.DatabaseException;
 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
@@ -79,8 +79,8 @@ public class LoopTab extends AdjustableTab {
         \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
@@ -95,6 +95,7 @@ public class LoopTab extends AdjustableTab {
         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
@@ -125,10 +126,10 @@ public class LoopTab extends AdjustableTab {
 \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
@@ -152,7 +153,7 @@ public class LoopTab extends AdjustableTab {
                                }\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
@@ -181,7 +182,7 @@ public class LoopTab extends AdjustableTab {
                                        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
index f9b7c8740b4a254e5587d11ab9df1ab290a9105a..6063be5c666e6a72721bec43c7a7eda89bb68751 100644 (file)
@@ -23,7 +23,7 @@ import org.simantics.graphviz.IGraph;
 import org.simantics.graphviz.Node;\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.utils.datastructures.MapList;\r
 \r
 /**\r
@@ -62,7 +62,7 @@ public class LoopGraphRequest extends DependencyGraphRequest {
                SysdynResource sr = SysdynResource.getInstance(g);\r
                if (g.isInstanceOf(root, sr.IndependentVariable) || g.isInstanceOf(root, sr.Input)) {\r
                        // Get ALL loops in the diagram in which the root exists.\r
-                       List<List<Resource>> loops = ConfigurationUtils.getLoops(g, root);\r
+                       List<List<Resource>> loops = LoopUtils.getLoops(g, root);\r
                        setRoot(g, graph, root);\r
                        \r
                        // Add the edges to the graph.\r
similarity index 58%
rename from org.simantics.sysdyn/src/org/simantics/sysdyn/utils/ConfigurationUtils.java
rename to org.simantics.sysdyn/src/org/simantics/sysdyn/utils/LoopUtils.java
index 9f5895c4abd0ea556cea987ea6b4d92594ad8970..130ebb0874cc14044149ff329faab2fbacf31864 100644 (file)
@@ -21,10 +21,12 @@ import java.util.List;
 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
@@ -34,7 +36,7 @@ import org.simantics.ui.SimanticsUI;
  * @author Tuomas Miettinen\r
  *\r
  */\r
-public class ConfigurationUtils {\r
+public class LoopUtils {\r
 \r
        private static class ElementaryLoopItem {\r
                public int mapping;\r
@@ -46,6 +48,12 @@ public class ConfigurationUtils {
                }\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
@@ -127,22 +135,30 @@ public class ConfigurationUtils {
                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
@@ -218,4 +234,90 @@ public class ConfigurationUtils {
                }\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