Enhancing Subcatchment Connectivity in InfoWorks ICM: A Step-by-Step Guide Using Ruby Scripting
Robert Dickinson
Autodesk Water Technologist for Storm Sewer and Flood | Expert in ICM InfoWorks/SWMM/Ruby | 18 Years at Innovyze/Autodesk | 51 Years with EPASWMM | Autodesk EBCS | SWMM5+
Enhancing Subcatchment Connectivity in InfoWorks ICM: A Step-by-Step Guide Using Ruby Scripting
This Ruby script is designed for use within InfoWorks ICM to associate subcatchments with the nearest node with the lowest ground level among five nodes. It performs several tasks to facilitate this connection between subcatchments and nodes in a stormwater or sewer model. Finding the correct receiving node for a subcatchment based on ground elevation is crucial for several important reasons:
## Hydrological Accuracy
Natural Flow Patterns
- Water naturally flows downhill following topographical features
- Natural drainage characteristics should not be altered to prevent system failures[3]
- Incorrect node connections can lead to unrealistic flow patterns and model inaccuracies
Critical Design Considerations
- Improper outlet selection can cause:
- Ponding above road fills
- Weakening/erosion of subgrades
- Overloading of downstream systems[3]
## Technical Requirements
Flow Direction Analysis
- Elevation and slope data help determine the likeliest manhole that would receive runoff from each subcatchment[1]
- Topography impacts overall runoff volume and flow patterns
- Slope shape (uniform, convex, concave) indicates surface and subsurface water concentration[3]
System Performance
- Incorrect connections can lead to:
- Road surface erosion
- Cut or fill failures
- Mass failures due to inadequate drainage[3]
- Proper node selection ensures the model accurately represents real-world conditions
The goal is to maintain natural drainage patterns while ensuring efficient stormwater management. Using elevation data helps identify the most appropriate receiving nodes that align with natural topography and flow paths.
Citations:
### Step-by-Step Breakdown:
1. Initial Node Selection and Array Preparation:
- The script begins by accessing the current InfoWorks ICM network (`net = WSApplication.current_network`).
- It iterates over all nodes (`hw_node` objects) and stores key attributes of each node that is currently selected. This includes the node ID, x and y coordinates, system type (e.g., stormwater, foul, etc.), and the ground level. The nodes' data is stored in an array called nodes, which will be used for further processing.
2. Start of Transaction:
- The script initiates a transaction (`net.transaction_begin`) to make changes to the network in a controlled way, ensuring all operations are performed as one atomic update.
3. Processing Selected Subcatchments:
- The script then moves on to the subcatchments (`hw_subcatchment` objects) in the network. It iterates over each subcatchment that is selected and aims to associate it with the nearest node with the lowest ground level.
For each selected subcatchment, it calculates its position (`sx` and sy) and initializes several variables to keep track of the distances to the nearest nodes of each system type.
4. Distance Calculation for Nodes:
- The script calculates the squared Euclidean distance between the subcatchment and every node in the network (`distance = ((sx - nx) (sx - nx)) + ((sy - ny) (sy - ny))`). The distance value is squared to simplify the calculations, avoiding the computational overhead of square roots.
- Each node’s ID, system type, and ground level are also stored in an array called nodes_with_distances, allowing easy reference later.
A Smart Approach to Node Assignment
This Ruby script is designed for use within InfoWorks ICM to associate subcatchments with the nearest node that has the lowest ground level among a selection of nodes. It performs several tasks to facilitate this connection between subcatchments and nodes in a stormwater or sewer model.
### Step-by-Step Breakdown:
1. Initial Node Selection and Array Preparation:
- The script begins by accessing the current InfoWorks ICM network (`net = WSApplication.current_network`).
- It iterates over all nodes (`hw_node` objects) and stores key attributes of each node that is currently selected. This includes the node ID, x and y coordinates, system type (e.g., stormwater, foul, etc.), and the ground level. The nodes' data is stored in an array called nodes, which will be used for further processing.
2. Start of Transaction:
- The script initiates a transaction (`net.transaction_begin`) to make changes to the network in a controlled way, ensuring all operations are performed as one atomic update.
3. Processing Selected Subcatchments:
- The script then moves on to the subcatchments (`hw_subcatchment` objects) in the network. It iterates over each subcatchment that is selected and aims to associate it with the nearest node with the lowest ground level.
For each selected subcatchment, it calculates its position (`sx` and sy) and initializes several variables to keep track of the distances to the nearest nodes of each system type.
4. Distance Calculation for Nodes:
- The script calculates the squared Euclidean distance between the subcatchment and every node in the network (`distance = ((sx - nx) (sx - nx)) + ((sy - ny) (sy - ny))`). The distance value is squared to simplify the calculations, avoiding the computational overhead of square roots.
- Each node’s ID, system type, and ground level are also stored in an array called nodes_with_distances, allowing easy reference later.
5. Sorting and Selection of Nearest Nodes:
- Once all distances are computed, the script sorts the nodes by distance (`sorted_nodes = nodes_with_distances.sort_by { |node| node[:distance] }`).
- It selects the five closest nodes (`nearest_5_nodes = sorted_nodes.first(5)`) and further analyzes these nodes to determine which one has the lowest ground level (`lowest_ground_level_node = nearest_5_nodes.min_by { |node| node[:ground_level] }`).
6. Updating Subcatchments:
- The subcatchment (`s`) is then updated with the ID of the nearest node that has the lowest ground level (`s.node_id = lowest_ground_level_node[:id]`).
- If such a node is found, the script increments the changed_nodes_count counter and writes the changes (`s.write`).
7. Commit Changes:
- After all subcatchments are processed, the transaction is committed (`net.transaction_commit`), meaning all updates are saved to the network in InfoWorks ICM.
- The script then prints out the total number of nodes that were checked and updated (`puts "Number of nodes checked: #{changed_nodes_count}"`).
### Summary of Purpose:
This script efficiently connects subcatchments to nodes in a network, prioritizing the nearest node with the lowest ground level, which is particularly useful for accurately modeling overland flow and runoff routing in a complex urban drainage system. By selecting the lowest ground-level node among the closest nodes, the script ensures that the subcatchment's connectivity is realistically represented, contributing to more accurate hydrodynamic simulation results.
For data integrity, the process is wrapped in a transaction, and using sorted nodes allows for a targeted association to ensure hydraulic consistency. This is especially important in modeling situations where the exact representation of subcatchment dynamics is needed.
Location of the Ruby Code on the Innovyze GitHub
net = WSApplication.current_network
nodes = Array.new
net.row_object_collection('hw_node').each do |n|
if n.selected?
temp = Array.new
temp << n.id
temp << n.x
temp << n.y
temp << n.system_type
temp << n.ground_level # Assuming ground_level is an attribute of the node
nodes << temp
end
end
net.transaction_begin
changed_nodes_count = 0
net.row_object_collection('hw_subcatchment').each do |s|
if s.selected?
node_system_type = ''
sx = s.x
sy = s.y
nearest_distance = 999999999.9
nearest_storm_distance = 999999999.9
nearest_foul_distance = 999999999.9
nearest_sanitary_distance = 999999999.9
nearest_combined_distance = 999999999.9
nearest_overland_distance = 999999999.9
nearest_other_distance = 999999999.9
# Array to store nodes with their distances
nodes_with_distances = []
(0...nodes.size).each do |i|
nx = nodes[i][1]
ny = nodes[i][2]
n_id = nodes[i][0]
distance = ((sx - nx) * (sx - nx)) + ((sy - ny) * (sy - ny))
node_system_type = nodes[i][3].downcase
ground_level = nodes[i][4] # Assuming ground_level is the 5th element in the nodes array
# Store the node with its distance
nodes_with_distances << { id: n_id, distance: distance, system_type: node_system_type, ground_level: ground_level }
end
# Sort the nodes based on distance
sorted_nodes = nodes_with_distances.sort_by { |node| node[:distance] }
# Select the nearest 5 nodes
nearest_5_nodes = sorted_nodes.first(5)
# Print the sorted nodes and their ground levels
#puts "Sorted nodes and their ground levels:"
#nearest_5_nodes.each do |node|
#puts "Node ID: #{node[:id]}, Distance: #{node[:distance]}, Ground Level: #{node[:ground_level]}"
#end
# Find the node with the lowest ground level among the nearest 5 nodes
lowest_ground_level_node = nearest_5_nodes.min_by { |node| node[:ground_level] }
# Update the subcatchment with the nearest node with the lowest ground level
if lowest_ground_level_node
s.node_id = lowest_ground_level_node[:id]
changed_nodes_count += 1
end
s.write
end
end
net.transaction_commit
puts "Number of nodes checked: #{changed_nodes_count}"
ICM Ruby Scripting & Drainage Quiz
Closing Note:
Thank you for reading these articles. I appreciate your engagement and support. Thank you again, and I hope you'll join me on this ongoing journey of learning and discovery. Until next time!
The articles in this newsletter highlight temporal asymmetries. They discuss topics that, while only universally relevant at some times, become crucial for those in need. These pieces are resources, and they are ready to let you know and help when specific circumstances arise.
Principal Engineer (wastewater network modeller) at WSP - EX Jacobs/EX AECOM/EX STANTEC - InfoWorks ICM
1 周Thanks for sharing! I generally follow a similar approach for sub-catchment assignments but using SQL scripts. Adding elevation to the sub-catchment (i.e., centroid) using digital terrain model increases the confidence and bit more accuracy.