circleKill.py 3.78 KB
Newer Older
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

############################################################################
#
# MODULE:       circleKill.py
# AUTHOR(S):    Julien Veyssier
# 
#
# COPYRIGHT:    (C) 2020 UR RIVERLY - INRAE
#
#               This program is free software under the GNU General Public
#               License (>=v2). Read the file LICENSE that comes with 
#                HRU-DELIN for details.
#
#############################################################################



20
import sys
21
22
23
try:
    import dbf
    DBF=True
24
except Exception as e:
25
    DBF=False
Julien Veyssier's avatar
Julien Veyssier committed
26
    print('!!! Warning, dbf python3 module not found, no topology dbf file will be generated')
27
28
    print('Install dbf module with: sudo apt install python3-dbf')
    print('or if you don\'t have superuser access: pip3 install dbf\n')
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

separator=','

class Hru():
    id = None
    toSubbasin = None
    toHruId = None

    def __init__(self, id, toSubbasin, toHruId):
        self.id = id
        self.toSubbasin = toSubbasin
        self.toHruId = toHruId

def circleKill(inputPath, outputPath):
    hruList = importFile(inputPath)
    solveCircles(hruList)
    writeResult(hruList, outputPath)

def importFile(path):
    hruList = []
    with open(path, 'r') as f:
        line = f.readline()
        while line.startswith('#'):
            line = f.readline()

        while line and not line.startswith('#'):
            lineSpl = line.split(separator)
            hruId = int(lineSpl[0].strip())
            toSubbasin = int(lineSpl[1].strip())
            toHruId = int(lineSpl[2].strip())
            hruList.append(Hru(hruId, toSubbasin, toHruId))
            line = f.readline()

    return hruList

def writeResult(hruList, path):
65
66
67
68
69
    parOutput = '%s.par' % path
    dbfOutput = '%s.dbf' % path

    # write .par file
    with open(parOutput, 'w') as fo:
70
71
72
73
74
        fo.write('# Adjusted flow relations\n')
        fo.write('# hruId "emergency exit" toHru\n')
        for hru in hruList:
            fo.write('%i,%i,%i\n' % (hru.id, hru.toSubbasin, hru.toHruId))
        fo.write('# End of records')
75
76
77
78
79
80
81

    # write dbf file if possible
    if DBF:
        table = dbf.Table(dbfOutput, 'hruID N(8,0); notausgang N(8,0); to_hruID N(8,0)')
        table.open(mode=dbf.READ_WRITE)
        for hru in hruList:
            table.append((hru.id, hru.toSubbasin, hru.toHruId))
82
83
84
85
86
87
88
89
90
91
92
        table.close()

def solveCircles(hruList):
    # indexed by hru id => HRU
    hruMap = {}
    # indexed by hru id => int
    statusMap = {}

    for hru in hruList:
        hruMap[hru.id] = hru

Julien Veyssier's avatar
Julien Veyssier committed
93
    for currentHru in hruList:
94
        #print('Checking HRU %s for circles' % currentHru.id)
95
96
97
98
99
100
101
102
103
        for hru2 in hruList:
            statusMap[hru2.id] = 0

        targetHru = currentHru
        continueSearch = True

        while continueSearch:
            if statusMap[targetHru.id] == 2:
                if currentHru.id == targetHru.id:
Julien Veyssier's avatar
Julien Veyssier committed
104
                    # Circle detected. The drainage is diverted to the "emergency exit"
105
106
107
108
109
110
111
112
113
114
                    toId = targetHru.toSubbasin
                    targetHru.toHruId = toId
                    continueSearch = False
                else:
                    # However, not starting from the HRU studied, but in the further course of the flow cascade
                    continueSearch = False
            elif targetHru.toHruId < 0:
                # No circle. Dewatering into a watercourse segment
                continueSearch = False
            else:
Julien Veyssier's avatar
Julien Veyssier committed
115
                # Continue searching in the flow cascade
116
                statusMap[targetHru.id] = 2
117
118
119
120
121
122
123
124
                targetHru = hruMap[targetHru.toHruId]

if __name__ == '__main__':
    if len(sys.argv) > 2:
        inPath = sys.argv[1]
        outPath = sys.argv[2]
        circleKill(inPath, outPath)
    else:
125
        sys.exit('Please provide two arguments: INPUT_PATH OUTPUT_PATH_PREFIX')