2
2
#include <grass/gis.h>
3
#include <grass/raster.h>
3
4
#include <grass/glocale.h>
6
double get_dist(double *dist_to_nbr, double *contour)
8
int ct_dir, r_nbr, c_nbr;
9
double dx, dy, ns_res, ew_res;
11
if (G_projection() == PROJECTION_LL) {
12
double ew_dist1, ew_dist2, ew_dist3;
13
double ns_dist1, ns_dist2, ns_dist3;
15
G_begin_distance_calculations();
17
/* EW Dist at North edge */
18
ew_dist1 = G_distance(window.east, window.north,
19
window.west, window.north);
20
/* EW Dist at Center */
21
ew_dist2 = G_distance(window.east, (window.north + window.south) / 2.,
22
window.west, (window.north + window.south) / 2.);
23
/* EW Dist at South Edge */
24
ew_dist3 = G_distance(window.east, window.south,
25
window.west, window.south);
26
/* NS Dist at East edge */
27
ns_dist1 = G_distance(window.east, window.north,
28
window.east, window.south);
29
/* NS Dist at Center */
30
ns_dist2 = G_distance((window.west + window.east) / 2., window.north,
31
(window.west + window.east) / 2., window.south);
32
/* NS Dist at West edge */
33
ns_dist3 = G_distance(window.west, window.north,
34
window.west, window.south);
36
ew_res = (ew_dist1 + ew_dist2 + ew_dist3) / (3 * window.cols);
37
ns_res = (ns_dist1 + ns_dist2 + ns_dist3) / (3 * window.rows);
40
ns_res = window.ns_res;
41
ew_res = window.ew_res;
44
for (ct_dir = 0; ct_dir < sides; ct_dir++) {
45
/* get r, c (r_nbr, c_nbr) for neighbours */
46
r_nbr = nextdr[ct_dir];
47
c_nbr = nextdc[ct_dir];
48
/* account for rare cases when ns_res != ew_res */
49
dy = ABS(r_nbr) * ns_res;
50
dx = ABS(c_nbr) * ew_res;
52
dist_to_nbr[ct_dir] = (dx + dy) * ele_scale;
54
dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy) * ele_scale;
57
* ns contour: ew_res / 2
58
* ew contour: ns_res / 2
59
* diag contour: sqrt(ns_res * nsres / 4 + ew_res * ew_res / 4) / 2
60
* = sqrt(ns_res * nsres + ew_res * ew_res) / 4
61
* if ns_res == ew_res:
62
* sqrt(2 * (res * res) / 4 = res * 0.354
64
* contour lengths "have been subjectively chosen",
65
* no justification why the diagonal contour is shorter
66
* BUT: if the diag contour is a bit shorter than the cardinal contour,
67
* this is further enhancing the correction for diagonal flow bias
68
* diagonal slope is already corrected for longer distance
69
* smaller slope and shorter contour length have the same effect:
73
/* contours are sides of an octagon, irregular if ns_res != ew_res
74
* ideally: arc lengths of an ellipse */
75
contour[0] = contour[1] = tan(atan(ew_res / ns_res) / 2.) * ns_res;
76
contour[2] = contour[3] = tan(atan(ns_res / ew_res) / 2.) * ew_res;
77
G_debug(1, "ns contour: %.4f", contour[0]);
78
G_debug(1, "ew contour: %.4f", contour[2]);
79
contour[4] = (ew_res - contour[0]);
80
contour[5] = (ns_res - contour[2]);
81
contour[7] = sqrt(contour[4] * contour[4] + contour[5] * contour[5]) / 2.;
82
G_debug(1, "diag contour: %.4f", contour[7]);
83
contour[4] = contour[5] = contour[6] = contour[7];
86
/* contours are sides of a rectangle */
87
contour[0] = contour[1] = ew_res;
88
contour[2] = contour[3] = ns_res;
90
return ew_res * ns_res;
93
double get_slope_tci(CELL ele, CELL down_ele, double dist)
98
return (double)(ele - down_ele) / dist;
9
CELL is_swale, value, valued, aspect;
10
int killer, threshold, count;
11
SHORT asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
12
SHORT asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
13
int this_index, down_index;
104
int r_nbr, c_nbr, ct_dir, np_side, edge;
105
CELL is_swale, aspect, ele_nbr;
107
int killer, threshold;
108
int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
109
int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
110
int this_index, down_index, nbr_index;
111
double *dist_to_nbr, *contour;
112
double tci_div, cell_size;
15
114
G_message(_("SECTION 3: Accumulating Surface Flow with SFD."));
116
/* distances to neighbours, contour lengths */
117
dist_to_nbr = (double *)G_malloc(sides * sizeof(double));
118
contour = (double *)G_malloc(sides * sizeof(double));
120
cell_size = get_dist(dist_to_nbr, contour);
18
122
if (bas_thres <= 0)
28
132
dr = r + asp_r[ABS(aspect)];
29
133
dc = c + asp_c[ABS(aspect)];
135
/* skip user-defined depressions */
33
138
if (dr >= 0 && dr < nrows && dc >= 0 && dc < ncols) { /* if ((dr = astar_pts[killer].downr) > -1) { */
34
139
down_index = SEG_INDEX(wat_seg, dr, dc);
35
140
value = wat[this_index];
36
if ((int)(ABS(value) + 0.5) >= threshold)
141
if (fabs(value) >= threshold)
37
142
FLAG_SET(swale, r, c);
38
143
valued = wat[down_index];
147
for (ct_dir = 0; ct_dir < sides; ct_dir++) {
148
/* get r, c (r_nbr, c_nbr) for neighbours */
149
r_nbr = r + nextdr[ct_dir];
150
c_nbr = c + nextdc[ct_dir];
152
if (dr == r_nbr && dc == c_nbr)
155
/* check that neighbour is within region */
156
if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
159
nbr_index = SEG_INDEX(wat_seg, r_nbr, c_nbr);
160
ele_nbr = alt[nbr_index];
161
if (Rast_is_c_null_value(&ele_nbr))
169
/* do not distribute flow along edges, this causes artifacts */
171
is_swale = FLAG_GET(swale, r, c);
172
if (is_swale && aspect > 0) {
173
aspect = -1 * drain[r - r_nbr + 1][c - c_nbr + 1];
174
asp[this_index] = aspect;
92
233
* before depressions/obstacles and gracefull flow divergence after
93
234
* depressions/obstacles
236
* Topographic Convergence Index (TCI)
237
* tendency of water to accumulate at a given point considering
238
* the gravitational forces to move the water accumulated at that
239
* point further downstream
241
* after Quinn et al. (1991), modified and adapted for the modified
242
* Holmgren MFD algorithm
243
* TCI: specific catchment area divided by tangens of slope
244
* specific catchment area: total catchment area divided by contour line
245
* TCI for D8: A / (L * tanb)
246
* TCI for MFD: A / (SUM(L_i) * (SUM(tanb_i * weight_i) / SUM(weight_i))
248
* A: total catchment area
249
* L_i: contour length towards i_th cell
250
* tanb_i: slope = tan(b) towards i_th cell
251
* weight_i: weight for flow distribution towards i_th cell
95
252
* ************************************/
97
254
int do_cum_mfd(void)
102
int killer, threshold, count;
258
DCELL value, valued, tci_div, sum_contour, cell_size;
259
int killer, threshold;
105
262
int mfd_cells, stream_cells, swale_cells, astar_not_set, is_null;
106
double *dist_to_nbr, *weight, sum_weight, max_weight;
263
double *dist_to_nbr, *contour, *weight, sum_weight, max_weight;
107
264
int r_nbr, c_nbr, r_max, c_max, ct_dir, np_side;
109
265
CELL ele, ele_nbr, aspect, is_worked;
110
double prop, max_acc;
266
double prop, max_val;
111
267
int workedon, edge, flat;
112
SHORT asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
113
SHORT asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
268
int asp_r[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 };
269
int asp_c[9] = { 0, 1, 0, -1, -1, -1, 0, 1, 1 };
114
270
int this_index, down_index, nbr_index;
116
G_message(_("SECTION 3: Accumulating Surface Flow with MFD."));
272
G_message(_("SECTION 3a: Accumulating Surface Flow with MFD."));
117
273
G_debug(1, "MFD convergence factor set to %d.", c_fac);
119
/* distances to neighbours */
275
/* distances to neighbours, weights, contour lengths */
120
276
dist_to_nbr = (double *)G_malloc(sides * sizeof(double));
121
277
weight = (double *)G_malloc(sides * sizeof(double));
123
for (ct_dir = 0; ct_dir < sides; ct_dir++) {
124
/* get r, c (r_nbr, c_nbr) for neighbours */
125
r_nbr = nextdr[ct_dir];
126
c_nbr = nextdc[ct_dir];
127
/* account for rare cases when ns_res != ew_res */
128
dy = ABS(r_nbr) * window.ns_res;
129
dx = ABS(c_nbr) * window.ew_res;
131
dist_to_nbr[ct_dir] = dx + dy;
133
dist_to_nbr[ct_dir] = sqrt(dx * dx + dy * dy);
278
contour = (double *)G_malloc(sides * sizeof(double));
280
cell_size = get_dist(dist_to_nbr, contour);
136
282
flag_clear_all(worked);
140
285
if (bas_thres <= 0)
156
302
if (dr >= 0 && dr < nrows && dc >= 0 && dc < ncols) { /* if ((dr = astar_pts[killer].downr) > -1) { */
157
303
value = wat[this_index];
158
304
down_index = SEG_INDEX(wat_seg, dr, dc);
159
valued = wat[down_index];
164
306
/* get weights */
171
311
astar_not_set = 1;
172
312
ele = alt[this_index];
176
315
/* this loop is needed to get the sum of weights */
177
316
for (ct_dir = 0; ct_dir < sides; ct_dir++) {
178
317
/* get r, c (r_nbr, c_nbr) for neighbours */
179
318
r_nbr = r + nextdr[ct_dir];
180
319
c_nbr = c + nextdc[ct_dir];
181
320
weight[ct_dir] = -1;
322
if (dr == r_nbr && dc == c_nbr)
182
325
/* check that neighbour is within region */
183
326
if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
186
329
nbr_index = SEG_INDEX(wat_seg, r_nbr, c_nbr);
188
/* check for swale or stream cells */
189
is_swale = FLAG_GET(swale, r_nbr, c_nbr);
192
331
valued = wat[nbr_index];
193
332
ele_nbr = alt[nbr_index];
194
if ((ABS(valued) + 0.5) >= threshold &&
195
ct_dir != np_side && ele_nbr > ele)
198
334
is_worked = FLAG_GET(worked, r_nbr, c_nbr);
199
335
if (is_worked == 0) {
200
is_null = G_is_c_null_value(&ele_nbr);
336
is_null = Rast_is_c_null_value(&ele_nbr);
204
338
if (!is_null && ele_nbr <= ele) {
205
339
if (ele_nbr < ele) {
327
456
valued = value - valued;
329
458
wat[down_index] = valued;
461
sum_contour = contour[np_side];
462
tci_div = get_slope_tci(ele, alt[down_index],
463
dist_to_nbr[np_side]);
466
/* topographic wetness index ln(a / tan(beta)) */
468
tci[this_index] = log((fabs(wat[this_index]) * cell_size) /
469
(sum_contour * tci_div));
474
G_warning(_n("MFD: A * path already processed when distributing flow: %d of %d cell",
475
"MFD: A * path already processed when distributing flow: %d of %d cells",
477
workedon, do_points);
480
G_message(_("SECTION 3b: Adjusting drainage directions."));
482
for (killer = 1; killer <= do_points; killer++) {
483
G_percent(killer, do_points, 1);
484
this_index = astar_pts[killer];
485
seg_index_rc(alt_seg, this_index, &r, &c);
486
FLAG_UNSET(worked, r, c);
487
aspect = asp[this_index];
489
dr = r + asp_r[ABS(aspect)];
490
dc = c + asp_c[ABS(aspect)];
494
if (dr >= 0 && dr < nrows && dc >= 0 && dc < ncols) { /* if ((dr = astar_pts[killer].downr) > -1) { */
495
value = wat[this_index];
496
down_index = SEG_INDEX(wat_seg, dr, dc);
501
/* get max flow accumulation */
505
ele = alt[this_index];
510
for (ct_dir = 0; ct_dir < sides; ct_dir++) {
511
/* get r, c (r_nbr, c_nbr) for neighbours */
512
r_nbr = r + nextdr[ct_dir];
513
c_nbr = c + nextdc[ct_dir];
515
/* check that neighbour is within region */
516
if (r_nbr >= 0 && r_nbr < nrows && c_nbr >= 0 &&
519
nbr_index = SEG_INDEX(wat_seg, r_nbr, c_nbr);
521
/* check for swale or stream cells */
522
is_swale = FLAG_GET(swale, r_nbr, c_nbr);
525
valued = wat[nbr_index];
526
ele_nbr = alt[nbr_index];
527
edge = Rast_is_c_null_value(&ele_nbr);
528
if ((ABS(valued) + 0.5) >= threshold &&
532
is_worked = !(FLAG_GET(worked, r_nbr, c_nbr));
533
if (is_worked == 0) {
536
is_null = Rast_is_c_null_value(&ele_nbr);
538
if (!is_null && ABS(valued) > max_val) {
539
max_val = ABS(valued);
550
/* do not distribute flow along edges, this causes artifacts */
552
is_swale = FLAG_GET(swale, r, c);
553
if (is_swale && aspect > 0) {
554
aspect = -1 * drain[r - r_nbr + 1][c - c_nbr + 1];
555
asp[this_index] = aspect;
333
561
if (dr != r_max || dc != c_max) {
334
562
aspect = drain[r - r_max + 1][c - c_max + 1];