1
/****************************************************************************
3
* MODULE: r.series.accumulate
4
* AUTHOR(S): Markus Metz
7
* PURPOSE: Calculates (accumulated) raster value means, growing degree days
8
* (GDDs) or Winkler indices from several input maps.
9
* COPYRIGHT: (C) 2012 by the GRASS Development Team
11
* This program is free software under the GNU General Public
12
* License (>=v2). Read the file COPYING that comes with GRASS
15
*****************************************************************************/
23
#include <grass/gis.h>
24
#include <grass/raster.h>
25
#include <grass/glocale.h>
29
#define METHOD_WINKLER 3
31
#define METHOD_HUGLIN 5
47
int main(int argc, char *argv[])
49
struct GModule *module;
52
struct Option *input, *basemap, *file, *output,
53
*range, *scale, *shift, *lower,
54
*upper, *limits, *method;
58
struct Flag *nulls, *lazy, *float_output;
61
int num_inputs, max_inputs;
63
struct map_info *inputs = NULL;
64
struct map_info_out *out = NULL;
65
struct map_info *basemap = NULL;
66
struct map_info *map_lower = NULL;
67
struct map_info *map_upper = NULL;
68
struct History history;
71
DCELL lo, hi, tscale, tshift, lower = 10.0, upper = 30.0;
73
RASTER_MAP_TYPE out_type;
79
module = G_define_module();
80
G_add_keyword(_("raster"));
81
G_add_keyword(_("series"));
82
G_add_keyword(_("accumulation"));
84
_("Makes each output cell value a accumulation"
85
"function of the values assigned to the corresponding cells "
86
"in the input raster map layers.");
88
parm.basemap = G_define_standard_option(G_OPT_R_INPUT);
89
parm.basemap->key = "basemap";
90
parm.basemap->description = _("Existing map to be added to output");
91
parm.basemap->required = NO;
93
parm.input = G_define_standard_option(G_OPT_R_INPUTS);
94
parm.input->required = NO;
96
parm.file = G_define_standard_option(G_OPT_F_INPUT);
97
parm.file->key = "file";
98
parm.file->description = _("Input file with raster map names, one per line");
99
parm.file->required = NO;
101
parm.output = G_define_standard_option(G_OPT_R_OUTPUT);
102
parm.output->multiple = NO;
104
parm.scale = G_define_option();
105
parm.scale->key = "scale";
106
parm.scale->type = TYPE_DOUBLE;
107
parm.scale->answer = "1.0";
108
parm.scale->required = NO;
109
parm.scale->description = _("Scale factor for input");
111
parm.shift = G_define_option();
112
parm.shift->key = "shift";
113
parm.shift->type = TYPE_DOUBLE;
114
parm.shift->answer = "0.0";
115
parm.shift->required = NO;
116
parm.shift->description = _("Shift factor for input");
118
parm.lower = G_define_standard_option(G_OPT_R_INPUT);
119
parm.lower->key = "lower";
120
parm.lower->required = NO;
121
parm.lower->description = _("The raster map specifying the lower accumulation limit, also called baseline");
123
parm.upper = G_define_standard_option(G_OPT_R_INPUT);
124
parm.upper->key = "upper";
125
parm.upper->required = NO;
126
parm.upper->description = _("The raster map specifying the upper accumulation limit, also called cutoff. Only applied to BEDD computation.");
128
parm.range = G_define_option();
129
parm.range->key = "range";
130
parm.range->type = TYPE_DOUBLE;
131
parm.range->key_desc = "min,max";
132
parm.range->description = _("Ignore values outside this range");
134
parm.limits = G_define_option();
135
parm.limits->key = "limits";
136
parm.limits->type = TYPE_DOUBLE;
137
parm.limits->key_desc = "lower,upper";
138
parm.limits->answer = "10,30";
139
parm.limits->description = _("Use these limits in case lower and/or upper input maps are not defined");
141
parm.method = G_define_option();
142
parm.method->key = "method";
143
parm.method->type = TYPE_STRING;
144
parm.method->multiple = NO;
145
parm.method->required = NO;
146
parm.method->options = "gdd,bedd,huglin,mean";
147
parm.method->answer = "gdd";
148
parm.method->label = "This method will be applied to compute the accumulative values from the input maps";
150
"gdd;%s;mean;%s;bedd;%s;huglin;%s",
151
_("Growing Degree Days or Winkler indices"),
152
_("Mean: sum(input maps)/(number of input maps)"),
153
_("Biologically Effective Degree Days"),
154
_("Huglin Heliothermal index"));
155
parm.method->descriptions = desc;
157
flag.nulls = G_define_flag();
158
flag.nulls->key = 'n';
159
flag.nulls->description = _("Propagate NULLs");
161
flag.lazy = G_define_flag();
162
flag.lazy->key = 'z';
163
flag.lazy->description = _("Do not keep files open");
165
flag.float_output = G_define_flag();
166
flag.float_output->key = 'f';
167
flag.float_output->description = _("Create a FCELL map (floating point single precision) as output");
169
if (G_parser(argc, argv))
172
lo = -1.0 / 0.0; /* -inf */
173
hi = 1.0 / 0.0; /* inf */
176
if (G_strncasecmp(parm.method->answer, "gdd", 3) == 0)
178
else if (G_strncasecmp(parm.method->answer, "mean", 4) == 0)
179
method = METHOD_MEAN;
180
else if (G_strncasecmp(parm.method->answer, "bedd", 4) == 0)
181
method = METHOD_BEDD;
182
else if (G_strncasecmp(parm.method->answer, "huglin", 7) == 0)
183
method = METHOD_HUGLIN;
185
if (parm.range->answer) {
186
lo = atof(parm.range->answers[0]);
187
hi = atof(parm.range->answers[1]);
190
if (parm.limits->answer) {
191
lower = atof(parm.limits->answers[0]);
192
upper = atof(parm.limits->answers[1]);
195
if (parm.scale->answer)
196
tscale = atof(parm.scale->answer);
200
if (parm.shift->answer)
201
tshift = atof(parm.shift->answer);
205
if (parm.input->answer && parm.file->answer)
206
G_fatal_error(_("%s= and %s= are mutually exclusive"),
207
parm.input->key, parm.file->key);
209
if (!parm.input->answer && !parm.file->answer)
210
G_fatal_error(_("Please specify %s= or %s="),
211
parm.input->key, parm.file->key);
215
/* process the input maps from the file */
216
if (parm.file->answer) {
219
in = fopen(parm.file->answer, "r");
221
G_fatal_error(_("Unable to open input file <%s>"),
231
if (!G_getl2(buf, sizeof(buf), in))
236
/* Ignore empty lines */
240
if (num_inputs >= max_inputs) {
243
G_realloc(inputs, max_inputs * sizeof(struct map_info));
245
p = &inputs[num_inputs++];
247
p->name = G_store(name);
248
G_verbose_message(_("Reading raster map <%s>..."), p->name);
249
p->buf = Rast_allocate_d_buf();
250
if (!flag.lazy->answer)
251
p->fd = Rast_open_old(p->name, "");
255
G_fatal_error(_("No raster map name found in input file"));
260
for (i = 0; parm.input->answers[i]; i++)
265
G_fatal_error(_("Raster map not found"));
267
inputs = G_malloc(num_inputs * sizeof(struct map_info));
269
for (i = 0; i < num_inputs; i++) {
270
struct map_info *p = &inputs[i];
272
p->name = parm.input->answers[i];
273
G_verbose_message(_("Reading raster map <%s>..."), p->name);
274
p->buf = Rast_allocate_d_buf();
275
if (!flag.lazy->answer)
276
p->fd = Rast_open_old(p->name, "");
278
max_inputs = num_inputs;
281
if (parm.basemap->answer) {
282
basemap = G_malloc(1 * sizeof(struct map_info));
283
basemap->name = parm.basemap->answer;
284
G_verbose_message(_("Reading raster map <%s>..."), basemap->name);
285
basemap->buf = Rast_allocate_d_buf();
286
basemap->fd = Rast_open_old(basemap->name, "");
289
if (parm.lower->answer) {
290
map_lower = G_malloc(1 * sizeof(struct map_info));
291
map_lower->name = parm.lower->answer;
292
G_verbose_message(_("Reading raster map <%s>..."), map_lower->name);
293
map_lower->buf = Rast_allocate_d_buf();
294
map_lower->fd = Rast_open_old(map_lower->name, "");
297
if (parm.upper->answer) {
298
map_upper = G_malloc(1 * sizeof(struct map_info));
299
map_upper->name = parm.upper->answer;
300
G_verbose_message(_("Reading raster map <%s>..."), map_upper->name);
301
map_upper->buf = Rast_allocate_d_buf();
302
map_upper->fd = Rast_open_old(map_upper->name, "");
305
out = G_calloc(1, sizeof(struct map_info_out));
306
out->name = parm.output->answer;
307
out_type = flag.float_output->answer ? FCELL_TYPE : DCELL_TYPE;
308
out->buf = Rast_allocate_buf(out_type);
309
out_size = Rast_cell_size(out_type);
310
out->fd = Rast_open_new(out->name, out_type);
312
nrows = Rast_window_rows();
313
ncols = Rast_window_cols();
315
Rast_set_d_null_value(&dcell_null, 1);
317
/* process the data */
318
G_verbose_message(_("Percent complete..."));
320
for (row = 0; row < nrows; row++) {
321
G_percent(row, nrows, 2);
324
Rast_get_d_row(basemap->fd, basemap->buf, row);
326
Rast_get_d_row(map_lower->fd, map_lower->buf, row);
328
Rast_get_d_row(map_upper->fd, map_upper->buf, row);
330
if (flag.lazy->answer) {
331
/* Open the files only on run time */
332
for (i = 0; i < num_inputs; i++) {
333
inputs[i].fd = Rast_open_old(inputs[i].name, "");
334
Rast_get_d_row(inputs[i].fd, inputs[i].buf, row);
335
Rast_close(inputs[i].fd);
339
for (i = 0; i < num_inputs; i++)
340
Rast_get_d_row(inputs[i].fd, inputs[i].buf, row);
343
#pragma omp for schedule (static) private (col)
344
for (col = 0; col < ncols; col++) {
345
int null = 0, non_null = 0;
346
DCELL min, max, avg, value;
349
lower = map_lower->buf[col];
351
upper = map_upper->buf[col];
354
G_fatal_error(_("'%s'=%f must be > '%s'=%f"), parm.upper->key, upper,
355
parm.lower->key, lower);
361
for (i = 0; i < num_inputs; i++) {
362
DCELL v = inputs[i].buf[col];
364
if (Rast_is_d_null_value(&v))
367
v = v * tscale + tshift;
368
if (parm.range->answer && (v < lo || v > hi)) {
373
if (min > v || Rast_is_d_null_value(&min))
375
if (max < v || Rast_is_d_null_value(&max))
383
if (!non_null || (null && flag.nulls->answer)) {
385
value = basemap->buf[col];
388
/* Compute mean or index */
393
avg = (avg + max) / 2;
403
/* Winkler or GDD index computation is the default */
406
if (method != METHOD_MEAN) {
414
value += basemap->buf[col];
416
Rast_set_d_value((char *)out->buf + col * out_size, value, out_type);
418
Rast_put_row(out->fd, out->buf, out_type);
421
G_percent(row, nrows, 2);
423
/* close output map */
426
Rast_short_history(out->name, "raster", &history);
427
Rast_command_history(&history);
428
Rast_write_history(out->name, &history);
430
/* Close input maps */
432
Rast_close(basemap->fd);
434
Rast_close(map_lower->fd);
436
Rast_close(map_upper->fd);
438
if (!flag.lazy->answer) {
439
for (i = 0; i < num_inputs; i++)
440
Rast_close(inputs[i].fd);
443
if (method == METHOD_GDD) {
444
struct Colors colors;
446
Rast_init_colors(&colors);
447
Rast_make_colors(&colors, "gdd", 0, 6000);
448
Rast_write_colors(out->name, G_mapset(), &colors);