filldepr.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /****************************************************************************
  2. *
  3. * MODULE: r.terraflow
  4. *
  5. * COPYRIGHT (C) 2007 Laura Toma
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. *****************************************************************************/
  18. #include <assert.h>
  19. #include <grass/iostream/ami.h>
  20. #include "filldepr.h"
  21. #include "unionFind.h"
  22. #include "common.h"
  23. #define FLOOD_DEBUG if(0)
  24. /************************************************************/
  25. /* INPUT: stream containing the edgelist of watershed adjacency graph
  26. E={(u,v,h) | 0 <= u,v <= W-1}; W is the maximum number of watersheds
  27. (also counting the outside watershed 0)
  28. elevation_type*
  29. h is the smallest height on the boundary between watershed u and
  30. watershed v;
  31. the outside face is assumed to be watershed number 0
  32. E contains the edges between the watersheds on the boundary and the
  33. outside watershed 0;
  34. E is sorted increasingly by (h,u,v)
  35. OUTPUT: allocate and returns an array raise[1..W-1], raise[i] is the
  36. height to which the watershed i must be raised in order to have a
  37. valid flow path to the outside watershed (raise[0] is 0) */
  38. /************************************************************/
  39. elevation_type*
  40. fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
  41. cclabel_type maxWatersheds) {
  42. if (stats) {
  43. stats->comment("----------", opt->verbose);
  44. stats->comment("flooding depressions");
  45. }
  46. /* find available memory */
  47. size_t mem_avail = getAvailableMemory();
  48. MM_manager.print();
  49. /* find how much memory filling depression uses */
  50. size_t mem_usage = inmemory_fill_depression_mmusage(maxWatersheds);
  51. /* decide whether to run it in memory or not */
  52. if (mem_avail > mem_usage) {
  53. return inmemory_fill_depression(boundaryStr, maxWatersheds);
  54. } else {
  55. return ext_fill_depression(boundaryStr, maxWatersheds);
  56. }
  57. }
  58. /************************************************************/
  59. elevation_type*
  60. ext_fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
  61. cclabel_type maxWatersheds) {
  62. fprintf(stderr, "fill_depressions: does not fit in memory\n");
  63. G_fatal_error("not implemented yet");
  64. }
  65. /************************************************************/
  66. /* inside the function memory allocation is done with malloc/calloc
  67. and not with new; memory check should be done prior to this function
  68. to decide whether there's enough available memory to run it*/
  69. /************************************************************/
  70. elevation_type*
  71. inmemory_fill_depression(AMI_STREAM<boundaryType> *boundaryStr,
  72. cclabel_type maxWatersheds) {
  73. assert(boundaryStr && maxWatersheds >= 0);
  74. /*__________________________________________________________*/
  75. /* initialize */
  76. /*__________________________________________________________*/
  77. /* allocate the raised-elevation array */
  78. elevation_type* raise = new elevation_type [maxWatersheds];
  79. assert(raise);
  80. /*allocate and initialize done; done[i] = true iff watershed i has
  81. found a flow path to the outside; initially only outside watershed
  82. is done */
  83. int* done = (int*)calloc(maxWatersheds, sizeof(int));
  84. assert(done);
  85. done[LABEL_BOUNDARY] = 1;
  86. /*allocate and initialize an union find structure; insert all
  87. watersheds except for the outside watershed; the outside watershed
  88. is not in the unionfind structure; */
  89. unionFind<cclabel_type> unionf;
  90. FLOOD_DEBUG printf("nb watersheds %d, bstream length %ld\n",
  91. (int)maxWatersheds, (long)boundaryStr->stream_len());
  92. for (cclabel_type i=1; i< maxWatersheds; i++) {
  93. FLOOD_DEBUG printf("makeset %d\n",i);
  94. unionf.makeSet(i);
  95. }
  96. /*__________________________________________________________*/
  97. /*SCAN THE EDGES; invariant---watersheds adjacent to a 'done' watershed
  98. become done */
  99. /*__________________________________________________________*/
  100. AMI_err ae;
  101. boundaryType* nextedge;
  102. elevation_type h;
  103. cclabel_type u, v, ur, vr;
  104. off_t nitems = boundaryStr->stream_len();
  105. boundaryStr->seek(0);
  106. for (size_t i=0; i< nitems; i++) {
  107. /*read next edge*/
  108. ae = boundaryStr->read_item(&nextedge);
  109. assert(ae == AMI_ERROR_NO_ERROR);
  110. u = nextedge->getLabel1();
  111. v = nextedge->getLabel2();
  112. h = nextedge->getElevation();
  113. FLOOD_DEBUG {
  114. printf("\nreading edge ((%d,%d),h=%d)\n",(int)u,(int)v,(int)h);
  115. }
  116. /*find representatives; LABEL_BOUNDARY means the outside watershed*/
  117. (u==LABEL_BOUNDARY)? ur = LABEL_BOUNDARY: ur = unionf.findSet(u);
  118. (v==LABEL_BOUNDARY)? vr = LABEL_BOUNDARY: vr = unionf.findSet(v);
  119. FLOOD_DEBUG printf("%d is %d, %d is %d\n", u, ur, v, vr);
  120. /*watersheds are done; just ignore it*/
  121. if ((ur == vr) || (done[ur] && done[vr])) {
  122. continue;
  123. }
  124. /*union and raise colliding watersheds*/
  125. /* if one of the watersheds is done, then raise the other one,
  126. mark it as done too but do not union them; this handles also the
  127. case of boundary watersheds; */
  128. if (done[ur] || done[vr]) {
  129. if (done[ur]) {
  130. FLOOD_DEBUG printf("%d is done, %d raised to %f and done\n",
  131. ur, vr, (double)h);
  132. done[vr] = 1;
  133. raise[vr] = h;
  134. } else {
  135. assert(done[vr]);
  136. FLOOD_DEBUG printf("%d is done, %d raised to %f and done\n",
  137. vr, ur, (double)h);
  138. done[ur] = 1;
  139. raise[ur] = h;
  140. }
  141. continue;
  142. }
  143. /* if none of the watersheds is done: union and raise them */
  144. assert(!done[ur] && !done[vr] && ur>0 && vr>0);
  145. FLOOD_DEBUG printf("union %d and %d, raised to %f\n", ur, vr, (double)h);
  146. raise[ur] = raise[vr] = h;
  147. unionf.makeUnion(ur,vr);
  148. }
  149. #ifndef NDEBUG
  150. for (cclabel_type i=1; i< maxWatersheds; i++) {
  151. /* assert(done[unionf.findSet(i)]); sometimes this fails! */
  152. if (!done[unionf.findSet(i)]) {
  153. fprintf(stderr, "warning: watershed %d (R=%d) not done\n",
  154. i, unionf.findSet(i));
  155. }
  156. }
  157. #endif
  158. /* for each watershed find its raised elevation */
  159. for (cclabel_type i=1; i< maxWatersheds; i++) {
  160. raise[i] = raise[unionf.findSet(i)];
  161. }
  162. raise[LABEL_BOUNDARY] = 0;
  163. /*__________________________________________________________*/
  164. /*cleanup*/
  165. /*__________________________________________________________*/
  166. free(done);
  167. return raise;
  168. }
  169. /************************************************************/
  170. /* returns the amount of mmemory allocated by
  171. inmemory_fill_depression() */
  172. size_t
  173. inmemory_fill_depression_mmusage(cclabel_type maxWatersheds) {
  174. size_t mmusage = 0;
  175. /*account for done array*/
  176. mmusage += sizeof(int)*maxWatersheds;
  177. /* account for raise array */
  178. mmusage += sizeof(elevation_type)*maxWatersheds;
  179. /*account for unionFind structure*/
  180. unionFind<cclabel_type> foo;
  181. mmusage += foo.mmusage(maxWatersheds);
  182. return mmusage;
  183. }
  184. /************************************************************/
  185. /* produce a new stream where each elevation e inside watershed i is
  186. replaced with max(raise[i], e) */
  187. /************************************************************/
  188. void
  189. commit_fill(AMI_STREAM<labelElevType>* labeledGrid,
  190. elevation_type* raise, cclabel_type maxWatersheds,
  191. AMI_STREAM<elevation_type>* filledGrid) {
  192. labelElevType* pt;
  193. elevation_type h;
  194. labeledGrid->seek(0);
  195. while (labeledGrid->read_item(&pt) == AMI_ERROR_NO_ERROR) {
  196. h = pt->getElevation();
  197. if(is_nodata(h) || pt->getLabel() == LABEL_UNDEF) {
  198. /*h = nodataType::ELEVATION_NODATA; ..unhack... XXX*/
  199. } else {
  200. assert(pt->getLabel() < maxWatersheds);
  201. h = (pt->getElevation() < raise[pt->getLabel()])?
  202. raise[pt->getLabel()]: pt->getElevation();
  203. }
  204. filledGrid->write_item(h);
  205. }
  206. /* cout << "filled " << filledGrid->stream_len() << " points\n"; */
  207. }