2

The map below is based on test data generated by the code that follows.

enter image description here

That code:

  1. Creates a file geodatabase (test.gdb), with a feature dataset (TestFD), and in that feature dataset there are two point feature classes (ValveTypeA and ValveTypeB) and a line feature class (TestLines)
  2. ValveTypeA, ValveTypeB and TestLines are used to create a geometric network (TestFD_Net) with its flow direction set by its digitized direction
  3. ValveTypeA and ValveTypeB both have a field "Type" with values "A" and "B" respectively and these are concatenated with the OBJECTID to see the labels in the map above.
  4. Another point feature class (FlagFC) is in the feature dataset but does not participate in the geometric network. Instead it is used as the flag to run two geometric network traces that are designed to find the isolation valves from FlagFC by first disabling ValveTypeA, and then disabling ValveTypeB
  5. Running the code correctly finds A1 and A2 as being the isolation valves when ValveTypeA is disabled; and correctly finds B1 and B4 as being the isolation valves when ValveTypeB is disabled
  6. The last line of the code merges ValveTypeA and ValveTypeB into a single feature class ValveTypesCombined

I think I have shown how I can find isolation valves for a valve type when those valve types are kept in separate feature classes within the feature dataset used to create the geometric network.

However, in the much more complicated geometric network which I am working on for a water utility, they have modelled their valve types in the same point feature class with an attribute to distinguish their types i.e. like in my ValveTypesCombined.

Is it possible to perform an isolation valve trace that can "pass through" one valve type and look for the other valve type to stop it?

In the example below I would like to be able to use ValvesCombined to find the valves of type "B" that can isolate FlagFC without the trace being stopped first by the valves of type "A".

`>>>` 

====== RESTART: C:\Temp\CreateTestGeometricNetwork.py =====

Isolation Valves for ValveTypeA: ['A1', 'A2']

Isolation Valves for ValveTypeB: ['B1', 'B4']

`>>>` 

import arcpy

if arcpy.Exists("C:/Temp/test.gdb"):
    arcpy.Delete_management("C:/Temp/test.gdb")
arcpy.CreateFileGDB_management("C:/Temp","test")
arcpy.CreateFeatureDataset_management("C:/Temp/test.gdb","TestFD","#")

arcpy.CreateFeatureclass_management("C:/Temp/test.gdb/TestFD","TestLines","POLYLINE","#","DISABLED","DISABLED","#","#","0","0","0")
cursor = arcpy.da.InsertCursor("C:/Temp/test.gdb/TestFD/TestLines", ["SHAPE@"])
array = arcpy.Array([arcpy.Point(2,0),arcpy.Point(2,1)])
polyline = arcpy.Polyline(array)
cursor.insertRow([polyline])
array = arcpy.Array([arcpy.Point(2,1),arcpy.Point(1,2)])
polyline = arcpy.Polyline(array)
cursor.insertRow([polyline])
array = arcpy.Array([arcpy.Point(2,1),arcpy.Point(3,2)])
polyline = arcpy.Polyline(array)
cursor.insertRow([polyline])
array = arcpy.Array([arcpy.Point(1,2),arcpy.Point(1,3)])
polyline = arcpy.Polyline(array)
cursor.insertRow([polyline])
array = arcpy.Array([arcpy.Point(1,3),arcpy.Point(0,4)])
polyline = arcpy.Polyline(array)
cursor.insertRow([polyline])
array = arcpy.Array([arcpy.Point(1,3),arcpy.Point(2,4)])
polyline = arcpy.Polyline(array)
cursor.insertRow([polyline])
array = arcpy.Array([arcpy.Point(3,2),arcpy.Point(3,3),arcpy.Point(4,4)])
polyline = arcpy.Polyline(array)
cursor.insertRow([polyline])
del cursor

arcpy.CreateFeatureclass_management("C:/Temp/test.gdb/TestFD","ValveTypeA","POINT","#","DISABLED","DISABLED","#","#","0","0","0")
cursor = arcpy.da.InsertCursor("C:/Temp/test.gdb/TestFD/ValveTypeA", ["SHAPE@XY"])
cursor.insertRow([[1,2]])
cursor.insertRow([[3,2]])
del cursor
arcpy.AddField_management("C:/Temp/test.gdb/TestFD/ValveTypeA","Type","TEXT","","","1")
arcpy.CalculateField_management("C:/Temp/test.gdb/TestFD/ValveTypeA","Type",'"A"',"PYTHON_9.3")

arcpy.CreateFeatureclass_management("C:/Temp/test.gdb/TestFD","ValveTypeB","POINT","#","DISABLED","DISABLED","#","#","0","0","0")
cursor = arcpy.da.InsertCursor("C:/Temp/test.gdb/TestFD/ValveTypeB", ["SHAPE@XY"])
cursor.insertRow([[1,3]])
cursor.insertRow([[0,4]])
cursor.insertRow([[2,4]])
cursor.insertRow([[4,4]])
del cursor
arcpy.AddField_management("C:/Temp/test.gdb/TestFD/ValveTypeB","Type","TEXT","","","1")
arcpy.CalculateField_management("C:/Temp/test.gdb/TestFD/ValveTypeB","Type",'"B"',"PYTHON_9.3")

arcpy.CreateFeatureclass_management("C:/Temp/test.gdb/TestFD","FlagFC","POINT","#","DISABLED","DISABLED","#","#","0","0","0")
cursor = arcpy.da.InsertCursor("C:/Temp/test.gdb/TestFD/FlagFC", ["SHAPE@XY"])
cursor.insertRow([[2,0]])
del cursor

arcpy.CreateGeometricNetwork_management("C:/Temp/test.gdb/TestFD","TestFD_Net",
                                        "TestLines SIMPLE_EDGE NO;ValveTypeA SIMPLE_JUNCTION NO;ValveTypeB SIMPLE_JUNCTION NO",
                                        "#","#","#","#","PRESERVE_ENABLED")
arcpy.SetFlowDirection_management("C:/Temp/test.gdb/TestFD/TestFD_Net","WITH_DIGITIZED_DIRECTION")

arcpy.TraceGeometricNetwork_management(
    "C:/Temp/test.gdb/TestFD/TestFD_Net",
    r"in_memory\{0}".format("TestFD_Net_group_layer"),
    "C:/Temp/test.gdb/TestFD/FlagFC",
    "FIND_CONNECTED","","","","","ValveTypeA",
    "TRACE_ENDS","","","","AS_IS","","","","AS_IS")

isolationValves = []
for layer in arcpy.mapping.Layer(r"in_memory\{0}".format("TestFD_Net_group_layer")):
    for x in arcpy.mapping.ListLayers(layer):
        if x.name == "ValveTypeA":
            with arcpy.da.SearchCursor("ValveTypeA", ['Type','OBJECTID']) as rows:
                for row in rows:
                    isolationValves.append("{0}{1}".format(row[0],row[1]))
print("Isolation Valves for ValveTypeA: {0}".format(isolationValves))

arcpy.Delete_management(r"in_memory\{0}".format("TestFD_Net_group_layer"))

arcpy.TraceGeometricNetwork_management(
    "C:/Temp/test.gdb/TestFD/TestFD_Net",
    r"in_memory\{0}".format("TestFD_Net_group_layer"),
    "C:/Temp/test.gdb/TestFD/FlagFC",
    "FIND_CONNECTED","","","","","ValveTypeB",
    "TRACE_ENDS","","","","AS_IS","","","","AS_IS")

isolationValves = []
for layer in arcpy.mapping.Layer(r"in_memory\{0}".format("TestFD_Net_group_layer")):
    for x in arcpy.mapping.ListLayers(layer):
        if x.name == "ValveTypeB":
            with arcpy.da.SearchCursor("ValveTypeB", ['Type','OBJECTID']) as rows:
                for row in rows:
                    isolationValves.append("{0}{1}".format(row[0],row[1]))
print("Isolation Valves for ValveTypeB: {0}".format(isolationValves))

arcpy.Merge_management("C:/Temp/test.gdb/TestFD/ValveTypeA;C:/Temp/test.gdb/TestFD/ValveTypeB",
                       "C:/Temp/test.gdb/TestFD/ValveTypesCombined")

I am using a Standard Level license of ArcGIS Desktop 10.5.1 for my testing away from the site, but onsite I am using a Standard Level license of ArcGIS Desktop 10.2.1.

  • My favourite geometric network & tracing toolset is Esri's ArcGIS for Water Utilities. The trace tools have an extra option Operable which you can set to determine whether a valve can be operated or not. If the valve is not operable the trace continues through to the next valve that is operable. I can't remember but I think these tools are available through arcpy (we certainly did scripted traces, but I don't recall if the operable flag was usable through these traces). – Midavalo Nov 26 '17 at 16:36
  • Thanks @Midavalo A quick search (google.com/search?q=ArcGIS+Water+Utilities+arcpy+operable) did not turn up any leads, and I am near the end of this assignment, but I will bear that in mind if I encounter similar requirements and have more time to investigate. – PolyGeo Nov 26 '17 at 22:22
  • Take a look at solutions.arcgis.com/utilities/water/help/network-editing/… - there are definitely Python tools included in the solution, which includes the trace ability. It may require a download and test. I'll see if I can find some time to give it a go (I no longer have access to the one I used for years) – Midavalo Nov 27 '17 at 1:13
  • Thanks @Midavalo - that looks very interesting, but for next time I have Water Utility requirements rather than this time where I think I now have a solution that will work for me. – PolyGeo Nov 27 '17 at 4:32
3

You would need to provide the in_barriers parameter to TraceGeometricNetwork_management containing point features representing the junctions (or edges) that should stop the trace.

2

The answer by @nef001 put me back on the right track to my solution which is illustrated by adding the code below to the bottom of the original test (and replacing the last Merge_management line of that).

The new code:

  1. Creates a second feature dataset (TestFD2)
  2. Writes the result of the Merge in TestFD2
  3. Copies the TestLines from TestFD to be called TestLines2 in TestFD2
  4. Creates a new geometric network in TestFD2 called TestFD_Net_2 and sets the flow direction on that
  5. Selects the Type B valves (ValveTypeCombB) from ValveTypesCombined so that they can be used as barriers in the next step
  6. Runs the Trace Geometric Network with slightly different settings than in the question
  7. Correctly identifies B3 and B6 (see picture) as the isolation valves when Type A valves are ignored, and the trace is let to run until it hits a Type B valve (barrier)

>>>

===== RESTART: C:\Temp\CreateTestGeometricNetwork.py =====

Isolation Valves for ValveTypeA: ['A1', 'A2']

Isolation Valves for ValveTypeB: ['B1', 'B4']

Isolation Valves for ValveTypesCombined: ['B3', 'B6']

>>>

enter image description here

arcpy.CreateFeatureDataset_management("C:/Temp/test.gdb","TestFD2","#")
arcpy.Merge_management("C:/Temp/test.gdb/TestFD/ValveTypeA;C:/Temp/test.gdb/TestFD/ValveTypeB",
                       "C:/Temp/test.gdb/TestFD2/ValveTypesCombined")
arcpy.CopyFeatures_management("C:/Temp/test.gdb/TestFD/TestLines","C:/Temp/test.gdb/TestFD2/TestLines2")

arcpy.CreateGeometricNetwork_management("C:/Temp/test.gdb/TestFD2","TestFD_Net_2",
                                        "TestLines2 SIMPLE_EDGE NO;ValveTypesCombined SIMPLE_JUNCTION NO",
                                        "#","#","#","#","PRESERVE_ENABLED")
arcpy.SetFlowDirection_management("C:/Temp/test.gdb/TestFD2/TestFD_Net_2","WITH_DIGITIZED_DIRECTION")

arcpy.Select_analysis("C:/Temp/test.gdb/TestFD2/ValveTypesCombined","C:/Temp/test.gdb/TestFD2/ValveTypeCombB","Type = 'B'")

arcpy.TraceGeometricNetwork_management(
    "C:/Temp/test.gdb/TestFD2/TestFD_Net_2",
    r"in_memory\{0}".format("TestFD_Net_2_group_layer"),
    "C:/Temp/test.gdb/TestFD/FlagFC",
    "FIND_CONNECTED","C:/Temp/test.gdb/TestFD2/ValveTypeCombB","","","","",
    "TRACE_ENDS","","","","AS_IS","","","","AS_IS")

isolationValves = []
for layer in arcpy.mapping.Layer(r"in_memory\{0}".format("TestFD_Net_2_group_layer")):
    for x in arcpy.mapping.ListLayers(layer):
        if x.name == "ValveTypesCombined":
            with arcpy.da.SearchCursor("ValveTypesCombined", ['Type','OBJECTID']) as rows:
                for row in rows:
                    isolationValves.append("{0}{1}".format(row[0],row[1]))
print("Isolation Valves for ValveTypesCombined: {0}".format(isolationValves))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.