def test_generateRobustScenarios(injectionWithdrawalRates, graph, distances, dic_node_minPress, dic_node_maxPress): dic_robustScenarios, entries, exits \ = robustPipelineSizing.generateRobustScenarios(injectionWithdrawalRates, graph, distances, dic_node_minPress, dic_node_maxPress) # we compute optimal values for each nodePair and save them in dictionary dic_nodePair_optvalue = {} for nodePair in dic_robustScenarios.keys(): # compute path between this two nodes shortestPath = nx.shortest_path(graph, nodePair[0], nodePair[1]) obj = 0.0 for i in range(0, len(shortestPath) - 1): if (shortestPath[i], shortestPath[i + 1]) in list( dic_robustScenarios[nodePair].keys()): obj = obj + dic_robustScenarios[nodePair][ (shortestPath[i], shortestPath[i + 1])] else: obj = obj - dic_robustScenarios[nodePair][ (shortestPath[i + 1], shortestPath[i])] dic_nodePair_optvalue[nodePair] = obj return dic_robustScenarios, entries, exits, dic_nodePair_optvalue
def test_robustPipelineDesign(): # write tests for function createNetwork() # check if returned graph has the edges of the input argument: def test_createNetwork(distances): graph, newdistances = robustPipelineSizing.createNetwork(distances) # check that every arc of the graph is in the original distances matrix # check that every arc of the graph is in the new distances matrix # check that in the new distance matrix only one direction either (u,v) or (v,u) is contained for arcIndex in list(graph.edges): assert (arcIndex in distances.index or (arcIndex[1], arcIndex[0]) in distances.index) assert (arcIndex in newdistances.index or (arcIndex[1], arcIndex[0]) in newdistances.index) assert (not (arcIndex in newdistances.index and (arcIndex[1], arcIndex[0]) in newdistances.index)) # check that every arcIndex of the original distance matrix is in the graph for arcIndex in distances.index: assert (arcIndex in graph.edges or (arcIndex[1], arcIndex[0]) in graph.edges) # check that every arcIndex of new distances matrix is in the graph for arcIndex in newdistances.index: assert (arcIndex in graph.edges or (arcIndex[1], arcIndex[0]) in graph.edges) # check lengths of the graph for arcIndex in nx.get_edge_attributes(graph, 'length').keys(): if arcIndex in newdistances.index: assert (newdistances[arcIndex] == nx.get_edge_attributes( graph, 'length')[arcIndex]) else: assert (newdistances[(arcIndex[1], arcIndex[0])] == nx.get_edge_attributes( graph, 'length')[arcIndex]) return graph, newdistances # we test the function createSteinerTree def test_createSteinerTree(graph, distances): stTree, newdistances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) # check if in newDistances only arcs of the spanning tree are contained for arc in stTree.edges: # first check that only one direction of the arc is contained assert (not (arc in newdistances.index and (arc[1], arc[0]))) # check that the arc or its reversered arc is contained assert (arc in newdistances.index or (arc[1], arc[0]) in newdistances.index) # check that all arcs, respectively its reversed arc is contained in MinSpannTree for arc in newdistances.index: assert (arc in graph.edges or (arc[1], arc[0]) in graph.edges) # check weights of the graph for arc in nx.get_edge_attributes(graph, 'length').keys(): if arc in newdistances.index: assert (newdistances[arc] == nx.get_edge_attributes( graph, 'length')[arc]) else: assert (newdistances[arc] == nx.get_edge_attributes( graph, 'length')[(arc[1], arc[0])]) return stTree, newdistances def test_networkRefinement(distances, maxPipeLength, dic_node_minPress, dic_node_maxPress): G, newdistances, dic_node_minPress, dic_node_maxPress = robustPipelineSizing.networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) # check that every arc of the graph is in the distance matrix, respectively its reversed arc # check that not the arc and its reversed are contained in the distance matrix for arc in list(G.edges): assert (arc in newdistances.index or (arc[1], arc[0]) in newdistances.index) assert (not (arc in newdistances.index and (arc[1], arc[0]) in newdistances.index)) # check that every arc of new distances matrix is in the graph for arc in newdistances.index: assert (arc in G.edges or (arc[1], arc[0]) in G.edges) # check that we have a minimal and maximal pressure for every node of the graph for node in G.nodes: assert (node in dic_node_minPress.keys() and node in dic_node_maxPress.keys()) return G, newdistances, dic_node_minPress, dic_node_maxPress def test_computeSingleSpecialScenario(graph, distances, entries, exits, startNode, endNode, dic_nodes_MinCapacity, dic_nodes_MaxCapacity, specialScenario=True): dic_scenario_flow = robustPipelineSizing.computeSingleSpecialScenario( graph, distances, entries, exits, startNode, endNode, dic_nodes_MinCapacity, dic_nodes_MaxCapacity, specialScenario) # check if each arc has a flow for arc in distances.index: assert (not (arc in dic_scenario_flow.keys() and (arc[1], arc[0]) in dic_scenario_flow.keys())) assert (arc in dic_scenario_flow.keys() or (arc[1], arc[0]) in dic_scenario_flow.keys()) return dic_scenario_flow def test_generateRobustScenarios(injectionWithdrawalRates, graph, distances, dic_node_minPress, dic_node_maxPress): dic_robustScenarios, entries, exits \ = robustPipelineSizing.generateRobustScenarios(injectionWithdrawalRates, graph, distances, dic_node_minPress, dic_node_maxPress) # we compute optimal values for each nodePair and save them in dictionary dic_nodePair_optvalue = {} for nodePair in dic_robustScenarios.keys(): # compute path between this two nodes shortestPath = nx.shortest_path(graph, nodePair[0], nodePair[1]) obj = 0.0 for i in range(0, len(shortestPath) - 1): if (shortestPath[i], shortestPath[i + 1]) in list( dic_robustScenarios[nodePair].keys()): obj = obj + dic_robustScenarios[nodePair][ (shortestPath[i], shortestPath[i + 1])] else: obj = obj - dic_robustScenarios[nodePair][ (shortestPath[i + 1], shortestPath[i])] dic_nodePair_optvalue[nodePair] = obj return dic_robustScenarios, entries, exits, dic_nodePair_optvalue def checkGraphDistanceMatrixCoincide(graph, distances): # check that for every arc in the graph either the arc or its reversed arc are contained in the distance matrix for arcIndex in list(graph.edges): assert (arcIndex in distances.index or (arcIndex[1], arcIndex[0]) in distances.index) assert (not (arcIndex in distances.index and (arcIndex[1], arcIndex[0]) in distances.index)) # check that for every arc in the distance matrix either the arc or its reversed are contained in the graph for arcIndex in distances.index: assert (arcIndex in list(graph.edges) or (arcIndex[1], arcIndex[0]) in list(graph.edges)) assert (not (arcIndex in list(graph.edges) and (arcIndex[1], arcIndex[0]) in list(graph.edges))) # check lengths of the graph for arcIndex in nx.get_edge_attributes(graph, 'length').keys(): if arcIndex in distances.index: assert (distances[arcIndex] == nx.get_edge_attributes( graph, 'length')[arcIndex]) else: assert (distances[(arcIndex[1], arcIndex[0])] == nx.get_edge_attributes( graph, 'length')[arcIndex]) return # ###################################################################################################################### # unit test: createNetwork # create input data and call tests data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] invalidData = [ 1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 450.0, 600.0, 2000.0 ] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) invalidDistances = pd.Series(invalidData, index=keys) # should raise an assertion error because an arc and its reversed arc with different length exist try: graph, distances = test_createNetwork(invalidDistances) except AssertionError as error: print(error) # We create the new network try: graph, distances = test_createNetwork(distances) except AssertionError as error: print(error) print( "Something went wrong in createNetwork; check comment above assertion for error" ) # # uncomment this block if you want the graph being plotted # nx.draw(graph, with_labels=True) # plt.show() ####################################################################################################################### # unit test function: createSteinerTree # create input data for testing and the optimal solution of the minimal spanning tree data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) optimalSolution = { ('w2', 'w1'): 1200.0, ('w2', 'w3'): 750.0, ('w4', 'w3'): 500.0, ('w3', 'w5'): 600.0 } # test the minimum spanning tree function stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) # check if spanning tree is optimal for arc in stTree.edges: if arc in optimalSolution.keys(): assert (optimalSolution[arc] == nx.get_edge_attributes( stTree, 'length')[arc]) elif (arc[1], arc[0]) in optimalSolution.keys(): assert (optimalSolution[(arc[1], arc[0])] == nx.get_edge_attributes( stTree, 'length')[arc]) else: print( "Something went wrong in computation of minimum spanning tree") raise () # check that the distance matrix and the graph of the graph (spanning tree) coincide checkGraphDistanceMatrixCoincide(stTree, distances) # # uncomment the following block if you want the minimal spanning tree to be plotted # nx.draw(stTree, with_labels=True) # plt.show() ####################################################################################################################### # unit test function networkRefinement # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 # optimal solution dic_node_minPressTruth = { 'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50, 'v1_w2_w1': 47.5, 'v2_w2_w1': 47.5, 'v1_w2_w3': 52.5, 'v1_w3_w5': 55 } dic_node_maxPressTruth = { 'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95, 'v1_w2_w1': 95, 'v2_w2_w1': 95, 'v1_w2_w3': 95, 'v1_w3_w5': 97.5 } nodesTruth = list(dic_node_minPressTruth.keys()) edgesTruth = [('w2', 'v1_w2_w1'), ('v1_w2_w1', 'v2_w2_w1'), ('v2_w2_w1', 'w1'), ('w4', 'w3'), ('w2', 'v1_w2_w3'), ('w3', 'v1_w2_w3'), ('w3', 'v1_w3_w5'), ('v1_w3_w5', 'w5')] # test function networkRefinement graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) # check solution assert (sorted(edgesTruth) == sorted(list(graph.edges))) assert (sorted(nodesTruth) == sorted(list(graph.nodes))) assert (dic_node_minPress == dic_node_minPressTruth) assert (dic_node_maxPress == dic_node_maxPressTruth) # uncomment this block if you want the graph to be plotted # nx.draw(graph, with_labels=True) # plt.show() ###################################################################################################################### # unit test function computeSingleSpecialScenario Case: SpecialScenario = true # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) dic_nodes_minCapacity = {'w1': -2, 'w2': 0, 'w3': -2, 'w4': 0, 'w5': 0} dic_nodes_maxCapacity = {'w1': 0, 'w2': 1, 'w3': 2, 'w4': 0, 'w5': 4} startNode = 'w1' endNode = 'w3' # create optimal solution entries = ['w1', 'w3'] exits = ['w2', 'w3', 'w5'] optSol_W1_W2 = { ('w2', 'v1_w2_w1'): -2.0, ('v1_w2_w1', 'v2_w2_w1'): -2.0, ('v2_w2_w1', 'w1'): -2.0, ('w2', 'v1_w2_w3'): 2.0, ('v1_w2_w3', 'w3'): 2.0 } # test function computeSingleSpecialScenario dic_scenario_flow_W1_W3 = test_computeSingleSpecialScenario( graph, distances, entries, exits, startNode, endNode, dic_nodes_minCapacity, dic_nodes_maxCapacity, True) # check solution: since flow values on arcs not part of the unique path between start and endNode are not unique, # we only check the unique flow values on the path between start and endNode for arc in optSol_W1_W2.keys(): assert (dic_scenario_flow_W1_W3[arc] == optSol_W1_W2[arc]) ####################################################################################################################### # unit test function computeSingleSpecialScenario Case: SpecialScenario = false # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) dic_nodes_minCapacity = { 'w1': -1, 'w2': 0, 'w3': -1, 'w4': 0, 'w5': 2, 'v1_w2_w1': 0, 'v2_w2_w1': 0, 'v1_w2_w3': 0, 'v1_w3_w5': 0 } dic_nodes_maxCapacity = dic_nodes_minCapacity startNode = 'w1' endNode = 'w3' # create optimal solution entries = [] exits = [] optSol_W1_W2 = { ('w2', 'v1_w2_w1'): -1.0, ('v1_w2_w1', 'v2_w2_w1'): -1.0, ('v2_w2_w1', 'w1'): -1.0, ('w2', 'v1_w2_w3'): 1.0, ('v1_w2_w3', 'w3'): 1.0, ('w3', 'v1_w3_w5'): 2.0, ('w3', 'v1_w3_w5'): 2.0 } # test function computeSingleSpecialScenario dic_scenario_flow_W1_W3 = test_computeSingleSpecialScenario( graph, distances, entries, exits, startNode, endNode, dic_nodes_minCapacity, dic_nodes_maxCapacity, False) # check solution: since demands are fixed, the solution is unique for arc in optSol_W1_W2.keys(): assert (dic_scenario_flow_W1_W3[arc] == optSol_W1_W2[arc]) ###################################################################################################################### # unit test of function generateRobustScenarios # create input data and optimal solution (only parts because inner function computeSingleSpecialScenario already tested data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) injectionRates = { 'w1': [-2.0, 0.0, -2.0, -2.0], 'w2': [1.0, 0.0, 0.0, 0.0], 'w3': [1.0, -2.0, 2.0, -2.0], 'w4': [0.0, 0.0, 0.0, 0.0], 'w5': [0.0, 2.0, 0.0, 4.0] } injectionWithdrawal = pd.DataFrame(data=injectionRates) # optimal solution entriesTruth = ['w1', 'w3'] exitsTruth = ['w2', 'w3', 'w5'] # optimal value of each scenario dic_nodePair_optValueTruth = { ('w4', 'w3'): 0.0, ('w4', 'w2'): 2.0, ('w4', 'v1_w2_w1'): 2.0, ('w4', 'v2_w2_w1'): 2.0, ('w4', 'w1'): 2.0, ('w4', 'v1_w2_w3'): 1.0, ('w4', 'v1_w3_w5'): 4.0, ('w4', 'w5'): 8.0, ('w3', 'w4'): 0.0, ('w3', 'w2'): 2.0, ('w3', 'v1_w2_w1'): 2.0, ('w3', 'v2_w2_w1'): 2.0, ('w3', 'w1'): 2.0, ('w3', 'v1_w2_w3'): 1.0, ('w3', 'v1_w3_w5'): 4.0, ('w3', 'w5'): 8.0, ('w2', 'w4'): 4.0, ('w2', 'w3'): 4.0, ('w2', 'v1_w2_w1'): 0.0, ('w2', 'v2_w2_w1'): 0.0, ('w2', 'w1'): 0.0, ('w2', 'v1_w2_w3'): 2.0, ('w2', 'v1_w3_w5'): 8.0, ('w2', 'w5'): 12.0, ('v1_w2_w1', 'w4'): 6.0, ('v1_w2_w1', 'w3'): 6.0, ('v1_w2_w1', 'w2'): 2.0, ('v1_w2_w1', 'v2_w2_w1'): 0.0, ('v1_w2_w1', 'w1'): 0.0, ('v1_w2_w1', 'v1_w2_w3'): 4.0, ('v1_w2_w1', 'v1_w3_w5'): 10.0, ('v1_w2_w1', 'w5'): 14.0, ('v2_w2_w1', 'w4'): 8.0, ('v2_w2_w1', 'w3'): 8.0, ('v2_w2_w1', 'w2'): 4.0, ('v2_w2_w1', 'v1_w2_w1'): 2.0, ('v2_w2_w1', 'w1'): 0.0, ('v2_w2_w1', 'v1_w2_w3'): 6.0, ('v2_w2_w1', 'v1_w3_w5'): 12.0, ('v2_w2_w1', 'w5'): 16.0, ('w1', 'w4'): 10.0, ('w1', 'w3'): 10.0, ('w1', 'w2'): 6.0, ('w1', 'v1_w2_w1'): 4.0, ('w1', 'v2_w2_w1'): 2.0, ('w1', 'v1_w2_w3'): 8.0, ('w1', 'v1_w3_w5'): 14.0, ('w1', 'w5'): 18.0, ('v1_w2_w3', 'w4'): 2.0, ('v1_w2_w3', 'w3'): 2.0, ('v1_w2_w3', 'w2'): 1.0, ('v1_w2_w3', 'v1_w2_w1'): 1.0, ('v1_w2_w3', 'v2_w2_w1'): 1.0, ('v1_w2_w3', 'w1'): 1.0, ('v1_w2_w3', 'v1_w3_w5'): 6.0, ('v1_w2_w3', 'w5'): 10.0, ('v1_w3_w5', 'w4'): 0.0, ('v1_w3_w5', 'w3'): 0.0, ('v1_w3_w5', 'w2'): 2.0, ('v1_w3_w5', 'v1_w2_w1'): 2.0, ('v1_w3_w5', 'v2_w2_w1'): 2.0, ('v1_w3_w5', 'w1'): 2.0, ('v1_w3_w5', 'v1_w2_w3'): 1.0, ('v1_w3_w5', 'w5'): 4.0, ('w5', 'w4'): 0.0, ('w5', 'w3'): 0.0, ('w5', 'w2'): 2.0, ('w5', 'v1_w2_w1'): 2.0, ('w5', 'v2_w2_w1'): 2.0, ('w5', 'w1'): 2.0, ('w5', 'v1_w2_w3'): 1.0, ('w5', 'v1_w3_w5'): 0.0 } nodes = list(dic_node_minPress.keys()) nodePair = [] for startnode in nodes: for endnode in nodes: if startnode is not endnode: nodePair.append((startnode, endnode)) # test function generateRobustScenarios dic_robustScenarios, entries, exits, dic_nodePair_optValue \ = test_generateRobustScenarios(injectionWithdrawal, graph, distances, dic_node_minPress, dic_node_maxPress) assert (sorted(entriesTruth) == sorted(entries)) assert (sorted(exitsTruth) == sorted(exits)) assert (sorted(dic_robustScenarios.keys()) == sorted(nodePair)) assert (dic_nodePair_optValue == dic_nodePair_optValueTruth) ###################################################################################################################### # unit test of function computeLargeMergedDiameters # create input data and optimal solution dic_diamToMerge_costs = {0.144: 10, 1.500: 20} # optimal solution dic_mergedDiamTruth = {0.190009: 20, 1.979262: 40} dic_reversed_diamsTruth = {0.190009: 0.144, 1.979262: 1.500} dic_mergedDiam, dic_reversed_diams = robustPipelineSizing.computeLargeMergedDiameters( dic_diamToMerge_costs, 6) assert (dic_mergedDiam == dic_mergedDiamTruth) assert (dic_reversed_diams == dic_reversed_diamsTruth) ####################################################################################################################### # unit function test of function determinePressureDropCoef # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) diameters = [0.1063, 1.536] testscenarios = { ('w5', 'w1'): { ('w4', 'w3'): 0.0, ('w2', 'v1_w2_w1'): 0.0, ('v1_w2_w1', 'v2_w2_w1'): 0.0, ('v2_w2_w1', 'w1'): 0.0, ('w2', 'v1_w2_w3'): -1.0, ('v1_w2_w3', 'w3'): -1.0, ('w3', 'v1_w3_w5'): 0.0, ('v1_w3_w5', 'w5'): 0.0 }, ('w2', 'v1_w3_w5'): { ('w4', 'w3'): 0.0, ('w2', 'v1_w2_w1'): -2.0, ('v1_w2_w1', 'v2_w2_w1'): -2.0, ('v2_w2_w1', 'w1'): -2.0, ('w2', 'v1_w2_w3'): 2.0, ('v1_w2_w3', 'w3'): 2.0, ('w3', 'v1_w3_w5'): 4.0, ('v1_w3_w5', 'w5'): 4.0 } } # optimal solution dic_pressure_coefTruth = { (0.1063, ('w5', 'w1')): { ('w4', 'w3'): 0, ('w2', 'v1_w2_w1'): 0, ('v1_w2_w1', 'v2_w2_w1'): 0, ('v2_w2_w1', 'w1'): 0, ('w2', 'v1_w2_w3'): -131.38307913282281, ('v1_w2_w3', 'w3'): -131.83249054911866, ('w3', 'v1_w3_w5'): 0, ('v1_w3_w5', 'w5'): 0 }, (0.1063, ('w2', 'v1_w3_w5')): { ('w4', 'w3'): 0, ('w2', 'v1_w2_w1'): -558.2111338732643, ('v1_w2_w1', 'v2_w2_w1'): -558.5140246655361, ('v2_w2_w1', 'w1'): -559.5025149566926, ('w2', 'v1_w2_w3'): 523.2976028753353, ('v1_w2_w3', 'w3'): 525.1425774408543, ('w3', 'v1_w3_w5'): 1677.5126669798137, ('v1_w3_w5', 'w5'): 1674.151293128955 }, (1.536, ('w5', 'w1')): { ('w4', 'w3'): 0, ('w2', 'v1_w2_w1'): 0, ('v1_w2_w1', 'v2_w2_w1'): 0, ('v2_w2_w1', 'w1'): 0, ('w2', 'v1_w2_w3'): -0.0001700642888961138, ('v1_w2_w3', 'w3'): -0.00017067718965527387, ('w3', 'v1_w3_w5'): 0, ('v1_w3_w5', 'w5'): 0 }, (1.536, ('w2', 'v1_w3_w5')): { ('w4', 'w3'): 0, ('w2', 'v1_w2_w1'): -0.0006460078899527932, ('v1_w2_w1', 'v2_w2_w1'): -0.0006463741986205677, ('v2_w2_w1', 'w1'): -0.000647570434768236, ('w2', 'v1_w2_w3'): 0.0006056017622910718, ('v1_w2_w3', 'w3'): 0.0006078348401792327, ('w3', 'v1_w3_w5'): 0.0017698676222416114, ('v1_w3_w5', 'w5'): 0.0017661900309253952 } } dic_pressure_coef = robustPipelineSizing.determinePressureDropCoef( testscenarios, distances, dic_node_minPress, dic_node_maxPress, diameters) assert (dic_pressure_coef == dic_pressure_coefTruth) ###################################################################################################################### # unit test of function computeTimeStepFlows # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) injectionRates = { 'w1': [-20.0, -20.0], 'w2': [10.0, 0.0], 'w3': [10.0, -20.0], 'w4': [0.0, 0.0], 'w5': [0.0, 40.0] } injectionWithdrawal = pd.DataFrame(data=injectionRates) entries = [] exits = [] # create optimal solution dic_timeStep_flowsTruth = { 0: { ('w4', 'w3'): 0.0, ('w2', 'v1_w2_w1'): -20.0, ('v1_w2_w1', 'v2_w2_w1'): -20.0, ('v2_w2_w1', 'w1'): -20.0, ('w2', 'v1_w2_w3'): 10.0, ('v1_w2_w3', 'w3'): 10.0, ('w3', 'v1_w3_w5'): 0.0, ('v1_w3_w5', 'w5'): 0.0 }, 1: { ('w4', 'w3'): 0.0, ('w2', 'v1_w2_w1'): -20.0, ('v1_w2_w1', 'v2_w2_w1'): -20.0, ('v2_w2_w1', 'w1'): -20.0, ('w2', 'v1_w2_w3'): 20.0, ('v1_w2_w3', 'w3'): 20.0, ('w3', 'v1_w3_w5'): 40.0, ('v1_w3_w5', 'w5'): 40.0 } } dic_timeStep_flows = robustPipelineSizing.computeTimeStepFlows( injectionWithdrawal, distances, graph, entries, exits) assert (dic_timeStep_flows == dic_timeStep_flowsTruth) ###################################################################################################################### # unit test of function determineOptimalDiscretePipelineSelection case Robust = True # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) injectionRates = { 'w1': [-20.0, 0.0, -20.0, -20.0], 'w2': [10.0, 0.0, 0.0, 0.0], 'w3': [10.0, -20.0, 20.0, -20.0], 'w4': [0.0, 0.0, 0.0, 0.0], 'w5': [0.0, 20.0, 0.0, 40.0] } injectionWithdrawal = pd.DataFrame(data=injectionRates) dic_robustScenarios, entries, exits = robustPipelineSizing.generateRobustScenarios( injectionWithdrawal, graph, distances, dic_node_minPress, dic_node_maxPress) diameters = [0.1063, 1.536] # for debugging reason we consider only two special scenarios dic_robustTestScenarios = {} dic_robustTestScenarios[('w1', 'w3')] = dic_robustScenarios[('w1', 'w3')] dic_robustTestScenarios[('w5', 'w1')] = dic_robustScenarios[('w5', 'w1')] dic_pressure_coef = robustPipelineSizing.determinePressureDropCoef( dic_robustTestScenarios, distances, dic_node_minPress, dic_node_maxPress, diameters) dic_diameter_costs = {0.1063: 10, 1.536: 30} specialScenarionames = [('w1', 'w3'), ('w5', 'w1')] # optimal solution dic_arc_diamTruth = { ('w4', 'w3'): 0.1063, ('w2', 'v1_w2_w1'): 1.536, ('v1_w2_w1', 'v2_w2_w1'): 1.536, ('v2_w2_w1', 'w1'): 1.536, ('w2', 'v1_w2_w3'): 1.536, ('v1_w2_w3', 'w3'): 1.536, ('w3', 'v1_w3_w5'): 1.536, ('v1_w3_w5', 'w5'): 1.536 } dic_arc_diam, dic_scen_node_press = robustPipelineSizing.determineOptimalDiscretePipelineSelection( graph, distances, dic_pressure_coef, specialScenarionames, dic_node_minPress, dic_node_maxPress, dic_diameter_costs, robust=True, verbose=2) assert (sorted(dic_arc_diam) == sorted(dic_arc_diamTruth)) ####################################################################################################################### # unit test of function determineOptimalDiscretePipelineSelection case Robust = False # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) injectionRates = { 'w1': [-5.0, -5.0], 'w2': [3.0, 0.0], 'w3': [2.0, 0.0], 'w4': [0.0, 0.0], 'w5': [0.0, 5.0] } injectionWithdrawal = pd.DataFrame(data=injectionRates) entries = [] exits = [] diameters = [0.1063, 1.536] dic_timeStep_flows = robustPipelineSizing.computeTimeStepFlows( injectionWithdrawal, distances, graph, entries, exits) dic_pressure_coef = robustPipelineSizing.determinePressureDropCoef( dic_timeStep_flows, distances, dic_node_minPress, dic_node_maxPress, diameters) dic_diameter_costs = {0.1063: 10, 1.536: 30} specialScenarionames = list(dic_timeStep_flows.keys()) # create optimal solution dic_arc_diamTruth = { ('w4', 'w3'): 0.1063, ('w2', 'v1_w2_w1'): 1.536, ('v1_w2_w1', 'v2_w2_w1'): 1.536, ('v2_w2_w1', 'w1'): 0.1063, ('w2', 'v1_w2_w3'): 1.536, ('v1_w2_w3', 'w3'): 1.536, ('w3', 'v1_w3_w5'): 1.536, ('v1_w3_w5', 'w5'): 0.1063 } dic_arc_diam, dic_scen_node_press = robustPipelineSizing.determineOptimalDiscretePipelineSelection( graph, distances, dic_pressure_coef, specialScenarionames, dic_node_minPress, dic_node_maxPress, dic_diameter_costs, robust=False, verbose=2) assert (sorted(dic_arc_diam) == sorted(dic_arc_diamTruth)) ####################################################################################################################### # unit test of function computePressureStartnodeArc # create input data and optimal solution arc = ('w1', 'w2') pressureEndNode = 50.0 dic_arc_diam = {arc: 0.1063} distances = pd.Series(1000.0, index=[arc]) dic_scenario_flows = {arc: 5.0} pressStartnode = robustPipelineSizing.computePressureStartnodeArc( arc, pressureEndNode, dic_scenario_flows, dic_arc_diam, distances) assert (np.round(pressStartnode, 3) == 105.59) # for the reversed arc flow we have the same result because the arc flow direction is handled by computePressureAtNode dic_scenario_flows = {arc: -5.0} pressStartnode = robustPipelineSizing.computePressureStartnodeArc( arc, pressureEndNode, dic_scenario_flows, dic_arc_diam, distances) assert (np.round(pressStartnode, 3) == 105.59) dic_scenario_flows = {arc: 0.0} pressStartnode = robustPipelineSizing.computePressureStartnodeArc( arc, pressureEndNode, dic_scenario_flows, dic_arc_diam, distances) assert (np.round(pressStartnode, 3) == np.round(pressureEndNode, 3)) ####################################################################################################################### # unit test of function computePressureEndnodeArc # create input data and optimal solution arc = ('w1', 'w2') pressStartNode = 100.0 dic_arc_diam = {arc: 0.1063} distances = pd.Series(1000.0, index=[arc]) dic_scenario_flows = {arc: 5.0} pressureEndNode = robustPipelineSizing.computePressureEndnodeArc( arc, pressStartNode, dic_scenario_flows, dic_arc_diam, distances) assert (np.round(pressureEndNode, 3) == 37.29) # results should be the same for reversed arc flow since the flow direction is handled by computePressureAtNode dic_scenario_flows = {arc: -5.0} pressureEndNode = robustPipelineSizing.computePressureEndnodeArc( arc, pressStartNode, dic_scenario_flows, dic_arc_diam, distances) assert (np.round(pressureEndNode, 3) == 37.29) dic_scenario_flows = {arc: 0.0} pressureEndNode = robustPipelineSizing.computePressureEndnodeArc( arc, pressStartNode, dic_scenario_flows, dic_arc_diam, distances) assert (np.round(pressureEndNode, 3) == np.round(pressStartNode, 3)) ####################################################################################################################### # unit test of function computePressureAtNode # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) injectionRates = { 'w1': [-5.0, -5.0], 'w2': [3.0, 0.0], 'w3': [2.0, 0.0], 'w4': [0.0, 0.0], 'w5': [0.0, 5.0] } injectionWithdrawal = pd.DataFrame(data=injectionRates) entries = [] exits = [] diameters = [0.1063, 1.536] dic_timeStep_flows = robustPipelineSizing.computeTimeStepFlows( injectionWithdrawal, distances, graph, entries, exits) dic_pressure_coef = robustPipelineSizing.determinePressureDropCoef( dic_timeStep_flows, distances, dic_node_minPress, dic_node_maxPress, diameters) dic_diameter_costs = {0.1063: 10, 1.536: 30} specialScenarionames = list(dic_timeStep_flows.keys()) dic_arc_diam, dic_scen_node_press = robustPipelineSizing.determineOptimalDiscretePipelineSelection( graph, distances, dic_pressure_coef, specialScenarionames, dic_node_minPress, dic_node_maxPress, dic_diameter_costs, robust=False) validation = True node = 'w1' upperPressNode = 'w1' tmp_violation = 0.0 dic_node_Pressure = {} for nodeindex in graph.nodes: dic_node_Pressure[nodeindex] = None dic_timeStep_flow = dic_timeStep_flows[0] # optimal solution dic_nodePressTruth = { 'w4': 80.6313893875461, 'w3': 80.6313893875461, 'w2': 80.6313969344965, 'v1_w2_w1': 80.63141923180355, 'v2_w2_w1': 80.63144152910475, 'w1': 100, 'v1_w2_w3': 80.63139316102138, 'v1_w3_w5': 80.6313893875461, 'w5': 80.6313893875461 } validation, tmp_violation = robustPipelineSizing.computePressureAtNode( validation, node, upperPressNode, graph, dic_arc_diam, distances, dic_timeStep_flow, dic_node_minPress, dic_node_maxPress, tmp_violation, dic_node_Pressure) assert (not validation) assert (tmp_violation == 0.6313893875460934) assert (dic_node_Pressure == dic_nodePressTruth) validation = True node = 'w4' upperPressNode = 'w4' tmp_violation = 0.0 dic_node_Pressure = {} for nodeindex in graph.nodes: dic_node_Pressure[nodeindex] = None dic_timeStep_flow = dic_timeStep_flows[0] # optimal solution dic_nodePressTruth = { 'w4': 80, 'w3': 80.0, 'w2': 80.00000760352876, 'v1_w2_w1': 80.00003006810435, 'v2_w2_w1': 80.00005253267393, 'w1': 99.4853419184688, 'v1_w2_w3': 80.00000380176446, 'v1_w3_w5': 80.0, 'w5': 80.0 } validation, tmp_violation = robustPipelineSizing.computePressureAtNode( validation, node, upperPressNode, graph, dic_arc_diam, distances, dic_timeStep_flow, dic_node_minPress, dic_node_maxPress, tmp_violation, dic_node_Pressure) assert (validation) assert (tmp_violation == 0.0) assert (dic_node_Pressure == dic_nodePressTruth) ##################################################################################################################### # unit test of function postprocessing # create input data and optimal solution data = [1200.0, 1200.0, 1500.0, 750.0, 1500.0, 500.0, 500.0, 600.0, 2000.0] keys = [('w1', 'w2'), ('w2', 'w1'), ('w1', 'w5'), ('w2', 'w3'), ('w2', 'w4'), ('w3', 'w4'), ('w4', 'w3'), ('w3', 'w5'), ('w4', 'w5')] distances = pd.Series(data, index=keys) graph, distances = robustPipelineSizing.createNetwork(distances) stTree, distances = robustPipelineSizing.createSteinerTree( graph, distances, list(graph.nodes)) dic_node_maxPress = {'w1': 100, 'w2': 90, 'w3': 100, 'w4': 80, 'w5': 95} dic_node_minPress = {'w1': 50, 'w2': 45, 'w3': 60, 'w4': 60, 'w5': 50} maxPipeLength = 500 graph, distances, dic_node_minPress, dic_node_maxPress = test_networkRefinement( distances, maxPipeLength, dic_node_minPress, dic_node_maxPress) dic_arc_diam = { ('w4', 'w3'): 0.1063, ('w2', 'v1_w2_w1'): 1.536, ('v1_w2_w1', 'v2_w2_w1'): 1.536, ('v2_w2_w1', 'w1'): 1.536, ('w2', 'v1_w2_w3'): 1.536, ('v1_w2_w3', 'w3'): 1.536, ('w3', 'v1_w3_w5'): 1.536, ('v1_w3_w5', 'w5'): 1.536 } testScen = { ('w2', 'v1_w3_w5'): { ('w4', 'w3'): 0.0, ('w2', 'v1_w2_w1'): -200.0, ('v1_w2_w1', 'v2_w2_w1'): -200.0, ('v2_w2_w1', 'w1'): -200.0, ('w2', 'v1_w2_w3'): 200.0, ('v1_w2_w3', 'w3'): 200.0, ('w3', 'v1_w3_w5'): 400.0, ('v1_w3_w5', 'w5'): 400.0 } } # optimal solution dic_scenPressTruth = { ('w2', 'v1_w3_w5'): { 'w4': 80, 'w3': 80.0, 'w2': 80.05723929028916, 'v1_w2_w1': 80.08775096325076, 'v2_w2_w1': 80.11825156968065, 'w1': 80.14874112202088, 'v1_w2_w3': 80.02862451899747, 'v1_w3_w5': 79.9087044007704, 'w5': 79.81730934184435 } } dic_scen_PressLevel, dic_scen_MaxViolPress = robustPipelineSizing.postprocessing( graph, distances, dic_arc_diam, testScen, dic_node_minPress, dic_node_maxPress) assert (dic_scenPressTruth == dic_scen_PressLevel) assert (dic_scen_MaxViolPress[('w2', 'v1_w3_w5')] == 0.0) # second testcase in which a violation exists dic_arc_diam = { ('w4', 'w3'): 0.1063, ('w2', 'v1_w2_w1'): 1.536, ('v1_w2_w1', 'v2_w2_w1'): 1.536, ('v2_w2_w1', 'w1'): 0.3063, ('w2', 'v1_w2_w3'): 1.536, ('v1_w2_w3', 'w3'): 1.536, ('w3', 'v1_w3_w5'): 1.536, ('v1_w3_w5', 'w5'): 1.536 } # optimal solution dic_scenPressTruth = { ('w2', 'v1_w3_w5'): { 'w4': 80, 'w3': 80.0, 'w2': 80.05723929028916, 'v1_w2_w1': 80.08775096325076, 'v2_w2_w1': 80.11825156968065, 'w1': 168.2934447139534, 'v1_w2_w3': 80.02862451899747, 'v1_w3_w5': 79.9087044007704, 'w5': 79.81730934184435 } } dic_scen_MaxViol = {('w2', 'v1_w3_w5'): 68.29344471395339} dic_scen_PressLevel, dic_scen_MaxViolPress = robustPipelineSizing.postprocessing( graph, distances, dic_arc_diam, testScen, dic_node_minPress, dic_node_maxPress) assert (dic_scen_PressLevel == dic_scenPressTruth) assert (dic_scen_MaxViolPress == dic_scen_MaxViol) print("All Unit tests worked as expected")