topmodel.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #include <math.h>
  2. #include <grass/raster.h>
  3. #include <grass/spawn.h>
  4. #include <grass/glocale.h>
  5. #include "global.h"
  6. #define ZERO 0.0000001
  7. void create_topidxstats(char *topidx, int ntopidxclasses, char *outtopidxstats)
  8. {
  9. char input[GPATH_MAX], nsteps[32];
  10. const char *args[5];
  11. struct Popen child;
  12. FILE *fp;
  13. double *atb, *Aatb_r, delta, prev_atb2;
  14. int i;
  15. int total_ncells;
  16. sprintf(input, "input=%s", topidx);
  17. sprintf(nsteps, "nsteps=%d", ntopidxclasses - 1);
  18. G_message("Creating topographic index statistics file...");
  19. G_verbose_message("r.stats -nc %s %s ...", input, nsteps);
  20. args[0] = "r.stats";
  21. args[1] = "-nc";
  22. args[2] = input;
  23. args[3] = nsteps;
  24. args[4] = NULL;
  25. if ((fp = G_popen_read(&child, "r.stats", args)) == NULL)
  26. G_fatal_error(_("Unable to run %s"), "r.stats");
  27. atb = (double *)G_malloc(ntopidxclasses * sizeof(double));
  28. Aatb_r = (double *)G_malloc(ntopidxclasses * sizeof(double));
  29. total_ncells = 0;
  30. delta = -1.0;
  31. prev_atb2 = 0.0;
  32. for (i = 0; i < ntopidxclasses - 1 && !feof(fp);) {
  33. double atb1, atb2;
  34. int ncells;
  35. get_line(fp, buf);
  36. if (sscanf(buf, "%lf-%lf %d", &atb1, &atb2, &ncells) == 3) {
  37. if (delta < 0)
  38. delta = atb2 - atb1;
  39. else if (atb1 > prev_atb2 + 0.5 * delta) {
  40. /* r.stats doesn't report non-existing ranges at all. Use 0.5 *
  41. * delta to avoid comparing two almost same double numbers. */
  42. while (prev_atb2 < atb1 - 0.5 * delta) {
  43. atb[i] = prev_atb2;
  44. Aatb_r[i++] = 0.0;
  45. prev_atb2 += delta;
  46. }
  47. }
  48. atb[i] = atb1;
  49. Aatb_r[i] = (double)ncells;
  50. total_ncells += ncells;
  51. prev_atb2 = atb2;
  52. if (++i == ntopidxclasses - 1) {
  53. atb[i] = atb2;
  54. Aatb_r[i] = 0.0;
  55. }
  56. }
  57. }
  58. G_popen_close(&child);
  59. if (i < ntopidxclasses - 1)
  60. G_fatal_error(_("Invalid %s output"), "r.stats");
  61. if ((fp = fopen(outtopidxstats, "w")) == NULL)
  62. G_fatal_error(_("Unable to create output file <%s>"), outtopidxstats);
  63. for (i = ntopidxclasses - 1; i >= 0; i--)
  64. fprintf(fp, "%10.3e %10.3e\n", atb[i], Aatb_r[i] / total_ncells);
  65. fclose(fp);
  66. }
  67. /* Calculate the areal average of topographic index */
  68. double calculate_lambda(void)
  69. {
  70. int i;
  71. double lambda;
  72. lambda = 0.0;
  73. for (i = 1; i < misc.ntopidxclasses; i++)
  74. lambda += topidxstats.Aatb_r[i] *
  75. (topidxstats.atb[i] + topidxstats.atb[i - 1]) / 2.0;
  76. return lambda;
  77. }
  78. /* Initialize the flows */
  79. void initialize(void)
  80. {
  81. int i, j;
  82. double A1, A2;
  83. /* average topographic index */
  84. misc.lambda = calculate_lambda();
  85. /* ln of the average transmissivity at the soil surface */
  86. misc.lnTe = params.lnTe + log(input.dt);
  87. /* main channel routing velocity */
  88. misc.vch = params.vch * input.dt;
  89. /* internal subcatchment routing velocity */
  90. misc.vr = params.vr * input.dt;
  91. /* initial subsurface flow per unit area */
  92. misc.qs0 = params.qs0 * input.dt;
  93. /* saturated subsurface flow per unit area */
  94. misc.qss = exp(misc.lnTe - misc.lambda);
  95. misc.tch = (double *)G_malloc(params.nch * sizeof(double));
  96. /* routing time in the main channel */
  97. misc.tch[0] = params.d[0] / misc.vch;
  98. for (i = 1; i < params.nch; i++)
  99. /* routing time in each internal subcatchment channel */
  100. misc.tch[i] = misc.tch[0] + (params.d[i] - params.d[0]) / misc.vr;
  101. /* time of concentration */
  102. misc.tc = (int)misc.tch[params.nch - 1];
  103. if ((double)misc.tc < misc.tch[params.nch - 1])
  104. misc.tc++;
  105. /* routing delay in the main channel */
  106. misc.delay = (int)misc.tch[0];
  107. /* time of concentration in the subcatchment */
  108. misc.tcsub = misc.tc - misc.delay;
  109. /* cumulative ratio of the contribution area for each time step */
  110. misc.Ad = (double *)G_malloc(misc.tcsub * sizeof(double));
  111. for (i = 0; i < misc.tcsub; i++) {
  112. int t;
  113. t = misc.delay + i + 1;
  114. if (t > misc.tch[params.nch - 1])
  115. misc.Ad[i] = params.A;
  116. else {
  117. for (j = 1; j < params.nch; j++) {
  118. if (t <= misc.tch[j]) {
  119. misc.Ad[i] = params.Ad[j - 1] +
  120. (params.Ad[j] - params.Ad[j - 1]) *
  121. (t - misc.tch[j - 1]) /
  122. (misc.tch[j] - misc.tch[j - 1]);
  123. break;
  124. }
  125. }
  126. }
  127. }
  128. /* difference in the contribution area for each time step */
  129. A1 = misc.Ad[0];
  130. for (i = 1; i < misc.tcsub; i++) {
  131. A2 = misc.Ad[i];
  132. misc.Ad[i] = A2 - A1;
  133. A1 = A2;
  134. }
  135. misc.Srz = (double **)G_malloc(input.ntimesteps * sizeof(double *));
  136. misc.Suz = (double **)G_malloc(input.ntimesteps * sizeof(double *));
  137. for (i = 0; i < input.ntimesteps; i++) {
  138. misc.Srz[i] = (double *)G_malloc(misc.ntopidxclasses * sizeof(double));
  139. misc.Suz[i] = (double *)G_malloc(misc.ntopidxclasses * sizeof(double));
  140. }
  141. for (i = 0; i < misc.ntopidxclasses; i++) {
  142. /* initial root zone storage deficit */
  143. misc.Srz[0][i] = params.Sr0;
  144. /* initial unsaturated zone storage */
  145. misc.Suz[0][i] = 0.0;
  146. }
  147. misc.S_mean = (double *)G_malloc(input.ntimesteps * sizeof(double));
  148. /* initial mean saturation deficit */
  149. misc.S_mean[0] = -params.m * log(misc.qs0 / misc.qss);
  150. misc.Qt = (double *)G_malloc(input.ntimesteps * sizeof(double));
  151. /* initial total flow */
  152. A1 = 0.0;
  153. for (i = 0; i < input.ntimesteps; i++) {
  154. if (i < misc.delay)
  155. misc.Qt[i] = misc.qs0 * params.A;
  156. else if (i < misc.tc) {
  157. A1 += misc.Ad[i - misc.delay];
  158. misc.Qt[i] = misc.qs0 * (params.A - A1);
  159. } else
  160. misc.Qt[i] = 0.0;
  161. }
  162. }
  163. void calculate_flows(void)
  164. {
  165. int i, j, k;
  166. misc.S = (double **)G_malloc(input.ntimesteps * sizeof(double *));
  167. misc.Ea = (double **)G_malloc(input.ntimesteps * sizeof(double *));
  168. misc.ex = (double **)G_malloc(input.ntimesteps * sizeof(double *));
  169. misc.qt = (double **)G_malloc(input.ntimesteps * sizeof(double *));
  170. misc.qo = (double **)G_malloc(input.ntimesteps * sizeof(double *));
  171. misc.qv = (double **)G_malloc(input.ntimesteps * sizeof(double *));
  172. misc.qs = (double *)G_malloc(input.ntimesteps * sizeof(double));
  173. misc.f = (double *)G_malloc(input.ntimesteps * sizeof(double));
  174. misc.fex = (double *)G_malloc(input.ntimesteps * sizeof(double));
  175. for (i = 0; i < input.ntimesteps; i++) {
  176. double f;
  177. misc.S[i] = (double *)G_malloc(misc.ntopidxclasses * sizeof(double));
  178. misc.Ea[i] = (double *)G_malloc(misc.ntopidxclasses * sizeof(double));
  179. misc.ex[i] = (double *)G_malloc(misc.ntopidxclasses * sizeof(double));
  180. misc.qt[i] = (double *)G_malloc((misc.ntopidxclasses + 1) *
  181. sizeof(double));
  182. misc.qo[i] = (double *)G_malloc((misc.ntopidxclasses + 1) *
  183. sizeof(double));
  184. misc.qv[i] = (double *)G_malloc((misc.ntopidxclasses + 1) *
  185. sizeof(double));
  186. misc.qt[i][misc.ntopidxclasses] = 0.0;
  187. misc.qo[i][misc.ntopidxclasses] = 0.0;
  188. misc.qv[i][misc.ntopidxclasses] = 0.0;
  189. misc.qs[i] = 0.0;
  190. if (params.infex) {
  191. /* infiltration */
  192. misc.f[i] = input.dt *
  193. calculate_infiltration(i + 1, input.R[i] / input.dt);
  194. /* infiltration excess runoff */
  195. misc.fex[i] = input.R[i] - misc.f[i];
  196. f = misc.f[i];
  197. }
  198. else {
  199. /* no infiltration excess runoff */
  200. misc.f[i] = 0.0;
  201. misc.fex[i] = 0.0;
  202. /* 100% of rainfall infiltrates */
  203. f = input.R[i];
  204. }
  205. if (i) {
  206. for (j = 0; j < misc.ntopidxclasses; j++) {
  207. misc.Srz[i][j] = misc.Srz[i - 1][j];
  208. misc.Suz[i][j] = misc.Suz[i - 1][j];
  209. }
  210. }
  211. /* subsurface flow */
  212. misc.qs[i] = misc.qss * exp(-misc.S_mean[i] / params.m);
  213. for (j = 0; j < misc.ntopidxclasses; j++) {
  214. double Aatb_r;
  215. /* average area of a topographic index class */
  216. Aatb_r = (topidxstats.Aatb_r[j] +
  217. (j < misc.ntopidxclasses - 1 ? topidxstats.Aatb_r[j + 1]
  218. : 0.0)) / 2.0;
  219. /* saturation deficit */
  220. misc.S[i][j] = misc.S_mean[i] +
  221. params.m * (misc.lambda - topidxstats.atb[j]);
  222. if (misc.S[i][j] < 0.0)
  223. /* fully saturated */
  224. misc.S[i][j] = 0.0;
  225. /* root zone storage deficit */
  226. misc.Srz[i][j] -= f;
  227. if (misc.Srz[i][j] < 0.0) {
  228. /* full storage */
  229. /* unsaturated zone storage */
  230. misc.Suz[i][j] -= misc.Srz[i][j];
  231. misc.Srz[i][j] = 0.0;
  232. }
  233. /* if there is enough unsaturated zone storage */
  234. misc.ex[i][j] = 0.0;
  235. if (misc.Suz[i][j] > misc.S[i][j]) {
  236. /* saturation excess */
  237. misc.ex[i][j] = misc.Suz[i][j] - misc.S[i][j];
  238. misc.Suz[i][j] = misc.S[i][j];
  239. }
  240. /* drainage from unsaturated zone */
  241. misc.qv[i][j] = 0.0;
  242. if (misc.S[i][j] > 0.0) {
  243. misc.qv[i][j] = (params.td > 0.0 ?
  244. misc.Suz[i][j] /
  245. (misc.S[i][j] * params.td) * input.dt
  246. : -params.td * params.K0 *
  247. exp(-misc.S[i][j] / params.m));
  248. if (misc.qv[i][j] > misc.Suz[i][j])
  249. misc.qv[i][j] = misc.Suz[i][j];
  250. misc.Suz[i][j] -= misc.qv[i][j];
  251. if (misc.Suz[i][j] < ZERO)
  252. misc.Suz[i][j] = 0.0;
  253. misc.qv[i][j] *= Aatb_r;
  254. }
  255. misc.qv[i][misc.ntopidxclasses] += misc.qv[i][j];
  256. /* evapotranspiration from root zone storage deficit */
  257. misc.Ea[i][j] = 0.0;
  258. if (input.Ep[i] > 0.0) {
  259. misc.Ea[i][j] = input.Ep[i] *
  260. (1 - misc.Srz[i][j] / params.Srmax);
  261. if (misc.Ea[i][j] > params.Srmax - misc.Srz[i][j])
  262. misc.Ea[i][j] = params.Srmax - misc.Srz[i][j];
  263. }
  264. misc.Srz[i][j] += misc.Ea[i][j];
  265. /* overland flow from fully saturated area */
  266. misc.qo[i][j] = 0.0;
  267. if (j > 0) {
  268. if (misc.ex[i][j] > 0.0)
  269. misc.qo[i][j] = topidxstats.Aatb_r[j] *
  270. (misc.ex[i][j - 1] + misc.ex[i][j]) / 2.0;
  271. else if (misc.ex[i][j - 1] > 0.0)
  272. misc.qo[i][j] = Aatb_r * misc.ex[i][j - 1] / 2.0;
  273. }
  274. misc.qo[i][misc.ntopidxclasses] += misc.qo[i][j];
  275. /* total flow */
  276. misc.qt[i][j] = misc.qo[i][j] + misc.qs[i];
  277. }
  278. /* aggregate flows over topographic index classes */
  279. misc.qo[i][misc.ntopidxclasses] += misc.fex[i];
  280. misc.qt[i][misc.ntopidxclasses] = misc.qo[i][misc.ntopidxclasses] +
  281. misc.qs[i];
  282. /* mean saturation deficit */
  283. misc.S_mean[i] += misc.qs[i] - misc.qv[i][misc.ntopidxclasses];
  284. if (i + 1 < input.ntimesteps)
  285. misc.S_mean[i + 1] = misc.S_mean[i];
  286. /* total flow in m^3/timestep */
  287. for (j = 0; j < misc.tcsub; j++) {
  288. k = i + j + misc.delay;
  289. if (k > input.ntimesteps - 1)
  290. break;
  291. misc.Qt[k] += misc.qt[i][misc.ntopidxclasses] * misc.Ad[j];
  292. }
  293. }
  294. /* mean total flow */
  295. misc.Qt_mean = 0.0;
  296. for (i = 0; i < input.ntimesteps; i++) {
  297. misc.Qt_mean += misc.Qt[i];
  298. if (!i || misc.Qt_peak < misc.Qt[i]) {
  299. misc.Qt_peak = misc.Qt[i];
  300. misc.tt_peak = i + 1;
  301. }
  302. }
  303. misc.Qt_mean /= input.ntimesteps;
  304. }
  305. void run_topmodel(void)
  306. {
  307. initialize();
  308. calculate_flows();
  309. }