为了描述物质在静态树T_S上的下游传输过程，引入了动态树T_D的概念。动态树结合了静态树的拓扑结构和相应的链接长度值，通过假设在河网所有源同时注入染料，且染料以恒定速度沿所有流向下游传播（流入是连续且速率恒定的）。这一概念的引入使得能够从动态角度研究河网中物质的传输过程，为理解河网的功能和动态特性提供了新的视角。以一个有四个源（a, b, c, d）的流域为例，其静态树为完全二叉树。在构建动态树时，初始时（步骤 0），所有链路为空（虚线表示），染料注入到 a、b、c、d 四个源，此时动态树有四个不相连的节点。随着时间推移，每一步染料向下游传播一个单位长度（假设速度为 1）。在步骤 1，四条溪流仍不相连，动态树有四个不相连的分支。步骤 2 时，溪流 a 和 b 合并，动态树中 a 和 b 节点连接成一个集群。步骤 3，溪流 c 与已合并的 a、b 集群合并，此时动态树有两个相连的集群。到步骤 4，所有有色通量合并，完成动态树的构建。
以下为相关代码，请根据上述信息帮我检查代码是否有误，并进行修正
def parse_inp_file(filepath):
    with open(filepath, 'r') as file:
        content = file.readlines()

    junctions = []
    conduits = []
    current_section = None

    for line in content:
        # 去除行两端的空白字符
        line = line.strip()

        # 跳过空行
        if not line:
            continue

        # Check for section headers
        if line.startswith("["):
            current_section = line.strip().replace("[", "").replace("]", "").strip()
            continue

        # Parse JUNCTIONS section
        if current_section == "JUNCTIONS" and not line.startswith(";;"):
            parts = line.split()
            junctions.append({
                'Name': parts[0],
                'Elevation': float(parts[1]),
                'MaxDepth': float(parts[2]),
                'InitDepth': float(parts[3]),
                'SurDepth': float(parts[4]),
                'Aponded': float(parts[5])
            })
        # Parse OUTFALLS section
        if current_section == "OUTFALLS" and not line.startswith(";;"):
            parts = line.split()
            junctions.append({
                'Name': parts[0],
                'Elevation': float(parts[1]),
            })

        # Parse CONDUITS section
        elif current_section == "CONDUITS" and not line.startswith(";;"):
            parts = line.split()
            conduits.append({
                'Name': parts[0],
                'FromNode': parts[1],
                'ToNode': parts[2],
                'Length': float(parts[3]),
                'Roughness': float(parts[4]),
                'InOffset': float(parts[5]),
                'OutOffset': float(parts[6]),
                'InitFlow': float(parts[7]),
                'MaxFlow': float(parts[8])
            })

    return junctions, conduits


def create_graph(junctions, conduits):
    G = nx.DiGraph()

    # Add junctions to the graph
    for junction in junctions:
        G.add_node(junction['Name'], elevation=junction['Elevation'])

    # Add conduits to the graph as directed edges
    for conduit in conduits:
        G.add_edge(conduit['FromNode'], conduit['ToNode'], length=conduit['Length'], roughness=conduit['Roughness'])

    return G


def identify_sources(graph):
    # 节点没有入边且有出边的为源头
    sources = [node for node in graph.nodes() if graph.in_degree(node) == 0 and graph.out_degree(node) > 0]
    return sources


def create_dynamic_tree(static_graph, sources, constant_injection_rate):
    dynamic_tree = nx.DiGraph()
    arrival_times = {node: float('inf') for node in static_graph.nodes()}
    paths = {node: [] for node in static_graph.nodes()}

    for source in sources:
        arrival_times[source] = 0
        dynamic_tree.add_node(source, arrival_time=0, is_merge_node=False)
        paths[source] = [source]  # Path back to source is just the source itself

    step = 0
    while True:
        current_merges = {}
        for node in nx.topological_sort(static_graph):
            if arrival_times[node] == float('inf'):
                continue

            for neighbor in static_graph.neighbors(node):
                edge_length = static_graph[node][neighbor]['length']
                arrival_time_to_neighbor = arrival_times[node] + (edge_length / constant_injection_rate)

                # If the arrival time to the neighbor is earlier, update it and add the edge
                if arrival_time_to_neighbor < arrival_times[neighbor]:
                    arrival_times[neighbor] = arrival_time_to_neighbor
                    dynamic_tree.add_node(neighbor, arrival_time=arrival_time_to_neighbor, is_merge_node=False)
                    dynamic_tree.add_edge(node, neighbor, propagation_time=edge_length / constant_injection_rate)
                    paths[neighbor] = paths[node] + [neighbor]  # Update path information
                elif arrival_time_to_neighbor == arrival_times[neighbor]:
                    # If multiple sources reach at the same time, mark it as a merge
                    if neighbor not in current_merges:
                        current_merges[neighbor] = []
                    current_merges[neighbor].append(node)

        # Process merges at this step
        for neighbor, upstream_nodes in current_merges.items():
            for upstream_node in upstream_nodes:
                if neighbor not in dynamic_tree.nodes:
                    dynamic_tree.add_node(neighbor, arrival_time=arrival_times[neighbor], is_merge_node=True)
                dynamic_tree.add_edge(upstream_node, neighbor)

        # Stop if all sources have merged into one node
        if len(arrival_times) - sum(1 for v in arrival_times.values() if v == float('inf')) <= 1:
            break

        step += 1

    return dynamic_tree

inp_file_path = 'benchmark2.inp'
# Parse the INP file
junctions, conduits = parse_inp_file(inp_file_path)

# Create a directed graph from the parsed data
graph = create_graph(junctions, conduits)

# 自动识别源头节点
sources = identify_sources(graph)

# 假设染料注入的恒定速度
constant_injection_rate = 1.0  # 根据需要设置

# 创建动态树
dynamic_tree = create_dynamic_tree(graph, sources, constant_injection_rate)