[GRASSLIST:2914] Puzzling mapcalc command

Hello,
I want to compute some maps with mapcalc (GRASS53 v2004/03.. on a SuSE box).
Depending on the way I parse the info to the command I have results or none

If I have a file "tmp" with
Vold=V
V=V+Down.0
Down=1
V=V-Down
Out=2
In=100000.*On.NN*Out[-1,0]

the command "cat tmp | r.mapcalc" gives me:
parse error, unexpected '[', expecting $end
Parse error

The commands entered one by one gives satisfactory results (in particular,
r.mapcalc "In=100000.*On.NN*Out[-1,0]"
or
echo "In=100000.*On.NN*Out[-1,0]" | r.mapcalc
both works.

I'd be very happy to get any insight :slight_smile:

Thx a lot in advance
P.

--
Soil & Water Laboratory
Dept. of Biological & Environmental Engineering
Cornell University
ITHACA, NY 14853
Tel: (607)255.2463

SWlab wrote:

I want to compute some maps with mapcalc (GRASS53 v2004/03.. on a SuSE box).
Depending on the way I parse the info to the command I have results or none

If I have a file "tmp" with
Vold=V
V=V+Down.0
Down=1
V=V-Down
Out=2
In=100000.*On.NN*Out[-1,0]

the command "cat tmp | r.mapcalc" gives me:
parse error, unexpected '[', expecting $end
Parse error

The commands entered one by one gives satisfactory results (in particular,
r.mapcalc "In=100000.*On.NN*Out[-1,0]"
or
echo "In=100000.*On.NN*Out[-1,0]" | r.mapcalc
both works.

I'd be very happy to get any insight :slight_smile:

Actually, I'm slightly surprised that r.mapcalc actually made it to
the last line without reporting an error. In retrospect, I can see
why; however, r.mapcalc should probably be changed to prohibit certain
aspects of the above. In particular, it should probably prohibit using
an identifier on the LHS of an assignment after it has occurred
elsewhere.

Identifiers can be interpreted in two different ways: as either a map
name or as a variable. If an identifier has previously occurred on the
LHS of an assignment, it is interpreted as a variable, otherwise it is
interpreted as a map name. [Names enclosed within quotes are always
interpreted as map names.]

In your first example, the line "Out=2" defines "Out" as a variable.
Consequently, the expression "Out[-1,0]" is invalid, as neighbourhood
modifiers can only be applied to maps, not variables. The same also
applies to colour and category lookups (i.e. @map, #map, etc).

OTOH, if you evaluate the statments individually, the identifier "Out"
in the expression "Out[-1,0]" will be interpreted as a map name, so
the neighbourhood modifier is valid.

An r.mapcalc "program" is essentially a list of assignments, each of
the form "<name> = <expression>". Assignment statements can occur
elsewhere, just like in C, and always define a variable that can be
accessed later in the program. However, those which occur at the top
level also create new maps.

Furthermore, any maps which are created by r.mapcalc don't actually
exist as maps until the program completes, so they cannot be accessed
as maps within the program.

--
Glynn Clements <glynn.clements@virgin.net>

[Thursday 11 March 2004 21:14] From Glynn Clements

SWlab wrote:
> I want to compute some maps with mapcalc (GRASS53 v2004/03.. on a SuSE
> box). Depending on the way I parse the info to the command I have results
> or none

Actually, I'm slightly surprised that r.mapcalc actually made it to
the last line without reporting an error. In retrospect, I can see
why; however, r.mapcalc should probably be changed to prohibit certain
aspects of the above. In particular, it should probably prohibit using
an identifier on the LHS of an assignment after it has occurred
elsewhere.

Glynn, thanks a lot for your enlighting answer. For a bit more background:
I'm porting a set of bash scripts to perl. The bash scripts were basically a
succession of calls to "r.mapcalc": maps were then evaluated at once, and
everything worked fine. Except of course that I kept on calling "r.mapcalc",
and I assume that there should be some initialization each time I call the
command (I don't speak C, so the sources are not really meaningful to me).

So I thought it'd be quicker (and more elegant) to put all my calls into one
big string, and call mapcalc just once (with the small function below). Fatal
mistake as you explained it so well... It seems that a workaround would be to
create shortr command lines, making sure the maps are created before using
them...

Is there any alternative to "r.mapcalc" to create/modify rasters in scripts ?
I thought about using PDLs in Perl, but the interaction with GRASS has to be
optimized to be really useful (I started using r.in.ascii/r.out.ascii to
read/write GRASS maps to/from PDLs, but the process is a bit too long...). Of
course, not talking C is a handicap, and I'm not really keen on using
FORTRAN either... Any idea would be welcomed.

Thanks alot

# A Perl call to mapcalc ########################
sub rmapcalc() {
    my $command=shift;
    for ($command) {
        s/ +//g; # Strips multiple spaces
        s/(?<!\n)\n//g; # Suppress NL in middle of a line
    };
    croak "ERROR: cannot fork: $!" unless defined(my $pid=open(GRASS,"|-"));
    my $tmpfile=".tmpsmdr";
    if($pid){
        print GRASS "$command\nexit\n";
        close(GRASS) or do { print "\nERROR with 'r.mapcalc' :\n";
                             print "$command\nexit\n";
                             open(X,"<$tmpfile") or die "Can't find
$tmpfile:$!";
                             while(<X>){print $_};
                             croak "Exit...";
                            };
        unlink($tmpfile); }
    else {
        exec("r.mapcalc 2>$tmpfile") or
            croak "ERROR: can't execute 'r.mapcalc': $!";
    };
    return;
};

--
Soil & Water Laboratory
Dept. of Biological & Environmental Engineering
Cornell University
ITHACA, NY 14853
Tel: (607)255.2463

On Mar 12, 2004, at 12:28 PM, SWlab wrote:

Is there any alternative to "r.mapcalc" to create/modify rasters in scripts ?
I thought about using PDLs in Perl, but the interaction with GRASS has to be
optimized to be really useful (I started using r.in.ascii/r.out.ascii to
read/write GRASS maps to/from PDLs, but the process is a bit too long...). Of
course, not talking C is a handicap, and I'm not really keen on using
FORTRAN either... Any idea would be welcomed.

What about using R? The R-GRASS module seems to be pretty well-developed, and designed for raster manipulation. Have a look at the example in Markus' short course:

http://mpa.itc.it/markus/shortcourse/notes7.html

Chris
--
Christopher J. Fonnesbeck ( c h r i s @ f o n n e s b e c k . o r g )
Georgia Cooperative Fish & Wildlife Research Unit, University of Georgia

SWlab wrote:

> > I want to compute some maps with mapcalc (GRASS53 v2004/03.. on a SuSE
> > box). Depending on the way I parse the info to the command I have results
> > or none

> Actually, I'm slightly surprised that r.mapcalc actually made it to
> the last line without reporting an error. In retrospect, I can see
> why; however, r.mapcalc should probably be changed to prohibit certain
> aspects of the above. In particular, it should probably prohibit using
> an identifier on the LHS of an assignment after it has occurred
> elsewhere.

Glynn, thanks a lot for your enlighting answer. For a bit more background:
I'm porting a set of bash scripts to perl. The bash scripts were basically a
succession of calls to "r.mapcalc": maps were then evaluated at once, and
everything worked fine. Except of course that I kept on calling "r.mapcalc",
and I assume that there should be some initialization each time I call the
command (I don't speak C, so the sources are not really meaningful to me).

A multi-statement r.mapcalc program is different from calling
r.mapcalc multiple times. The former does:

  open all input maps
  open all output maps
  for each row
    read row from all input maps
    for each output map
      calculate and write row of output map
  close all input maps
  close all output maps

while the latter does

  for each output map
    open all input maps
    open output map
    for each row
      read row from all input maps
      calculate and write row of output map
    close output map
    close all input maps

The main semantic consequence of this is that, in a multi-statement
r.mapcalc program, you can't use the output maps as maps, only as
variables.

OTOH, if any maps occur on the RHS of more than one assignment,
performing multiple assignments in one command will be more efficient,
as the input maps are only opened/read/closed once per command, not
once per output map.

So I thought it'd be quicker (and more elegant) to put all my calls into one
big string, and call mapcalc just once (with the small function below). Fatal
mistake as you explained it so well... It seems that a workaround would be to
create shortr command lines, making sure the maps are created before using
them...

For complex calculations, you ideally want a two-level structure, i.e.
a sequence of multi-statement r.mapcalc programs, with each program
doing as much as possible to minimise the total number of programs.

Also, to avoid writing intermediate variables as maps, use eval().
E.g.

  V1 = 1
  V2 = 2
  Out = V1+V2

will create maps V1, V2 and Out, while

  Out = eval(V1 = 1, V2 = 2, V1+V2)

will only create "Out".

[eval() returns its last argument; the other arguments are only useful
insofar as they have side effects.]

BTW, you probably shouldn't use a variable on both the LHS and RHS of
an assignment (e.g. V=V+1). Whilst it will work in most cases, it
isn't guaranteed. Instead, use several variables, assigning each one
only once.

Is there any alternative to "r.mapcalc" to create/modify rasters in scripts ?
I thought about using PDLs in Perl, but the interaction with GRASS has to be
optimized to be really useful (I started using r.in.ascii/r.out.ascii to
read/write GRASS maps to/from PDLs, but the process is a bit too long...). Of
course, not talking C is a handicap, and I'm not really keen on using
FORTRAN either... Any idea would be welcomed.

Note that the limitation of not being able to read a map until it has
been created is inherent in GRASS itself. When creating maps (which
includes overwriting existing maps), the data is always written to a
temporary file. The new map isn't "visible" until it has been closed
(i.e. completely written).

--
Glynn Clements <glynn.clements@virgin.net>