1
"""@package grass.temporal
3
Temporal algebra parser class
5
(C) 2014 by the GRASS Development Team
6
This program is free software under the GNU General Public
7
License (>=v2). Read the file COPYING that comes with GRASS
10
:authors: Thomas Leppelt and Soeren Gebbert
12
.. code-block:: python
14
>>> import grass.temporal as tgis
16
>>> p = tgis.TemporalAlgebraLexer()
19
>>> expression = "C = A : B"
20
>>> p.test(expression)
22
LexToken(NAME,'C',1,0)
23
LexToken(EQUALS,'=',1,2)
24
LexToken(NAME,'A',1,4)
25
LexToken(T_SELECT,':',1,6)
26
LexToken(NAME,'B',1,8)
27
>>> expression = "C = test1 !: test2"
28
>>> p.test(expression)
30
LexToken(NAME,'C',1,0)
31
LexToken(EQUALS,'=',1,2)
32
LexToken(NAME,'test1',1,4)
33
LexToken(T_NOT_SELECT,'!:',1,10)
34
LexToken(NAME,'test2',1,13)
35
>>> expression = "C = test1 {:,equal} test2"
36
>>> p.test(expression)
37
C = test1 {:,equal} test2
38
LexToken(NAME,'C',1,0)
39
LexToken(EQUALS,'=',1,2)
40
LexToken(NAME,'test1',1,4)
41
LexToken(T_SELECT_OPERATOR,'{:,equal}',1,10)
42
LexToken(NAME,'test2',1,20)
43
>>> expression = "C = test1 {!:,equal} test2"
44
>>> p.test(expression)
45
C = test1 {!:,equal} test2
46
LexToken(NAME,'C',1,0)
47
LexToken(EQUALS,'=',1,2)
48
LexToken(NAME,'test1',1,4)
49
LexToken(T_SELECT_OPERATOR,'{!:,equal}',1,10)
50
LexToken(NAME,'test2',1,21)
51
>>> expression = "C = test1 # test2"
52
>>> p.test(expression)
54
LexToken(NAME,'C',1,0)
55
LexToken(EQUALS,'=',1,2)
56
LexToken(NAME,'test1',1,4)
57
LexToken(HASH,'#',1,10)
58
LexToken(NAME,'test2',1,12)
59
>>> expression = "C = test1 {#} test2"
60
>>> p.test(expression)
62
LexToken(NAME,'C',1,0)
63
LexToken(EQUALS,'=',1,2)
64
LexToken(NAME,'test1',1,4)
65
LexToken(T_HASH_OPERATOR,'{#}',1,10)
66
LexToken(NAME,'test2',1,14)
67
>>> expression = "C = test1 {#,equal} test2"
68
>>> p.test(expression)
69
C = test1 {#,equal} test2
70
LexToken(NAME,'C',1,0)
71
LexToken(EQUALS,'=',1,2)
72
LexToken(NAME,'test1',1,4)
73
LexToken(T_HASH_OPERATOR,'{#,equal}',1,10)
74
LexToken(NAME,'test2',1,20)
75
>>> expression = "C = test1 {#,equal|during} test2"
76
>>> p.test(expression)
77
C = test1 {#,equal|during} test2
78
LexToken(NAME,'C',1,0)
79
LexToken(EQUALS,'=',1,2)
80
LexToken(NAME,'test1',1,4)
81
LexToken(T_HASH_OPERATOR,'{#,equal|during}',1,10)
82
LexToken(NAME,'test2',1,27)
83
>>> expression = "E = test1 : test2 !: test1"
84
>>> p.test(expression)
85
E = test1 : test2 !: test1
86
LexToken(NAME,'E',1,0)
87
LexToken(EQUALS,'=',1,2)
88
LexToken(NAME,'test1',1,4)
89
LexToken(T_SELECT,':',1,10)
90
LexToken(NAME,'test2',1,12)
91
LexToken(T_NOT_SELECT,'!:',1,18)
92
LexToken(NAME,'test1',1,21)
93
>>> expression = 'D = buff_t(test1,"10 months")'
94
>>> p.test(expression)
95
D = buff_t(test1,"10 months")
96
LexToken(NAME,'D',1,0)
97
LexToken(EQUALS,'=',1,2)
98
LexToken(BUFF_T,'buff_t',1,4)
99
LexToken(LPAREN,'(',1,10)
100
LexToken(NAME,'test1',1,11)
101
LexToken(COMMA,',',1,16)
102
LexToken(QUOTE,'"',1,17)
103
LexToken(INT,10,1,18)
104
LexToken(NAME,'months',1,21)
105
LexToken(QUOTE,'"',1,27)
106
LexToken(RPAREN,')',1,28)
107
>>> expression = 'H = tsnap(test1)'
108
>>> p.test(expression)
110
LexToken(NAME,'H',1,0)
111
LexToken(EQUALS,'=',1,2)
112
LexToken(TSNAP,'tsnap',1,4)
113
LexToken(LPAREN,'(',1,9)
114
LexToken(NAME,'test1',1,10)
115
LexToken(RPAREN,')',1,15)
116
>>> expression = 'H = tsnap(test2 {:,during} buff_t(test1, "1 days"))'
117
>>> p.test(expression)
118
H = tsnap(test2 {:,during} buff_t(test1, "1 days"))
119
LexToken(NAME,'H',1,0)
120
LexToken(EQUALS,'=',1,2)
121
LexToken(TSNAP,'tsnap',1,4)
122
LexToken(LPAREN,'(',1,9)
123
LexToken(NAME,'test2',1,10)
124
LexToken(T_SELECT_OPERATOR,'{:,during}',1,16)
125
LexToken(BUFF_T,'buff_t',1,27)
126
LexToken(LPAREN,'(',1,33)
127
LexToken(NAME,'test1',1,34)
128
LexToken(COMMA,',',1,39)
129
LexToken(QUOTE,'"',1,41)
131
LexToken(NAME,'days',1,44)
132
LexToken(QUOTE,'"',1,48)
133
LexToken(RPAREN,')',1,49)
134
LexToken(RPAREN,')',1,50)
135
>>> expression = 'H = tshift(test2 {:,during} buff_t(test1, "1 days"), "1 months")'
136
>>> p.test(expression)
137
H = tshift(test2 {:,during} buff_t(test1, "1 days"), "1 months")
138
LexToken(NAME,'H',1,0)
139
LexToken(EQUALS,'=',1,2)
140
LexToken(TSHIFT,'tshift',1,4)
141
LexToken(LPAREN,'(',1,10)
142
LexToken(NAME,'test2',1,11)
143
LexToken(T_SELECT_OPERATOR,'{:,during}',1,17)
144
LexToken(BUFF_T,'buff_t',1,28)
145
LexToken(LPAREN,'(',1,34)
146
LexToken(NAME,'test1',1,35)
147
LexToken(COMMA,',',1,40)
148
LexToken(QUOTE,'"',1,42)
150
LexToken(NAME,'days',1,45)
151
LexToken(QUOTE,'"',1,49)
152
LexToken(RPAREN,')',1,50)
153
LexToken(COMMA,',',1,51)
154
LexToken(QUOTE,'"',1,53)
156
LexToken(NAME,'months',1,56)
157
LexToken(QUOTE,'"',1,62)
158
LexToken(RPAREN,')',1,63)
159
>>> expression = 'H = tshift(A , 10)'
160
>>> p.test(expression)
162
LexToken(NAME,'H',1,0)
163
LexToken(EQUALS,'=',1,2)
164
LexToken(TSHIFT,'tshift',1,4)
165
LexToken(LPAREN,'(',1,10)
166
LexToken(NAME,'A',1,11)
167
LexToken(COMMA,',',1,13)
168
LexToken(INT,10,1,15)
169
LexToken(RPAREN,')',1,17)
170
>>> expression = 'H = if(td(A) > 10, A)'
171
>>> p.test(expression)
172
H = if(td(A) > 10, A)
173
LexToken(NAME,'H',1,0)
174
LexToken(EQUALS,'=',1,2)
175
LexToken(IF,'if',1,4)
176
LexToken(LPAREN,'(',1,6)
177
LexToken(TD,'td',1,7)
178
LexToken(LPAREN,'(',1,9)
179
LexToken(NAME,'A',1,10)
180
LexToken(RPAREN,')',1,11)
181
LexToken(GREATER,'>',1,13)
182
LexToken(INT,10,1,15)
183
LexToken(COMMA,',',1,17)
184
LexToken(NAME,'A',1,19)
185
LexToken(RPAREN,')',1,20)
186
>>> expression = 'H = if(td(A) > 10, A, B)'
187
>>> p.test(expression)
188
H = if(td(A) > 10, A, B)
189
LexToken(NAME,'H',1,0)
190
LexToken(EQUALS,'=',1,2)
191
LexToken(IF,'if',1,4)
192
LexToken(LPAREN,'(',1,6)
193
LexToken(TD,'td',1,7)
194
LexToken(LPAREN,'(',1,9)
195
LexToken(NAME,'A',1,10)
196
LexToken(RPAREN,')',1,11)
197
LexToken(GREATER,'>',1,13)
198
LexToken(INT,10,1,15)
199
LexToken(COMMA,',',1,17)
200
LexToken(NAME,'A',1,19)
201
LexToken(COMMA,',',1,20)
202
LexToken(NAME,'B',1,22)
203
LexToken(RPAREN,')',1,23)
204
>>> expression = 'I = if(equals,td(A) > 10 {||,equals} td(B) < 10, A)'
205
>>> p.test(expression)
206
I = if(equals,td(A) > 10 {||,equals} td(B) < 10, A)
207
LexToken(NAME,'I',1,0)
208
LexToken(EQUALS,'=',1,2)
209
LexToken(IF,'if',1,4)
210
LexToken(LPAREN,'(',1,6)
211
LexToken(NAME,'equals',1,7)
212
LexToken(COMMA,',',1,13)
213
LexToken(TD,'td',1,14)
214
LexToken(LPAREN,'(',1,16)
215
LexToken(NAME,'A',1,17)
216
LexToken(RPAREN,')',1,18)
217
LexToken(GREATER,'>',1,20)
218
LexToken(INT,10,1,22)
219
LexToken(T_COMP_OPERATOR,'{||,equals}',1,25)
220
LexToken(TD,'td',1,37)
221
LexToken(LPAREN,'(',1,39)
222
LexToken(NAME,'B',1,40)
223
LexToken(RPAREN,')',1,41)
224
LexToken(LOWER,'<',1,43)
225
LexToken(INT,10,1,45)
226
LexToken(COMMA,',',1,47)
227
LexToken(NAME,'A',1,49)
228
LexToken(RPAREN,')',1,50)
229
>>> expression = 'I = if(equals,td(A) > 10 || start_day() < 10, A)'
230
>>> p.test(expression)
231
I = if(equals,td(A) > 10 || start_day() < 10, A)
232
LexToken(NAME,'I',1,0)
233
LexToken(EQUALS,'=',1,2)
234
LexToken(IF,'if',1,4)
235
LexToken(LPAREN,'(',1,6)
236
LexToken(NAME,'equals',1,7)
237
LexToken(COMMA,',',1,13)
238
LexToken(TD,'td',1,14)
239
LexToken(LPAREN,'(',1,16)
240
LexToken(NAME,'A',1,17)
241
LexToken(RPAREN,')',1,18)
242
LexToken(GREATER,'>',1,20)
243
LexToken(INT,10,1,22)
244
LexToken(OR,'|',1,25)
245
LexToken(OR,'|',1,26)
246
LexToken(START_DAY,'start_day',1,28)
247
LexToken(LPAREN,'(',1,37)
248
LexToken(RPAREN,')',1,38)
249
LexToken(LOWER,'<',1,40)
250
LexToken(INT,10,1,42)
251
LexToken(COMMA,',',1,44)
252
LexToken(NAME,'A',1,46)
253
LexToken(RPAREN,')',1,47)
254
>>> expression = 'E = if({equals},td(A) >= 4 {&&,contain} td(B) == 2, C : D)'
255
>>> p.test(expression)
256
E = if({equals},td(A) >= 4 {&&,contain} td(B) == 2, C : D)
257
LexToken(NAME,'E',1,0)
258
LexToken(EQUALS,'=',1,2)
259
LexToken(IF,'if',1,4)
260
LexToken(LPAREN,'(',1,6)
261
LexToken(T_REL_OPERATOR,'{equals}',1,7)
262
LexToken(COMMA,',',1,15)
263
LexToken(TD,'td',1,16)
264
LexToken(LPAREN,'(',1,18)
265
LexToken(NAME,'A',1,19)
266
LexToken(RPAREN,')',1,20)
267
LexToken(GREATER_EQUALS,'>=',1,22)
269
LexToken(T_COMP_OPERATOR,'{&&,contain}',1,27)
270
LexToken(TD,'td',1,40)
271
LexToken(LPAREN,'(',1,42)
272
LexToken(NAME,'B',1,43)
273
LexToken(RPAREN,')',1,44)
274
LexToken(CEQUALS,'==',1,46)
276
LexToken(COMMA,',',1,50)
277
LexToken(NAME,'C',1,52)
278
LexToken(T_SELECT,':',1,54)
279
LexToken(NAME,'D',1,56)
280
LexToken(RPAREN,')',1,57)
281
>>> expression = 'F = if({equals},A {#,equal}, B, C : D)'
282
>>> p.test(expression)
283
F = if({equals},A {#,equal}, B, C : D)
284
LexToken(NAME,'F',1,0)
285
LexToken(EQUALS,'=',1,2)
286
LexToken(IF,'if',1,4)
287
LexToken(LPAREN,'(',1,6)
288
LexToken(T_REL_OPERATOR,'{equals}',1,7)
289
LexToken(COMMA,',',1,15)
290
LexToken(NAME,'A',1,16)
291
LexToken(T_HASH_OPERATOR,'{#,equal}',1,18)
292
LexToken(COMMA,',',1,27)
293
LexToken(NAME,'B',1,29)
294
LexToken(COMMA,',',1,30)
295
LexToken(NAME,'C',1,32)
296
LexToken(T_SELECT,':',1,34)
297
LexToken(NAME,'D',1,36)
298
LexToken(RPAREN,')',1,37)
299
>>> p = tgis.TemporalAlgebraParser()
302
>>> expression = "D = A {!:} B {:,during} C"
303
>>> print(expression)
304
D = A {!:} B {:,during} C
305
>>> p.parse(expression)
307
A** = A* {:,during} C
309
>>> expression = "D = A {:} B {!:,during} C"
310
>>> print(expression)
311
D = A {:} B {!:,during} C
312
>>> p.parse(expression)
314
A** = A* {!:,during} C
318
>>> expression = "C = test1 : test2"
319
>>> print(expression)
321
>>> p.parse(expression, 'stvds')
322
>>> expression = 'D = buff_t(test1,"10 months")'
323
>>> print(expression)
324
D = buff_t(test1,"10 months")
325
>>> p.parse(expression, 'stvds')
326
>>> expression = 'E = test2 {:,during} buff_t(test1,"1 days")'
327
>>> print(expression)
328
E = test2 {:,during} buff_t(test1,"1 days")
329
>>> p.parse(expression, 'stvds')
330
>>> expression = 'F = test2 {:,equal} buff_t(test1,"1 days")'
331
>>> print(expression)
332
F = test2 {:,equal} buff_t(test1,"1 days")
333
>>> p.parse(expression, 'stvds')
335
>>> expression = 'H = tsnap(test2 {:,during} buff_t(test1, "1 days"))'
336
>>> p.parse(expression, 'stvds')
337
test1* = buff_t( test1 , " 1 days " )
338
test2* = test2 {:,during} test1*
339
test2** = tsnap( test2* )
341
>>> expression = 'H = tshift(test2 {:,during} test1, "1 days")'
342
>>> p.parse(expression, 'stvds')
343
test2* = test2 {:,during} test1
344
test2** = tshift( test2* , " 1 days " )
346
>>> expression = 'H = tshift(H, 3)'
347
>>> p.parse(expression, 'stvds')
350
>>> expression = 'C = if(td(A) == 2, A)'
351
>>> p.parse(expression, 'stvds')
354
A* = if condition None then A
356
>>> expression = 'C = if(td(A) == 5, A, B)'
357
>>> p.parse(expression, 'stvds')
360
A* = if condition None then A else B
362
>>> expression = 'C = if(td(A) == 5 || start_date(A) > "2010-01-01", A, B)'
363
>>> p.parse(expression, 'stvds')
366
start_date A > "2010-01-01"
368
A* = if condition None then A else B
371
>>> p = tgis.TemporalAlgebraLexer()
374
>>> expression = "D = strds(A) : stvds(B) : str3ds(C)"
375
>>> p.test(expression)
376
D = strds(A) : stvds(B) : str3ds(C)
377
LexToken(NAME,'D',1,0)
378
LexToken(EQUALS,'=',1,2)
379
LexToken(STRDS,'strds',1,4)
380
LexToken(LPAREN,'(',1,9)
381
LexToken(NAME,'A',1,10)
382
LexToken(RPAREN,')',1,11)
383
LexToken(T_SELECT,':',1,13)
384
LexToken(STVDS,'stvds',1,15)
385
LexToken(LPAREN,'(',1,20)
386
LexToken(NAME,'B',1,21)
387
LexToken(RPAREN,')',1,22)
388
LexToken(T_SELECT,':',1,24)
389
LexToken(STR3DS,'str3ds',1,26)
390
LexToken(LPAREN,'(',1,32)
391
LexToken(NAME,'C',1,33)
392
LexToken(RPAREN,')',1,34)
394
>>> p = tgis.TemporalAlgebraLexer()
397
>>> expression = "R = if(A {#,during} stvds(C) == 1, A)"
398
>>> p.test(expression)
399
R = if(A {#,during} stvds(C) == 1, A)
400
LexToken(NAME,'R',1,0)
401
LexToken(EQUALS,'=',1,2)
402
LexToken(IF,'if',1,4)
403
LexToken(LPAREN,'(',1,6)
404
LexToken(NAME,'A',1,7)
405
LexToken(T_HASH_OPERATOR,'{#,during}',1,9)
406
LexToken(STVDS,'stvds',1,20)
407
LexToken(LPAREN,'(',1,25)
408
LexToken(NAME,'C',1,26)
409
LexToken(RPAREN,')',1,27)
410
LexToken(CEQUALS,'==',1,29)
412
LexToken(COMMA,',',1,33)
413
LexToken(NAME,'A',1,35)
414
LexToken(RPAREN,')',1,36)
416
>>> p = tgis.TemporalAlgebraLexer()
419
>>> expression = "R = if({during}, stvds(C) {#,contains} A == 2, A)"
420
>>> p.test(expression)
421
R = if({during}, stvds(C) {#,contains} A == 2, A)
422
LexToken(NAME,'R',1,0)
423
LexToken(EQUALS,'=',1,2)
424
LexToken(IF,'if',1,4)
425
LexToken(LPAREN,'(',1,6)
426
LexToken(T_REL_OPERATOR,'{during}',1,7)
427
LexToken(COMMA,',',1,15)
428
LexToken(STVDS,'stvds',1,17)
429
LexToken(LPAREN,'(',1,22)
430
LexToken(NAME,'C',1,23)
431
LexToken(RPAREN,')',1,24)
432
LexToken(T_HASH_OPERATOR,'{#,contains}',1,26)
433
LexToken(NAME,'A',1,39)
434
LexToken(CEQUALS,'==',1,41)
436
LexToken(COMMA,',',1,45)
437
LexToken(NAME,'A',1,47)
438
LexToken(RPAREN,')',1,48)
443
import ply.lex as lex
444
import ply.yacc as yacc
450
import grass.pygrass.modules as pymod
451
from space_time_datasets import *
452
from factory import *
453
from open_stds import *
454
from temporal_operator import *
456
##############################################################################
458
class TemporalAlgebraLexer(object):
459
"""Lexical analyzer for the GRASS GIS temporal algebra"""
461
# Functions that defines an if condition, temporal buffering, snapping and
462
# selection of maps with temporal extent.
463
conditional_functions = {
474
# Variables with date and time strings
475
datetime_functions = {
476
'start_time' : 'START_TIME', # start time as HH::MM:SS
477
'start_date' : 'START_DATE', # start date as yyyy-mm-DD
478
'start_datetime' : 'START_DATETIME', # start datetime as yyyy-mm-DD HH:MM:SS
479
'end_time' : 'END_TIME', # end time as HH:MM:SS
480
'end_date' : 'END_DATE', # end date as yyyy-mm-DD
481
'end_datetime' : 'END_DATETIME', # end datetime as yyyy-mm-DD HH:MM:SS
486
'td' : 'TD', # The size of the current
487
# sample time interval in days and
488
# fraction of days for absolute time,
489
# and in relative units in case of relative time.
490
#'start_td' : 'START_TD', # The time difference between the start
491
# time of the sample space time raster
492
# dataset and the start time of the
493
# current sample interval or instance.
494
# The time is measured in days and
495
# fraction of days for absolute time,
496
# and in relative units in case of relative time.
497
#'end_td' : 'END_TD', # The time difference between the
498
# start time of the sample
499
# space time raster dataset and the
500
# end time of the current sample interval.
501
# The time is measured in days and
502
# fraction of days for absolute time,
503
# and in relative units in case of relative time.
504
# The end_time() will be represented by null() in case of a time instance.
505
'start_doy' : 'START_DOY', # Day of year (doy) from the start time [1 - 366]
506
'start_dow' : 'START_DOW', # Day of week (dow) from the start time [1 - 7], the start of the week is Monday == 1
507
'start_year' : 'START_YEAR', # The year of the start time [0 - 9999]
508
'start_month' : 'START_MONTH', # The month of the start time [1 - 12]
509
'start_week' : 'START_WEEK', # Week of year of the start time [1 - 54]
510
'start_day' : 'START_DAY', # Day of month from the start time [1 - 31]
511
'start_hour' : 'START_HOUR', # The hour of the start time [0 - 23]
512
'start_minute': 'START_MINUTE', # The minute of the start time [0 - 59]
513
'start_second': 'START_SECOND', # The second of the start time [0 - 59]
514
'end_doy' : 'END_DOY', # Day of year (doy) from the end time [1 - 366]
515
'end_dow' : 'END_DOW', # Day of week (dow) from the end time [1 - 7], the start of the week is Monday == 1
516
'end_year' : 'END_YEAR', # The year of the end time [0 - 9999]
517
'end_month' : 'END_MONTH', # The month of the end time [1 - 12]
518
'end_week' : 'END_WEEK', # Week of year of the end time [1 - 54]
519
'end_day' : 'END_DAY', # Day of month from the start time [1 - 31]
520
'end_hour' : 'END_HOUR', # The hour of the end time [0 - 23]
521
'end_minute' : 'END_MINUTE', # The minute of the end time [0 - 59]
522
'end_second' : 'END_SECOND', # The second of the end time [0 - 59]
525
# This is the list of token names.
555
# Build the token list
556
tokens = tokens + tuple(datetime_functions.values()) \
557
+ tuple(time_functions.values()) \
558
+ tuple(conditional_functions.values())
560
# Regular expression rules for simple tokens
561
t_T_SELECT_OPERATOR = r'\{[!]?[:][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}'
562
t_T_HASH_OPERATOR = r'\{[#][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}'
563
t_T_COMP_OPERATOR = r'\{(\|\||&&)[,][a-zA-Z\| ]*[,]?[\|&]?([,])?([lrudi]|left|right|union|disjoint|intersect)?\}'
564
t_T_REL_OPERATOR = r'\{([a-zA-Z\| ])+\}'
566
t_T_NOT_SELECT = r'!:'
574
t_LOWER_EQUALS = r'<='
576
t_GREATER_EQUALS = r'>='
582
# These are the things that should be ignored.
585
# Read time string and convert it into a date object
586
def t_DATETIME(self, t):
587
r'"\d\d\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])[ T](0[0-9]|1(0-9)|2[0-4]):(0[0-9]|[1-5][0-9]|60):(0[0-9]|[1-5][0-9]|60)"'
588
# t.value = int(t.value)
592
# Read date string and convert it into a date object
594
r'"\d\d\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"'
595
# t.value = int(t.value)
598
# Read time string and convert it into a date object
600
r'"(0[0-9]|1[0-9]|2[0-4]):(0[0-9]|[1-5][0-9]|60):(0[0-9]|[1-5][0-9]|60)"'
601
# t.value = int(t.value)
604
# Read in a float. This rule has to be done before the int rule.
605
def t_FLOAT(self, t):
606
r'-?\d+\.\d*(e-?\d+)?'
607
t.value = float(t.value)
613
t.value = int(t.value)
615
# Read in a list of maps.
618
t.value = list(t.value)
622
# def t_comment(self, t):
626
# Track line numbers.
627
def t_newline(self, t):
629
t.lineno += len(t.value)
632
r'[a-zA-Z_][a-zA-Z_0-9]*'
633
self.temporal_symbol(t)
637
def temporal_symbol(self, t):
638
# Check for reserved words
639
if t.value in TemporalAlgebraLexer.time_functions.keys():
640
t.type = TemporalAlgebraLexer.time_functions.get(t.value)
641
elif t.value in TemporalAlgebraLexer.datetime_functions.keys():
642
t.type = TemporalAlgebraLexer.datetime_functions.get(t.value)
643
elif t.value in TemporalAlgebraLexer.conditional_functions.keys():
644
t.type = TemporalAlgebraLexer.conditional_functions.get(t.value)
650
def t_error(self, t):
651
raise SyntaxError("syntax error on line %d near '%s'" %
655
def build(self,**kwargs):
656
self.lexer = lex.lex(module=self, optimize=False, debug=False, **kwargs)
662
self.lexer.input(data)
664
tok = self.lexer.token()
668
###############################################################################
670
class GlobalTemporalVar(object):
671
""" This class handles global temporal variable conditional expressions,
672
like start_doy() == 3.
673
The three parts of the statement are stored separately in
674
tfunc (START_DOY), compop (==) and value (3).
675
But also boolean values, time differences and relation operators for comparison in
676
if-statements can be stored in this class.
683
self.relationop = None
688
if self.tfunc != None and self.compop != None and self.value != None:
690
elif self.boolean != None:
692
elif self.relationop != None and self.topology != []:
694
elif self.td != None:
697
def get_type_value(self):
698
typename = self.get_type()
700
if typename == "global":
701
valuelist = [self.tfunc, self.compop, self.value]
702
elif typename == "operator":
703
valuelist.append(self.topology)
704
valuelist.append(self.relationop)
705
elif typename == "boolean":
706
valuelist = self.boolean
707
elif typename == "timediff":
708
valuelist.append(self.td)
713
return str(self.tfunc) + str(self.compop) + str(self.value)
715
###############################################################################
717
class FatalError(Exception):
718
def __init__(self, msg):
724
###############################################################################
726
class TemporalAlgebraParser(object):
727
"""The temporal algebra class"""
729
# Get the tokens from the lexer class
730
tokens = TemporalAlgebraLexer.tokens
732
# Setting equal precedence level for select and hash operations.
734
('left', 'T_SELECT_OPERATOR', 'T_SELECT', 'T_NOT_SELECT', 'T_HASH_OPERATOR', 'HASH'), # 1
735
('left', 'AND', 'OR', 'T_COMP_OPERATOR'), #2
738
def __init__(self, pid=None, run = True, debug = False, spatial = False,
739
null = False, register_null = False, nprocs = 1):
743
# Intermediate vector map names
746
self.spatial = spatial
748
self.mapset = get_current_mapset()
749
self.temporaltype = None
750
self.msgr = get_tgis_message_interface()
751
self.dbif = SQLDatabaseInterfaceConnection()
753
self.register_null = register_null
754
self.removable_maps = {}
755
self.m_mremove = pymod.Module('g.remove')
756
self.m_copy = pymod.Module('g.copy')
758
self.use_granularity = False
761
if self.dbif.connected:
764
def setup_common_granularity(self, expression, stdstype = 'strds', lexer = None):
765
"""Configure the temporal algebra to use the common granularity of all
766
space time datasets in the expression to generate the map lists.
768
This function will analyze the expression to detect space time datasets
769
and computes the common granularity from all granularities.
771
This granularity is then be used to generate the map lists. Hence, all
772
maps from all STDS will have equidistant temporal extents. The only meaningful
773
temporal relation is "equal".
775
:param expression: The algebra expression to analyze
777
:param lexer: The temporal algebra lexer (select, raster, voxel, vector) that should be used to
778
parse the expression, default is TemporalAlgebraLexer
780
:return: True if successful, False otherwise
784
# Split the expression to ignore the left part
785
expressions = expression.split("=")[1:]
786
expression = " ".join(expressions)
788
# Check if spatio-temporal operators are present in the expression
789
if "{" in expression or "}" in expression:
790
self.msgr.error(_("Spatio temporal operators are not supported in granularity algebra mode"))
795
l = TemporalAlgebraLexer()
797
l.lexer.input(expression)
804
tok = l.lexer.token()
808
tokens.append(tok.type)
811
if tokens[count - 2] == "MAP" or tokens[count - 2] == "TMAP":
814
if tok.type == "NAME" and ignore == False:
815
name_list.append(tok.value)
820
dbif, connected = init_dbif(self.dbif)
822
for name in name_list:
823
stds = open_old_stds(name, stdstype, dbif)
824
# We need valid temporal topology
825
if stds.check_temporal_topology() is False:
826
self.msgr.error(_("All input space time datasets must have a valid temporal topology."))
829
grans.append(stds.get_granularity())
830
ttypes[stds.get_temporal_type()] = stds.get_temporal_type()
832
# Only one temporal type is allowed
834
self.msgr.error(_("All input space time datasets must have the same temporal type."))
837
# Compute the common granularity
838
if "absolute" in ttypes.keys():
839
self.granularity = compute_common_absolute_time_granularity(grans)
841
self.granularity = compute_common_relative_time_granularity(grans)
843
self.use_granularity = True
847
def parse(self, expression, stdstype = 'strds', maptype = 'rast', mapclass = RasterDataset,
848
basename = None, overwrite=False):
849
self.lexer = TemporalAlgebraLexer()
851
self.parser = yacc.yacc(module=self, debug=self.debug)
853
self.overwrite = overwrite
855
self.stdstype = stdstype
856
self.maptype = maptype
857
self.mapclass = mapclass
858
self.basename = basename
859
self.expression = expression
860
self.parser.parse(expression)
862
def generate_map_name(self):
863
"""Generate an unique map name and register it in the objects map list
865
The map names are unique between processes. Do not use the
866
same object for map name generation in multiple threads.
873
name = "tmp_map_name_%i_%i"%(pid, self.count)
874
self.names[name] = name
877
def generate_new_map(self, base_map, bool_op = 'and', copy = True, rename = True,
879
"""Generate a new map using the spatio-temporal extent of the base map
881
:param base_map: This map is used to create the new map
882
:param bool_op: The boolean operator specifying the spatial extent
883
operation (intersection, union, disjoint union)
884
:param copy: Specifies if the temporal extent of mapB should be
886
:param rename: Specifies if the generated map get a random name or get
887
the id from the base map.
888
:param remove: Set this True if this map is an intermediate or empty map that should be removed
891
# Generate an intermediate name for the result map list.
892
name = self.generate_map_name()
893
# Check for mapset in given stds input.
894
mapname = name + "@" + self.mapset
895
# Create new map based on the related map list.
896
map_new = base_map.get_new_instance(mapname)
897
# Set initial map extend of new vector map.
898
self.overlay_map_extent(map_new, base_map, bool_op = bool_op, copy = copy)
900
name = base_map.get_id()
903
self.removable_maps[name] = map_new
904
# Make sure to set the uid that is used in several dictionaries
908
def overlay_map_extent(self, mapA, mapB, bool_op = None, temp_op = 'l',
910
"""Compute the spatio-temporal extent of two topological related maps
912
:param mapA: The first map
913
:param mapB: The second maps
914
:param bool_op: The boolean operator specifying the spatial extent
915
operation (intersection, union, disjoint union)
916
:param temp_op: The temporal operator specifying the temporal
917
extent operation (intersection, union, disjoint union, right reference)
918
Left reference is the default temporal extent behaviour.
919
:param copy: Specifies if the temporal extent of mapB should be
921
:return: 0 if there is no overlay
925
map_extent_temporal = mapB.get_temporal_extent()
926
map_extent_spatial = mapB.get_spatial_extent()
927
# Set initial map extend of new vector map.
928
mapA.set_spatial_extent(map_extent_spatial)
929
mapA.set_temporal_extent(map_extent_temporal)
930
if "cmd_list" in dir(mapB):
931
mapA.cmd_list = mapB.cmd_list
932
if "condition_value" in dir(mapB):
933
mapA.condition_value = mapB.condition_value
935
# Calculate spatial extent for different overlay operations.
937
overlay_ext = mapA.spatial_intersection(mapB)
938
if overlay_ext != None:
939
mapA.set_spatial_extent(overlay_ext)
942
elif bool_op in ['or', 'xor']:
943
overlay_ext = mapA.spatial_union(mapB)
944
if overlay_ext != None:
945
mapA.set_spatial_extent(overlay_ext)
948
elif bool_op == 'disor':
949
overlay_ext = mapA.spatial_disjoint_union(mapB)
950
if overlay_ext != None:
951
mapA.set_spatial_extent(overlay_ext)
955
# Calculate temporal extent for different temporal operators.
957
temp_ext = mapA.temporal_intersection(mapB)
959
mapA.set_temporal_extent(temp_ext)
963
temp_ext = mapA.temporal_union(mapB)
965
mapA.set_temporal_extent(temp_ext)
969
temp_ext = mapA.temporal_disjoint_union(mapB)
971
mapA.set_temporal_extent(temp_ext)
975
temp_ext = mapB.get_temporal_extent()
977
mapA.set_temporal_extent(temp_ext)
982
def set_temporal_extent_list(self, maplist, topolist = ["EQUAL"], temporal = 'l' ):
983
""" Change temporal extent of map list based on temporal relations to
984
other map list and given temporal operator.
986
:param maplist: List of map objects for which relations has been build
988
:param topolist: List of strings of temporal relations.
989
:param temporal: The temporal operator specifying the temporal
990
extent operation (intersection, union, disjoint
991
union, right reference, left reference).
993
:return: Map list with specified temporal extent.
997
for map_i in maplist:
998
# Loop over temporal related maps and create overlay modules.
999
tbrelations = map_i.get_temporal_relations()
1000
# Generate an intermediate map for the result map list.
1001
map_new = self.generate_new_map(base_map=map_i, bool_op = 'and',
1002
copy = True, rename = True)
1003
# Combine temporal and spatial extents of intermediate map with related maps.
1004
for topo in topolist:
1005
if topo in tbrelations.keys():
1006
for map_j in (tbrelations[topo]):
1008
# Generate an intermediate map for the result map list.
1009
map_new = self.generate_new_map(base_map=map_i, bool_op = 'and',
1010
copy = True, rename = True)
1011
# Create overlayed map extent.
1012
returncode = self.overlay_map_extent(map_new, map_j, 'and', \
1014
# Stop the loop if no temporal or spatial relationship exist.
1017
# Append map to result map list.
1018
elif returncode == 1:
1019
print(map_new.get_id() + " " + str(map_new.get_temporal_extent_as_tuple()))
1020
print(map_new.condition_value)
1021
# print(map_new.cmd_list)
1022
# resultlist.append(map_new)
1023
resultdict[map_new.get_id()] = map_new
1025
# Create r.mapcalc expression string for the operation.
1026
#cmdstring = self.build_command_string(s_expr_a = map_new,
1028
# operator = function)
1029
# Conditional append of module command.
1030
#map_new.cmd_list = cmdstring
1033
# Append map to result map list.
1034
#if returncode == 1:
1035
# resultlist.append(map_new)
1036
# Get sorted map objects as values from result dictionoary.
1037
resultlist = resultdict.values()
1038
resultlist = sorted(resultlist, key = AbstractDatasetComparisonKeyStartTime)
1042
######################### Temporal functions ##############################
1044
def remove_maps(self):
1045
"""Removes empty or intermediate maps of different type.
1049
map_names["raster"] = []
1050
map_names["raster3d"] = []
1051
map_names["vector"] = []
1053
if self.removable_maps:
1054
for map in self.removable_maps.values():
1055
map_names[map.get_type()].append(map.get_name())
1057
for key in map_names.keys():
1059
self.msgr.message(_("Removing un-needed or empty %s maps"%(key)))
1060
self._remove_maps(map_names[key], key)
1062
def _remove_maps(self, namelist, map_type):
1063
"""Remove maps of specific type
1065
:param namelist: List of map names to be removed
1066
:param map_type: The type of the maps (raster, raster_3d or vector)
1069
chunklist = [namelist[i:i + max] for i in range(0, len(namelist), max)]
1070
for chunk in chunklist:
1071
stringlist = ",".join(chunk)
1074
m = copy.deepcopy(self.m_mremove)
1075
m.inputs["type"].value = map_type
1076
m.inputs["name"].value = stringlist
1077
m.flags["f"].value = True
1081
def check_stds(self, input, clear = False, stds_type = None, check_type=True):
1082
""" Check if input space time dataset exist in database and return its map list.
1084
:param input: Name of space time data set as string or list of maps.
1085
:param clear: Reset the stored conditional values to empty list.
1086
:param check_type: Check the type of the space time dataset to match the global stds type
1087
:param stds_type: The type of the space time dataset to be opened, if not provided
1088
then self.stdstype will be used
1090
:return: List of maps.
1093
if isinstance(input, str):
1094
# Check for mapset in given stds input.
1095
if input.find("@") >= 0:
1098
id_input = input + "@" + self.mapset
1099
# Create empty spacetime dataset.
1101
stds = dataset_factory(stds_type, id_input)
1103
stds = dataset_factory(self.stdstype, id_input)
1104
# Check for occurence of space time dataset.
1105
if stds.is_in_db(dbif=self.dbif) == False:
1106
raise FatalError(_("Space time %s dataset <%s> not found") %
1107
(stds.get_new_map_instance(None).get_type(), id_input))
1109
# Select temporal dataset entry from database.
1110
stds.select(dbif=self.dbif)
1111
if self.use_granularity:
1112
# We create the maplist out of the map array from none-gap objects
1114
map_array = stds.get_registered_maps_as_objects_by_granularity(gran=self.granularity, dbif=self.dbif)
1115
for entry in map_array:
1116
# Ignore gap objects
1117
if entry[0].get_id() is not None:
1118
maplist.append(entry[0])
1120
maplist = stds.get_registered_maps_as_objects(dbif=self.dbif)
1121
# Create map_value as empty list item.
1122
for map_i in maplist:
1123
if "map_value" not in dir(map_i):
1124
map_i.map_value = []
1125
if "condition_value" not in dir(map_i):
1126
map_i.condition_value = []
1127
# Set and check global temporal type variable and map.
1128
if map_i.is_time_absolute() and self.temporaltype == None:
1129
self.temporaltype = 'absolute'
1130
elif map_i.is_time_relative() and self.temporaltype == None:
1131
self.temporaltype = 'relative'
1132
elif map_i.is_time_absolute() and self.temporaltype == 'relative':
1133
self.msgr.fatal(_("Wrong temporal type of space time dataset <%s> \
1134
<%s> time is required") %
1135
(id_input, self.temporaltype))
1136
elif map_i.is_time_relative() and self.temporaltype == 'absolute':
1137
self.msgr.fatal(_("Wrong temporal type of space time dataset <%s> \
1138
<%s> time is required") %
1139
(id_input, self.temporaltype))
1140
elif isinstance(input, self.mapclass):
1141
# Check if the input is a single map and return it as list with one entry.
1144
elif isinstance(input, list):
1146
# Create map_value as empty list item.
1147
for map_i in maplist:
1148
if "map_value" not in dir(map_i):
1149
map_i.map_value = []
1151
map_i.map_value = []
1152
if "condition_value" not in dir(map_i):
1153
map_i.condition_value = []
1155
map_i.condition_value = []
1157
self.msgr.fatal(_("Wrong type of input " + str(input)))
1159
# We generate a unique map id that will be used
1160
# in the topology analysis, since the maplist can
1161
# contain maps with equal map ids
1163
map.uid = self.generate_map_name()
1165
print map.get_name(), map.uid, map.get_temporal_extent_as_tuple()
1169
def get_temporal_topo_list(self, maplistA, maplistB = None, topolist = ["EQUAL"],
1170
assign_val = False, count_map = False, compare_bool = False,
1171
compop = None, aggregate = None):
1172
"""Build temporal topology for two space time data sets, copy map objects
1173
for given relation into map list.
1175
:param maplistA: List of maps.
1176
:param maplistB: List of maps.
1177
:param topolist: List of strings of temporal relations.
1178
:param assign_val: Boolean for assigning a boolean map value based on
1179
the map_values from the compared map list by
1180
topological relationships.
1181
:param count_map: Boolean if the number of topological related maps
1183
:param compare_bool: Boolean for comparing boolean map values based on
1184
related map list and compariosn operator.
1185
:param compop: Comparison operator, && or ||.
1186
:param aggregate: Aggregation operator for relation map list, & or |.
1188
:return: List of maps from maplistA that fulfil the topological relationships
1189
to maplistB specified in topolist.
1191
.. code-block:: python
1193
# Example with two lists of maps
1194
>>> import grass.temporal as tgis
1196
>>> l = tgis.TemporalAlgebraParser()
1197
>>> # Create two list of maps with equal time stamps
1200
>>> for i in range(10):
1201
... idA = "a%i@B"%(i)
1202
... mapA = tgis.RasterDataset(idA)
1204
... idB = "b%i@B"%(i)
1205
... mapB = tgis.RasterDataset(idB)
1207
... check = mapA.set_relative_time(i, i + 1, "months")
1208
... check = mapB.set_relative_time(i, i + 1, "months")
1209
... mapsA.append(mapA)
1210
... mapsB.append(mapB)
1211
>>> resultlist = l.get_temporal_topo_list(mapsA, mapsB, ['EQUAL'])
1212
>>> for map in resultlist:
1213
... if map.get_equal():
1214
... relations = map.get_equal()
1215
... print "Map %s has equal relation to map %s"%(map.get_name(),
1216
... relations[0].get_name())
1217
Map a0 has equal relation to map b0
1218
Map a1 has equal relation to map b1
1219
Map a2 has equal relation to map b2
1220
Map a3 has equal relation to map b3
1221
Map a4 has equal relation to map b4
1222
Map a5 has equal relation to map b5
1223
Map a6 has equal relation to map b6
1224
Map a7 has equal relation to map b7
1225
Map a8 has equal relation to map b8
1226
Map a9 has equal relation to map b9
1227
>>> resultlist = l.get_temporal_topo_list(mapsA, mapsB, ['DURING'])
1228
>>> print(resultlist)
1230
>>> # Create two list of maps with equal time stamps
1233
>>> for i in range(10):
1234
... idA = "a%i@B"%(i)
1235
... mapA = tgis.RasterDataset(idA)
1237
... idB = "b%i@B"%(i)
1238
... mapB = tgis.RasterDataset(idB)
1240
... check = mapA.set_relative_time(i, i + 1, "months")
1241
... check = mapB.set_relative_time(i, i + 2, "months")
1242
... mapsA.append(mapA)
1243
... mapsB.append(mapB)
1244
>>> resultlist = l.get_temporal_topo_list(mapsA, mapsB, ['starts','during'])
1245
>>> for map in resultlist:
1246
... if map.get_starts():
1247
... relations = map.get_starts()
1248
... print "Map %s has start relation to map %s"%(map.get_name(),
1249
... relations[0].get_name())
1250
Map a0 has start relation to map b0
1251
Map a1 has start relation to map b1
1252
Map a2 has start relation to map b2
1253
Map a3 has start relation to map b3
1254
Map a4 has start relation to map b4
1255
Map a5 has start relation to map b5
1256
Map a6 has start relation to map b6
1257
Map a7 has start relation to map b7
1258
Map a8 has start relation to map b8
1259
Map a9 has start relation to map b9
1260
>>> for map in resultlist:
1261
... if map.get_during():
1262
... relations = map.get_during()
1263
... print "Map %s has during relation to map %s"%(map.get_name(),
1264
... relations[0].get_name())
1265
Map a0 has during relation to map b0
1266
Map a1 has during relation to map b0
1267
Map a2 has during relation to map b1
1268
Map a3 has during relation to map b2
1269
Map a4 has during relation to map b3
1270
Map a5 has during relation to map b4
1271
Map a6 has during relation to map b5
1272
Map a7 has during relation to map b6
1273
Map a8 has during relation to map b7
1274
Map a9 has during relation to map b8
1275
>>> # Create two list of maps with equal time stamps and map_value method.
1278
>>> for i in range(10):
1279
... idA = "a%i@B"%(i)
1280
... mapA = tgis.RasterDataset(idA)
1282
... idB = "b%i@B"%(i)
1283
... mapB = tgis.RasterDataset(idB)
1285
... check = mapA.set_relative_time(i, i + 1, "months")
1286
... check = mapB.set_relative_time(i, i + 1, "months")
1287
... mapB.map_value = True
1288
... mapsA.append(mapA)
1289
... mapsB.append(mapB)
1290
>>> # Create two list of maps with equal time stamps
1293
>>> for i in range(10):
1294
... idA = "a%i@B"%(i)
1295
... mapA = tgis.RasterDataset(idA)
1297
... mapA.map_value = True
1298
... idB = "b%i@B"%(i)
1299
... mapB = tgis.RasterDataset(idB)
1301
... mapB.map_value = False
1302
... check = mapA.set_absolute_time(datetime(2000,1,i+1),
1303
... datetime(2000,1,i + 2))
1304
... check = mapB.set_absolute_time(datetime(2000,1,i+6),
1305
... datetime(2000,1,i + 7))
1306
... mapsA.append(mapA)
1307
... mapsB.append(mapB)
1308
>>> resultlist = l.get_temporal_topo_list(mapsA, mapsB)
1309
>>> for map in resultlist:
1310
... print(map.get_id())
1316
>>> resultlist = l.get_temporal_topo_list(mapsA, mapsB, ['during'])
1317
>>> for map in resultlist:
1318
... print(map.get_id())
1321
topologylist = ["EQUAL", "FOLLOWS", "PRECEDES", "OVERLAPS", "OVERLAPPED", \
1322
"DURING", "STARTS", "FINISHES", "CONTAINS", "STARTED", \
1324
complementdict = {"EQUAL": "EQUAL", "FOLLOWS" : "PRECEDES",
1325
"PRECEDES" : "FOLLOWS", "OVERLAPS" : "OVERLAPPED",
1326
"OVERLAPPED" : "OVERLAPS", "DURING" : "CONTAINS",
1327
"CONTAINS" : "DURING", "STARTS" : "STARTED",
1328
"STARTED" : "STARTS", "FINISHES" : "FINISHED",
1329
"FINISHED" : "FINISHES"}
1331
# Check if given temporal relation are valid.
1332
for topo in topolist:
1333
if topo.upper() not in topologylist:
1334
raise SyntaxError("Unpermitted temporal relation name '" + topo + "'")
1336
# Create temporal topology for maplistA to maplistB.
1337
tb = SpatioTemporalTopologyBuilder()
1338
# Dictionary with different spatial variables used for topology builder.
1339
spatialdict = {'strds' : '2D', 'stvds' : '2D', 'str3ds' : '3D'}
1340
# Build spatial temporal topology
1342
tb.build(maplistA, maplistB, spatial = spatialdict[self.stdstype])
1344
tb.build(maplistA, maplistB)
1345
# Iterate through maps in maplistA and search for relationships given
1347
for map_i in maplistA:
1348
tbrelations = map_i.get_temporal_relations()
1350
self.assign_bool_value(map_i, tbrelations, topolist)
1352
self.compare_bool_value(map_i, tbrelations, compop, aggregate, topolist)
1353
for topo in topolist:
1354
if topo.upper() in tbrelations.keys():
1356
relationmaplist = tbrelations[topo.upper()]
1357
gvar = GlobalTemporalVar()
1358
gvar.td = len(relationmaplist)
1359
if "map_value" in dir(map_i):
1360
map_i.map_value.append(gvar)
1362
map_i.map_value = gvar
1363
# Use unique identifier, since map names may be equal
1364
resultdict[map_i.uid] = map_i
1365
resultlist = resultdict.values()
1367
# Sort list of maps chronological.
1368
resultlist = sorted(resultlist, key = AbstractDatasetComparisonKeyStartTime)
1372
def assign_bool_value(self, map_i, tbrelations, topolist = ["EQUAL"]):
1373
""" Function to assign boolean map value based on the map_values from the
1374
compared map list by topological relationships.
1376
:param map_i: Map object with temporal extent.
1377
:param tbrelations: List of temporal relation to map_i.
1378
:param topolist: List of strings for given temporal relations.
1380
:return: Map object with conditional value that has been assigned by
1381
relation maps that fulfil the topological relationships to
1382
maplistB specified in topolist.
1384
condition_value_list = []
1385
for topo in topolist:
1386
if topo.upper() in tbrelations.keys():
1387
#relationmaplist = tbrelations[complementdict[topo.upper()]]
1388
relationmaplist = tbrelations[topo.upper()]
1389
for relationmap in relationmaplist:
1390
for boolean in relationmap.condition_value:
1391
if isinstance(boolean, bool):
1392
condition_value_list.append(boolean)
1394
print(str(relationmap.get_temporal_extent_as_tuple()) + str(boolean))
1395
if all(condition_value_list):
1399
map_i.condition_value = [resultbool]
1403
def compare_bool_value(self, map_i, tbrelations, compop, aggregate, topolist = ["EQUAL"]):
1404
""" Function to evaluate two map lists with boolean values by boolean
1405
comparison operator.
1407
:param map_i: Map object with temporal extent.
1408
:param tbrelations: List of temporal relation to map_i.
1409
:param topolist: List of strings for given temporal relations.
1410
:param compop: Comparison operator, && or ||.
1411
:param aggregate: Aggregation operator for relation map list, & or |.
1413
:return: Map object with conditional value that has been evaluated by
1414
comparison operators.
1416
# Build conditional list with elements from related maps and given relation operator.
1417
leftbool = map_i.condition_value[0]
1418
condition_value_list = [leftbool]
1420
for topo in topolist:
1421
if topo.upper() in tbrelations.keys():
1422
relationmaplist = tbrelations[topo.upper()]
1424
condition_value_list.append(compop[0])
1425
condition_value_list.append('(')
1426
for relationmap in relationmaplist:
1427
for boolean in relationmap.condition_value:
1428
if isinstance(boolean, bool):
1430
condition_value_list.append(aggregate)
1431
condition_value_list.append(boolean)
1434
condition_value_list.append(')')
1435
# Convert conditional list to concatenated string and evaluate booleans.
1436
condition_value_str = ''.join(map(str, condition_value_list))
1438
print(condition_value_str)
1439
resultbool = eval(condition_value_str)
1442
# Add boolean value to result list.
1443
map_i.condition_value = [resultbool]
1447
def eval_toperator(self, operator, optype = 'relation'):
1448
"""This function evaluates a string containing temporal operations.
1450
:param operator: String of temporal operations, e.g. {!=,equal|during,l}.
1451
:param optype: String to define operator type.
1453
:return :List of temporal relations (equal, during), the given function
1454
(!:) and the interval/instances (l).
1456
.. code-block:: python
1458
>>> import grass.temporal as tgis
1460
>>> p = tgis.TemporalOperatorParser()
1461
>>> operator = "{+, during}"
1462
>>> p.parse(operator, optype = 'raster')
1463
>>> print(p.relations, p.temporal, p.function)
1464
(['during'], 'l', '+')
1467
p = TemporalOperatorParser()
1468
p.parse(operator, optype)
1469
p.relations = [rel.upper() for rel in p.relations]
1471
return(p.relations, p.temporal, p.function, p.aggregate)
1473
def perform_temporal_selection(self, maplistA, maplistB, topolist = ["EQUAL"],
1474
inverse = False, assign_val = False):
1475
"""This function performs temporal selection operation.
1477
:param maplistA: List of maps representing the left side of a temporal
1479
:param maplistB: List of maps representing the right side of a temporal
1481
:param topolist: List of strings of temporal relations.
1482
:param inverse: Boolean value that specifies if the selection should be
1484
:param assign_val: Boolean for assigning a boolean map value based on
1485
the map_values from the compared map list by
1486
topological relationships.
1488
:return: List of selected maps from maplistA.
1490
.. code-block:: python
1492
>>> import grass.temporal as tgis
1494
>>> l = tgis.TemporalAlgebraParser()
1495
>>> # Example with two lists of maps
1496
>>> # Create two list of maps with equal time stamps
1499
>>> for i in range(10):
1500
... idA = "a%i@B"%(i)
1501
... mapA = tgis.RasterDataset(idA)
1503
... idB = "b%i@B"%(i)
1504
... mapB = tgis.RasterDataset(idB)
1506
... check = mapA.set_relative_time(i, i + 1, "months")
1507
... check = mapB.set_relative_time(i + 5, i + 6, "months")
1508
... mapsA.append(mapA)
1509
... mapsB.append(mapB)
1510
>>> resultlist = l.perform_temporal_selection(mapsA, mapsB, ['EQUAL'],
1512
>>> for map in resultlist:
1513
... if map.get_equal():
1514
... relations = map.get_equal()
1515
... print "Map %s has equal relation to map %s"%(map.get_name(),
1516
... relations[0].get_name())
1517
Map a5 has equal relation to map b0
1518
Map a6 has equal relation to map b1
1519
Map a7 has equal relation to map b2
1520
Map a8 has equal relation to map b3
1521
Map a9 has equal relation to map b4
1522
>>> resultlist = l.perform_temporal_selection(mapsA, mapsB, ['EQUAL'],
1524
>>> for map in resultlist:
1525
... if not map.get_equal():
1526
... print "Map %s has no equal relation to mapset mapsB"%(map.get_name())
1527
Map a0 has no equal relation to mapset mapsB
1528
Map a1 has no equal relation to mapset mapsB
1529
Map a2 has no equal relation to mapset mapsB
1530
Map a3 has no equal relation to mapset mapsB
1531
Map a4 has no equal relation to mapset mapsB
1535
topolist = self.get_temporal_topo_list(maplistA, maplistB, topolist,
1536
assign_val = assign_val)
1537
resultlist = topolist
1540
topolist = self.get_temporal_topo_list(maplistA, maplistB, topolist,
1541
assign_val = assign_val)
1543
for map_i in maplistA:
1544
if map_i not in topolist:
1545
resultlist.append(map_i)
1547
# if "condition_value" in dir(map_i):
1548
# map_i.condition_value.append(False)
1550
# Sort list of maps chronological.
1551
resultlist = sorted(resultlist, key = AbstractDatasetComparisonKeyStartTime)
1554
def set_granularity(self, maplistA, maplistB, toperator = 'l', topolist = ["EQUAL"]):
1555
"""This function sets the temporal extends of a list of maps based on
1558
:param maplistB: List of maps.
1559
:param maplistB: List of maps.
1560
:param toperator: String containing the temporal operator: l, r, d, i, u.
1561
:param topolist: List of topological relations.
1563
:return: List of maps with the new temporal extends.
1565
.. code-block:: python
1567
>>> import grass.temporal as tgis
1569
>>> p = tgis.TemporalAlgebraParser()
1570
>>> # Create two list of maps with equal time stamps
1573
>>> for i in range(10):
1574
... idA = "a%i@B"%(i)
1575
... mapA = tgis.RasterDataset(idA)
1577
... idB = "b%i@B"%(i)
1578
... mapB = tgis.RasterDataset(idB)
1580
... check = mapA.set_relative_time(i, i + 1, "months")
1581
... check = mapB.set_relative_time(i*2, i*2 + 2, "months")
1582
... mapsA.append(mapA)
1583
... mapsB.append(mapB)
1584
>>> resultlist = p.set_granularity(mapsA, mapsB, toperator = "u", topolist = ["during"])
1585
>>> for map in resultlist:
1586
... start,end,unit = map.get_relative_time()
1587
... print(map.get_id() + ' - start: ' + str(start) + ' end: ' + str(end))
1588
a1@B - start: 0 end: 2
1589
a0@B - start: 0 end: 2
1590
a3@B - start: 2 end: 4
1591
a2@B - start: 2 end: 4
1592
a5@B - start: 4 end: 6
1593
a4@B - start: 4 end: 6
1594
a7@B - start: 6 end: 8
1595
a6@B - start: 6 end: 8
1596
a9@B - start: 8 end: 10
1597
a8@B - start: 8 end: 10
1600
topologylist = ["EQUAL", "FOLLOWS", "PRECEDES", "OVERLAPS", "OVERLAPPED", \
1601
"DURING", "STARTS", "FINISHES", "CONTAINS", "STARTED", \
1604
for topo in topolist:
1605
if topo.upper() not in topologylist:
1606
raise SyntaxError("Unpermitted temporal relation name '" + topo + "'")
1608
# Create temporal topology for maplistA to maplistB.
1609
tb = SpatioTemporalTopologyBuilder()
1610
# Dictionary with different spatial variables used for topology builder.
1611
spatialdict = {'strds' : '2D', 'stvds' : '2D', 'str3ds' : '3D'}
1612
# Build spatial temporal topology for maplistB to maplistB.
1614
tb.build(maplistA, maplistB, spatial = spatialdict[self.stdstype])
1616
tb.build(maplistA, maplistB)
1619
# Iterate through maps in maplistA and search for relationships given
1621
for map_i in maplistA:
1622
tbrelations = map_i.get_temporal_relations()
1623
map_extent = map_i.get_temporal_extent()
1624
map_start = map_extent.get_start_time()
1625
map_end = map_extent.get_end_time()
1627
for topo in topolist:
1628
if topo.upper() in tbrelations.keys():
1629
relationmaplist = tbrelations[topo.upper()]
1630
for relationmap in relationmaplist:
1632
if toperator == "i":
1633
newextent = map_i.temporal_intersection(relationmap)
1634
elif toperator == "u":
1635
newextent = map_i.temporal_union(relationmap)
1636
elif toperator == "d":
1637
newextent = map_i.temporal_disjoint_union(relationmap)
1638
elif toperator == "l":
1639
newextent = map_i.get_temporal_extent()
1640
elif toperator == "r":
1641
newextent = relationmap.get_temporal_extent()
1642
if newextent != None:
1643
start = newextent.get_start_time()
1644
end = newextent.get_end_time()
1645
#print(map_i.get_id() + ' - start: ' + str(start) + ' end: ' + str(end))
1646
# Track changes in temporal extents of maps.
1647
if map_start != start or map_end != end :
1649
if map_i.is_time_absolute():
1650
map_i.set_absolute_time(start, end)
1652
relunit = map_i.get_relative_time_unit()
1653
map_i.set_relative_time(int(start), int(end), relunit)
1654
resultdict[map_i.get_id()] = map_i
1657
print('Topologic relation: ' + topo.upper() + ' not found.')
1658
resultdict[map_i.get_id()] = map_i
1659
if unchanged == True:
1661
print('Leave temporal extend of result map: ' + map_i.get_map_id() + ' unchanged.')
1663
resultlist = resultdict.values()
1664
# Sort list of maps chronological.
1665
resultlist = sorted(resultlist, key = AbstractDatasetComparisonKeyStartTime)
1666
# Get relations to maplistB per map in A.
1667
# Loop over all relations from list
1668
# temporal extent = map.temporal_intersection(map)
1669
# if temporal extend is None = delete map.
1673
def get_temporal_func_dict(self, map):
1674
""" This function creates a dictionary containing temporal functions for a
1675
map dataset with time stamp.
1677
:param map: Map object with time stamps.
1679
:return: Dictionary with temporal functions for given input map.
1681
.. code-block:: python
1683
>>> import grass.temporal as tgis
1686
>>> l = tgis.TemporalAlgebraParser()
1687
>>> # Example with one list of maps
1688
>>> # Create one list of maps with equal time stamps
1689
>>> for i in range(1):
1690
... idA = "a%i@B"%(i)
1691
... mapA = tgis.RasterDataset(idA)
1693
... check = mapA.set_absolute_time(datetime.datetime(2000,1,1),
1694
... datetime.datetime(2000,10,1))
1695
... tfuncdict = l.get_temporal_func_dict(mapA)
1696
>>> print(tfuncdict["START_YEAR"])
1698
>>> print(tfuncdict["START_TIME"])
1700
>>> print(tfuncdict["START_DATE"])
1702
>>> print(tfuncdict["START_DATETIME"])
1706
tvardict = {"START_DOY" : None, "START_DOW" : None, "START_YEAR" : None,
1707
"START_MONTH" : None, "START_WEEK" : None, "START_DAY" : None,
1708
"START_HOUR" : None, "START_MINUTE" : None, "START_SECOND" : None,
1709
"END_DOY" : None, "END_DOW" : None, "END_YEAR" : None,
1710
"END_MONTH" : None, "END_WEEK" : None, "END_DAY" : None,
1711
"END_HOUR" : None, "END_MINUTE" : None, "END_SECOND" : None,
1712
"START_DATE" : None, "START_DATETIME" : None, "START_TIME" : None,
1713
"END_DATE" : None, "END_DATETIME" : None, "END_TIME" : None}
1715
# Compute temporal function only for maps with absolute time reference.
1716
if map.is_time_absolute:
1717
# Get datetime of map.
1718
start, end = map.get_absolute_time()
1719
# Compute DOY via time deltas.
1720
yearstart = datetime(start.year, 1, 1)
1721
yearend = datetime(end.year, 1, 1)
1722
deltastart = start - yearstart
1723
deltaend = end - yearend
1725
# Evaluate datetime objects and fill in into dict.
1726
tvardict["START_DOY"] = deltastart.days + 1
1727
tvardict["START_DOW"] = start.isoweekday()
1728
tvardict["START_YEAR"] = start.year
1729
tvardict["START_MONTH"] = start.month
1730
tvardict["START_WEEK"] = start.isocalendar()[1]
1731
tvardict["START_DAY"] = start.day
1732
tvardict["START_HOUR"] = start.hour
1733
tvardict["START_MINUTE"] = start.minute
1734
tvardict["START_SECOND"] = start.second
1735
tvardict["END_DOY"] = deltaend.days + 1
1736
tvardict["END_DOW"] = end.isoweekday()
1737
tvardict["END_YEAR"] = end.year
1738
tvardict["END_MONTH"] = end.month
1739
tvardict["END_WEEK"] = end.isocalendar()[1]
1740
tvardict["END_DAY"] = end.day
1741
tvardict["END_HOUR"] = end.hour
1742
tvardict["END_MINUTE"] = end.minute
1743
tvardict["END_SECOND"] = end.second
1744
tvardict["START_DATE"] = start.date()
1745
tvardict["START_DATETIME"] = start
1746
tvardict["START_TIME"] = start.time()
1747
tvardict["END_DATE"] = end.date()
1748
tvardict["END_DATETIME"] = end
1749
tvardict["END_TIME"] = end.time()
1751
if not map.is_time_absolute:
1752
tvardict["START_DATE"] = start.date()
1753
tvardict["START_DATETIME"] = start
1754
tvardict["START_TIME"] = start.time()
1755
tvardict["END_DATE"] = end.date()
1756
tvardict["END_DATETIME"] = end
1757
tvardict["END_TIME"] = end.time()
1758
#core.fatal(_("The temporal functions for map <%s> only supported for absolute"\
1759
# "time." % (str(map.get_id()))))
1762
def eval_datetime_str(self, tfuncval, comp, value):
1763
# Evaluate date object comparison expression.
1765
boolname = eval(str(tfuncval < value))
1767
boolname = eval(str(tfuncval > value))
1769
boolname = eval(str(tfuncval == value))
1771
boolname = eval(str(tfuncval <= value))
1773
boolname = eval(str(tfuncval >= value))
1775
boolname = eval(str(tfuncval != value))
1779
def eval_global_var(self, gvar, maplist):
1780
""" This function evaluates a global variable expression for a map list.
1781
For example: start_day() > 5 , end_month() == 2.
1783
:param gvar: Object of type GlobalTemporalVar containing temporal.
1784
:param maplist: List of map objects.
1786
:return: List of maps from maplist with added conditional boolean values.
1789
# Loop over maps of input map list.
1790
for map_i in maplist:
1791
# Get dictionary with temporal variables for the map.
1792
tfuncdict = self.get_temporal_func_dict(map_i)
1793
# Get value from global variable.
1795
# Get comparison operator from global variable, like <, >, <=, >=, ==, !=
1796
comp_op = gvar.compop
1797
# Get temporal function name for global variable.
1798
tfunc = gvar.tfunc.upper()
1799
# Get value for function name from dictionary.
1800
tfuncval = tfuncdict[tfunc]
1801
# Check if value has to be transferred to datetime object for comparison.
1802
if tfunc in ["START_DATE", "END_DATE"]:
1803
timeobj = datetime.strptime(value.replace("\"",""), '%Y-%m-%d')
1804
value = timeobj.date()
1805
boolname = self.eval_datetime_str(tfuncval, comp_op, value)
1806
elif tfunc in ["START_TIME", "END_TIME"]:
1807
timeobj = datetime.strptime(value.replace("\"",""), '%H:%M:%S')
1808
value = timeobj.time()
1809
boolname = self.eval_datetime_str(tfuncval, comp_op, value)
1810
elif tfunc in ["START_DATETIME", "END_DATETIME"]:
1811
timeobj = datetime.strptime(value.replace("\"",""), '%Y-%m-%d %H:%M:%S')
1813
boolname = self.eval_datetime_str(tfuncval, comp_op, value)
1815
boolname = eval(str(tfuncval) + comp_op + str(value))
1816
# Add conditional boolean value to the map.
1817
if "condition_value" in dir(map_i):
1818
map_i.condition_value.append(boolname)
1820
map_i.condition_value = boolname
1823
def eval_map_list(self, maplist ,thenlist, topolist = ["EQUAL"]):
1824
""" This function transfers boolean values from temporal expression
1825
from one map list to another by their topology. These boolean
1826
values are added to the maps as condition_value.
1828
:param maplist: List of map objects containing boolean map values.
1829
:param thenlist: List of map objects where the boolean values
1832
:return: List of maps from thenlist with added conditional boolean values.
1834
# Get topology of then statement map list in relation to the other maplist
1835
# and assign boolean values of the maplist to the thenlist.
1836
containlist = self.perform_temporal_selection(thenlist, maplist,
1838
topolist = topolist)
1839
# Inverse selection of maps from thenlist and assigning False values.
1840
#excludelist = self.perform_temporal_selection(thenlist, maplist,
1841
# assign_val = True,
1843
# topolist = topolist)
1844
# Combining the selection and inverse selection list.
1845
resultlist = containlist# + excludelist
1849
def build_condition_list(self, tvarexpr, thenlist, topolist = ["EQUAL"]):
1850
""" This function evaluates temporal variable expressions of a conditional
1851
expression in two steps.
1852
At first it combines stepwise the single conditions by their relations with LALR.
1853
In this prossess sub condition map lists will be created which will include
1854
information of the underlying single conditions. Important: The temporal
1855
relations between conditions are evaluated by implicit aggregation.
1856
In the second step the aggregated condition map list will be compared with the
1857
map list of conclusion statements by the given temporal relation.
1859
The result is writen as 'condition_value' attribute to the resulting map objects.
1860
These attribute consists of boolean expressions and operators which can be
1861
evaluated with the eval_condition_list function.
1862
[True, '||', False, '&&', True]
1864
For example: td(A) == 1 && start_day() > 5 --> [True || False]
1865
(for one map.condition_value in a then map list)
1867
:param tvarexpr: List of GlobalTemporalVar objects and map lists.
1868
The list is constructed by the TemporalAlgebraParser
1869
in order of expression evaluation in the parser.
1871
:param thenlist: Map list object of the conclusion statement.
1872
It will be compared and evaluated by the conditions.
1874
:param topolist: List of temporal relations between the conditions and the
1877
:return: Map list with conditional values for all temporal expressions.
1881
# Evaluate the temporal variable expression and compute the temporal combination
1884
# Check if the input expression is a valid single global variable.
1885
if isinstance(tvarexpr, GlobalTemporalVar) and tvarexpr.get_type() == "global" :
1886
# Use method eval_global_var to evaluate expression.
1887
resultlist = self.eval_global_var(tvarexpr, thenlist)
1888
# Check if a given list is a list of maps.
1889
elif all([issubclass(type(ele), AbstractMapDataset) for ele in tvarexpr]):
1890
# Use method eval_map_list to evaluate map_list in comparison to thenlist.
1891
resultlist = self.eval_map_list(tvarexpr, thenlist, topolist)
1892
elif len(tvarexpr) % 2 != 0:
1893
# Define variables for map list comparisons.
1898
#self.msgr.fatal("Condition list is not complete. Elements missing")
1899
for iter in range(len(tvarexpr)):
1900
expr = tvarexpr[iter]
1901
operator = tvarexpr[iter +1]
1902
relexpr = tvarexpr[iter +2]
1903
if all([issubclass(type(ele), list) for ele in [expr, relexpr]]):
1904
resultlist = self.get_temporal_topo_list(expr, relexpr)
1905
# Loop through the list, search for map lists or global variables.
1906
for expr in tvarexpr:
1907
if isinstance(expr, list):
1908
if all([issubclass(type(ele), AbstractMapDataset) for ele in expr]):
1910
# Use method eval_map_list to evaluate map_list
1911
resultlist = self.eval_map_list(expr, thenlist, topolist)
1913
# Recursive function call to look into nested list elements.
1914
self.build_condition_list(expr, thenlist)
1916
elif isinstance(expr, GlobalTemporalVar):
1917
# Use according functions for different global variable types.
1918
if expr.get_type() == "operator":
1919
if all(["condition_value" in dir(map_i) for map_i in thenlist]):
1920
# Add operator string to the condition list.
1921
[map_i.condition_value.extend(expr.get_type_value()) for map_i in thenlist]
1922
if expr.get_type() == "global":
1923
# Use method eval_global_var to evaluate expression.
1924
resultlist = self.eval_global_var(expr, thenlist)
1926
# Sort resulting list of maps chronological.
1927
resultlist = sorted(resultlist, key = AbstractDatasetComparisonKeyStartTime)
1931
def eval_condition_list(self, maplist, inverse = False):
1932
""" This function evaluates conditional values of a map list.
1933
A recursive function is used to evaluate comparison statements
1934
from left to right in the given conditional list.
1938
- [True, '||', False, '&&', True] -> True
1939
- [True, '||', False, '&&', False] -> False
1940
- [True, '&&', False, '&&', True] -> False
1941
- [False, '||', True, '||', False] -> True
1942
- [False, '&&', True, '&&', True] -> False
1943
- [True, '&&', True, '&&', True] -> True
1944
- [True, '&&', True] -> True
1945
- [True, '&&', False] -> False
1946
- [False, '||', True] -> True
1948
:param tvarexpr: List of GlobalTemporalVar objects and map lists.
1949
The list is constructed by the TemporalAlgebraParser
1950
in order of expression evaluation in the parser.
1952
:return: Map list with conditional values for all temporal expressions.
1954
def recurse_compare(conditionlist):
1955
for ele in conditionlist:
1957
ele_index = conditionlist.index(ele)
1958
topolist = conditionlist.pop(ele_index -1)
1959
right = conditionlist.pop(ele_index)
1960
left = conditionlist.pop(ele_index - 2)
1961
if any([left, right]):
1965
conditionlist[ele_index - 2] = result
1966
recurse_compare(conditionlist)
1968
ele_index = conditionlist.index(ele)
1969
topolist = conditionlist.pop(ele_index -1)
1970
right = conditionlist.pop(ele_index)
1971
left = conditionlist.pop(ele_index - 2)
1972
if all([left, right]):
1976
conditionlist[ele_index - 2] = result
1977
recurse_compare(conditionlist)
1978
resultlist = conditionlist
1985
# Loop through map list and evaluate conditional values.
1986
for map_i in maplist:
1987
if "condition_value" in dir(map_i):
1988
# Get condition values from map object.
1989
conditionlist = map_i.condition_value
1990
# Evaluate conditions in list with recursive function.
1991
resultbool = recurse_compare(conditionlist)
1992
# Set conditional value of map to resulting boolean.
1993
map_i.condition_value = resultbool
1994
# Add all maps that fulfill the conditions to result list.
1996
resultlist.append(map_i)
1998
print(map_i.get_map_id() + ' ' + str(map_i.condition_value))
2000
inverselist.append(map_i)
2006
###########################################################################
2008
def p_statement_assign(self, t):
2009
# The expression should always return a list of maps.
2011
statement : stds EQUALS expr
2015
dbif, connected = init_dbif(self.dbif)
2016
map_stds_type = None
2018
if isinstance(t[3], list):
2023
process_queue = pymod.ParallelModuleQueue(int(self.nprocs))
2025
# Test if temporal extents have been changed by temporal
2026
# relation operators (i|r).
2028
maps_stds_type = map_i.get_new_stds_instance(None).get_type()
2029
map_type = map_i.get_type()
2030
if maps_stds_type != self.stdstype:
2031
self.msgr.warning(_("The resulting space time dataset type <%(a)s> is "\
2032
"different from the requested type <%(b)s>"\
2033
%({"a":maps_stds_type, "b":self.stdstype})))
2035
map_type_2 = map_i.get_type()
2036
if map_type != map_type_2:
2037
self.msgr.fatal(_("Maps that should be registered in the "\
2038
"resulting space time dataset have different types."))
2040
map_i_extent = map_i.get_temporal_extent_as_tuple()
2041
map_test = map_i.get_new_instance(map_i.get_id())
2042
map_test.select(dbif)
2043
map_test_extent = map_test.get_temporal_extent_as_tuple()
2044
if map_test_extent != map_i_extent:
2045
# Create new map with basename
2046
newident = self.basename + "_" + str(count)
2047
map_result = map_i.get_new_instance(newident + "@" + self.mapset)
2049
if map_test.map_exists() and self.overwrite == False:
2050
self.msgr.fatal("Error raster maps with basename %s exist. "\
2051
"Use --o flag to overwrite existing file" \
2054
map_result.set_temporal_extent(map_i.get_temporal_extent())
2055
map_result.set_spatial_extent(map_i.get_spatial_extent())
2056
# Attention we attach a new attribute
2057
map_result.is_new = True
2058
register_list.append(map_result)
2061
if map_i.get_type() == 'raster':
2062
m = copy.deepcopy(self.m_copy)
2063
m.inputs["raster"].value = map_i.get_id(), newident
2064
m.flags["overwrite"].value = self.overwrite
2065
process_queue.put(m)
2066
elif map_i.get_type() == 'raster3d':
2067
m = copy.deepcopy(self.m_copy)
2068
m.inputs["raster_3d"].value = map_i.get_id(), newident
2069
m.flags["overwrite"].value = self.overwrite
2070
process_queue.put(m)
2071
elif map_i.get_type() == 'vector':
2072
m = copy.deepcopy(self.m_copy)
2073
m.inputs["vector"].value = map_i.get_id(), newident
2074
m.flags["overwrite"].value = self.overwrite
2075
process_queue.put(m)
2077
register_list.append(map_i)
2080
# Wait for running processes
2081
process_queue.wait()
2083
# Open connection to temporal database.
2084
# Create result space time dataset based on the map stds type
2085
resultstds = open_new_stds(t[1],maps_stds_type, \
2086
'absolute', t[1], t[1], \
2087
'mean', self.dbif, \
2088
overwrite = self.overwrite)
2089
for map_i in register_list:
2090
# Get meta data from grass database.
2092
# Check if temporal extents have changed and a new map was created
2093
if hasattr(map_i, "is_new") is True:
2094
# Do not register empty maps if not required
2095
# In case of a null map continue, do not register null maps
2096
if map_i.metadata.get_min() is None and \
2097
map_i.metadata.get_max() is None:
2098
if not self.register_null:
2099
self.removable_maps[map_i.get_name()] = map_i
2101
if map_i.is_in_db(dbif) and self.overwrite:
2102
# Update map in temporal database.
2103
map_i.update_all(dbif)
2104
elif map_i.is_in_db(dbif) and self.overwrite == False:
2105
# Raise error if map exists and no overwrite flag is given.
2106
self.msgr.fatal("Error map %s exist in temporal database. "
2107
"Use overwrite flag. : \n%s" \
2108
%(map_i.get_map_id(), cmd.popen.stderr))
2110
# Insert map into temporal database.
2112
# Register map in result space time dataset.
2113
success = resultstds.register_map(map_i, dbif)
2114
resultstds.update_from_registered_maps(dbif)
2116
self.msgr.warning("Empty result space time dataset. "\
2117
"No map has been registered in %s" %(t[1] ))
2118
# Open connection to temporal database.
2119
# Create result space time dataset.
2120
resultstds = open_new_stds(t[1], self.stdstype, \
2121
'absolute', t[1], t[1], \
2123
overwrite = self.overwrite)
2131
print t[1], "=", t[3]
2133
def p_stds_1(self, t):
2134
# Definition of a space time dataset
2140
def p_paren_expr(self, t):
2141
""" expr : LPAREN expr RPAREN"""
2144
def p_number(self,t):
2150
def p_expr_strds_function(self, t):
2151
# Specifiy a explicitely a space time raster dataset
2154
expr : STRDS LPAREN stds RPAREN
2157
t[0] = self.check_stds(t[3], stds_type = "strds", check_type=False)
2161
print "Opening STRDS: ", t[0]
2163
def p_expr_str3ds_function(self, t):
2164
# Specifiy a explicitely a space time raster dataset
2167
expr : STR3DS LPAREN stds RPAREN
2170
t[0] = self.check_stds(t[3], stds_type = "str3ds", check_type=False)
2174
print "Opening STR3DS: ", t[0]
2176
def p_expr_stvds_function(self, t):
2177
# Specifiy a explicitely a space time vector dataset
2180
expr : STVDS LPAREN stds RPAREN
2184
t[0] = self.check_stds(t[3], stds_type = "stvds", check_type=False)
2188
print "Opening STVDS: ", t[0]
2190
def p_expr_tmap_function(self, t):
2192
# Only the spatial extent of the map is evaluated.
2193
# Temporal extent is not existing.
2197
expr : TMAP LPAREN stds RPAREN
2202
if not isinstance(input, list):
2203
# Check for mapset in given stds input.
2204
if input.find("@") >= 0:
2207
id_input = input + "@" + self.mapset
2208
# Create empty map dataset.
2209
map_i = dataset_factory(self.maptype, id_input)
2210
# Check for occurence of space time dataset.
2211
if map_i.map_exists() == False:
2212
raise FatalError(_("%s map <%s> not found in GRASS spatial database") %
2213
(map_i.get_type(), id_input))
2215
# Select dataset entry from database.
2216
map_i.select(dbif=self.dbif)
2218
raise FatalError(_("Wrong map type <%s> . TMAP only supports single "\
2219
"maps that are registered in the temporal GRASS database")\
2220
%(map_i.get_type()))
2221
# Return map object.
2224
t[0] = "tmap(", t[3] , ")"
2227
print "tmap(", t[3] , ")"
2229
def p_t_hash(self,t):
2231
t_hash_var : stds HASH stds
2238
maplistA = self.check_stds(t[1])
2239
maplistB = self.check_stds(t[3])
2240
resultlist = self.get_temporal_topo_list(maplistA, maplistB,
2244
def p_t_hash2(self,t):
2246
t_hash_var : stds T_HASH_OPERATOR stds
2247
| stds T_HASH_OPERATOR expr
2248
| expr T_HASH_OPERATOR stds
2249
| expr T_HASH_OPERATOR expr
2253
maplistA = self.check_stds(t[1])
2254
maplistB = self.check_stds(t[3])
2255
topolist = self.eval_toperator(t[2], optype = 'hash')[0]
2256
resultlist = self.get_temporal_topo_list(maplistA, maplistB, topolist,
2260
def p_t_td_var(self, t):
2262
t_td_var : TD LPAREN stds RPAREN
2263
| TD LPAREN expr RPAREN
2266
maplist = self.check_stds(t[3])
2267
for map_i in maplist:
2268
if map_i.is_time_absolute:
2269
start, end = map_i.get_absolute_time()
2271
td = time_delta_to_relative_time(end - start)
2273
start, end, unit = current.get_relative_time()
2276
if "map_value" in dir(map_i):
2277
gvar = GlobalTemporalVar()
2279
map_i.map_value.append(gvar)
2281
map_i.map_value = gvar
2285
t[0] = "td(" + str(t[3]) + ")"
2288
print "td(" + str(t[3]) + ")"
2291
def p_t_time_var(self, t):
2292
# Temporal variables that return a double or integer value
2316
def p_compare_op(self, t):
2317
# Compare operators that are supported for temporal expressions
2328
def p_t_var_expr_td_hash(self, t):
2333
t_var_expr : t_td_var comp_op number
2334
| t_hash_var comp_op number
2337
maplist = self.check_stds(t[1])
2340
for map_i in maplist:
2341
# Evaluate time diferences and hash operator statements for each map.
2343
td = map_i.map_value[0].td
2344
boolname = eval(str(td) + comp_op + value)
2345
# Add conditional boolean value to the map.
2346
if "condition_value" in dir(map_i):
2347
map_i.condition_value.append(boolname)
2349
map_i.condition_value = boolname
2351
self.msgr.fatal("Error: the given expression does not contain a correct time difference object.")
2356
print t[1], t[2], t[3]
2358
def p_t_var_expr_number(self, t):
2360
# start_month(A) > 2
2362
# start_day(B) < start_month(A)
2364
t_var_expr : t_var LPAREN stds RPAREN comp_op number
2365
| t_var LPAREN expr RPAREN comp_op number
2367
# TODO: Implement comparison operator for map lists.
2368
#| t_var LPAREN stds RPAREN comp_op t_var LPAREN stds RPAREN
2369
#| t_var LPAREN stds RPAREN comp_op t_var LPAREN expr RPAREN
2370
#| t_var LPAREN expr RPAREN comp_op t_var LPAREN expr RPAREN
2371
#| t_var LPAREN expr RPAREN comp_op t_var LPAREN stds RPAREN
2372
# TODO: Implement statement in backward direction:
2373
# number comp_op t_var LPAREN stds RPAREN
2375
maplist = self.check_stds(t[3])
2376
gvar = GlobalTemporalVar()
2380
# Evaluate temporal variable for given maplist.
2381
resultlist = self.eval_global_var(gvar, maplist)
2385
print t[1], t[3], t[5], t[6]
2387
def p_t_var_expr_time(self, t):
2389
# start_time(A) == "12:30:00"
2390
# start_date(B) <= "2001-01-01"
2391
# start_datetime(C) > "2001-01-01 12:30:00"
2392
# TODO: Implement statement in backward direction:
2393
# TIME comp_op START_TIME LPAREN stds RPAREN
2395
t_var_expr : START_TIME LPAREN stds RPAREN comp_op TIME
2396
| START_DATE LPAREN stds RPAREN comp_op DATE
2397
| START_DATETIME LPAREN stds RPAREN comp_op DATETIME
2398
| END_TIME LPAREN stds RPAREN comp_op TIME
2399
| END_DATE LPAREN stds RPAREN comp_op DATE
2400
| END_DATETIME LPAREN stds RPAREN comp_op DATETIME
2401
| START_TIME LPAREN expr RPAREN comp_op TIME
2402
| START_DATE LPAREN expr RPAREN comp_op DATE
2403
| START_DATETIME LPAREN expr RPAREN comp_op DATETIME
2404
| END_TIME LPAREN expr RPAREN comp_op TIME
2405
| END_DATE LPAREN expr RPAREN comp_op DATE
2406
| END_DATETIME LPAREN expr RPAREN comp_op DATETIME
2409
# Check input maplist.
2410
maplist = self.check_stds(t[3])
2411
# Build global temporal variable.
2412
gvar = GlobalTemporalVar()
2416
# Evaluate temporal variable for given maplist.
2417
resultlist = self.eval_global_var(gvar, maplist)
2423
print t[1], t[3], t[5], t[6]
2425
def p_t_var_expr_comp(self, t):
2427
t_var_expr : t_var_expr AND AND t_var_expr
2428
| t_var_expr OR OR t_var_expr
2431
# Check input maplists and operators.
2434
relations = ["EQUAL"]
2436
function = t[2] + t[3]
2438
# Build conditional values based on topological relationships.
2439
complist = self.get_temporal_topo_list(tvarexprA, tvarexprB, topolist = relations,
2440
compare_bool = True, compop = function[0], aggregate = aggregate)
2441
# Set temporal extent based on topological relationships.
2442
resultlist = self.set_temporal_extent_list(complist, topolist = relations,
2443
temporal = temporal)
2448
print t[1], t[2] + t[3], t[4]
2450
def p_t_var_expr_comp_op(self, t):
2452
t_var_expr : t_var_expr T_COMP_OPERATOR t_var_expr
2457
# Evaluate temporal comparison operator.
2458
relations, temporal, function, aggregate = self.eval_toperator(t[2], optype = 'boolean')
2459
# Build conditional values based on topological relationships.
2460
complist = self.get_temporal_topo_list(tvarexprA, tvarexprB, topolist = relations,
2461
compare_bool = True, compop = function[0], aggregate = aggregate)
2462
# Set temporal extent based on topological relationships.
2463
resultlist = self.set_temporal_extent_list(complist, topolist = relations,
2464
temporal = temporal)
2469
print t[1], t[2], t[3]
2471
def p_expr_t_select(self, t):
2472
# Temporal equal selection
2473
# The temporal topology relation equals is implicit
2475
# A : B # Select the part of A that is temporally equal B
2477
expr : stds T_SELECT stds
2478
| expr T_SELECT stds
2479
| stds T_SELECT expr
2480
| expr T_SELECT expr
2483
# Setup database connection.
2486
maplistA = self.check_stds(t[1])
2487
maplistB = self.check_stds(t[3])
2488
# Perform selection.
2489
selectlist = self.perform_temporal_selection(maplistA, maplistB)
2496
print str(t[1]), "* = ", t[1], t[2], t[3]
2498
def p_expr_t_not_select(self, t):
2499
# Temporal equal selection
2500
# The temporal topology relation equals is implicit
2502
# A !: B # Select the part of A that is temporally unequal to B
2504
expr : stds T_NOT_SELECT stds
2505
| expr T_NOT_SELECT stds
2506
| stds T_NOT_SELECT expr
2507
| expr T_NOT_SELECT expr
2511
maplistA = self.check_stds(t[1])
2512
maplistB = self.check_stds(t[3])
2513
# Perform negative selection.
2514
selectlist = self.perform_temporal_selection(maplistA, maplistB,
2522
print t[1] + "* = ", t[1], t[2], t[3]
2525
def p_expr_t_select_operator(self, t):
2526
# Temporal equal selection
2527
# The temporal topology relation equals is implicit
2529
# A {!:} B # Select the part of A that is temporally unequal to B
2530
# A {:} B # Select the part of A that is temporally equal B
2531
# A {equals, !:} B # Select the part of A that is temporally unequal to B
2532
# A {during, !:} B # Select the part of A that is temporally not during B
2533
# A {overlaps, :} B # Select the part of A that temporally overlaps B
2534
# A {overlaps|equals, :} B # Select the part of A that temporally overlaps or equals B
2536
expr : stds T_SELECT_OPERATOR stds
2537
| expr T_SELECT_OPERATOR stds
2538
| stds T_SELECT_OPERATOR expr
2539
| expr T_SELECT_OPERATOR expr
2543
maplistA = self.check_stds(t[1])
2544
maplistB = self.check_stds(t[3])
2545
# Evaluate temporal operator.
2546
operators = self.eval_toperator(t[2], optype = 'select')
2547
# Check for negative selection.
2548
if operators[2] == "!:":
2552
# Perform selection.
2553
selectlist = self.perform_temporal_selection(maplistA, maplistB,
2554
topolist = operators[0], inverse = negation)
2555
selectlist = self.set_granularity(selectlist, maplistB, operators[1],
2563
print t[1] + "* = ", t[1], t[2], t[3]
2566
def p_expr_condition_if(self, t):
2568
# if( start_date() < "2005-06-01", A:B)
2570
expr : IF LPAREN t_var_expr COMMA stds RPAREN
2571
| IF LPAREN t_var_expr COMMA expr RPAREN
2574
# Get stds/map list of then statement.
2575
thenlist = self.check_stds(t[5])
2576
# Get temporal conditional statement.
2578
thencond = self.build_condition_list(tvarexpr, thenlist)
2579
thenresult = self.eval_condition_list(thencond)
2580
# Clear the map and conditional values of the map list.
2581
resultlist = self.check_stds(thenresult, clear = True)
2582
# Return resulting map list.
2588
print str(t[5]) + "* = ", "if condition", str(t[3]), ' then ', str(t[5])
2590
def p_expr_condition_if_relation(self, t):
2592
# if({equal} start_date() < "2005-06-01", A:B)
2594
expr : IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA stds RPAREN
2595
| IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA expr RPAREN
2598
# Get stds/map list of then statement.
2599
thenlist = self.check_stds(t[7])
2600
# Get temporal conditional statement.
2602
topolist = self.eval_toperator(t[3], optype = 'relation')[0]
2603
thencond = self.build_condition_list(tvarexpr, thenlist, topolist)
2604
thenresult = self.eval_condition_list(thencond)
2605
# Clear the map and conditional values of the map list.
2606
resultlist = self.check_stds(thenresult, clear = True)
2607
# Return resulting map list.
2613
print "result* = ", "if ", str(t[3]), "condition", str(t[5]), " then ", str(t[7])
2615
def p_expr_condition_elif(self, t):
2617
# if( start_date() < "2005-06-01", if(start_time() < "12:30:00", A:B), A!:B)
2619
expr : IF LPAREN t_var_expr COMMA stds COMMA stds RPAREN
2620
| IF LPAREN t_var_expr COMMA stds COMMA expr RPAREN
2621
| IF LPAREN t_var_expr COMMA expr COMMA stds RPAREN
2622
| IF LPAREN t_var_expr COMMA expr COMMA expr RPAREN
2625
# Get stds/map list of then statement.
2626
thenlist = self.check_stds(t[5])
2627
elselist = self.check_stds(t[7])
2628
# Get temporal conditional statement for then and else expressions.
2630
thencond = self.build_condition_list(tvarexpr, thenlist)
2631
thenresult = self.eval_condition_list(thencond)
2632
elsecond = self.build_condition_list(tvarexpr, elselist)
2633
elseresult = self.eval_condition_list(elsecond, inverse = True)
2635
# Combine and sort else and then statement to result map list.
2636
combilist = thenresult + elseresult
2637
resultlist = sorted(combilist, key = AbstractDatasetComparisonKeyStartTime)
2638
# Clear the map and conditional values of the map list.
2639
resultlist = self.check_stds(resultlist, clear = True)
2640
# Return resulting map list.
2646
print str(t[5]) + "* = ", "if condition", str(t[3]), " then ", str(t[5]), ' else ', str(t[7])
2648
def p_expr_condition_elif_relation(self, t):
2650
# if({equal}, start_date() < "2005-06-01", if(start_time() < "12:30:00", A:B), A!:B)
2651
# The then and else statement using the same topological relationships.
2652
# Feature request: Independent relationships for then and else to conditions.
2654
expr : IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA stds COMMA stds RPAREN
2655
| IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA stds COMMA expr RPAREN
2656
| IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA expr COMMA stds RPAREN
2657
| IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA expr COMMA expr RPAREN
2660
# Get stds/map list of then statement.
2661
thenlist = self.check_stds(t[7])
2662
elselist = self.check_stds(t[9])
2663
# Get temporal conditional statement.
2665
topolist = self.eval_toperator(t[3], optype = 'relation')[0]
2666
thencond = self.build_condition_list(tvarexpr, thenlist, topolist)
2667
thenresult = self.eval_condition_list(thencond)
2668
elsecond = self.build_condition_list(tvarexpr, elselist, topolist)
2669
elseresult = self.eval_condition_list(elsecond, inverse = True)
2671
# Combine and sort else and then statement to result map list.
2672
combilist = thenresult + elseresult
2673
resultlist = sorted(combilist, key = AbstractDatasetComparisonKeyStartTime)
2674
# Clear the map and conditional values of the map list.
2675
resultlist = self.check_stds(resultlist, clear = True)
2676
# Return resulting map list.
2686
print str(t[7]), "* = ", "if condition", str(t[5]), " then ", str(t[7]), ' else ', str(t[9])
2688
print str(t[9]), "* = ", "if condition", str(t[5]), " then ", str(t[7]), ' else ', str(t[9])
2690
def p_expr_t_buff(self, t):
2692
# buff_t(A : B, "10 minutes") # Select the part of A that is temporally
2693
# equal to B and create a buffer of 10 minutes around
2695
expr : BUFF_T LPAREN stds COMMA QUOTE number NAME QUOTE RPAREN
2696
| BUFF_T LPAREN expr COMMA QUOTE number NAME QUOTE RPAREN
2697
| BUFF_T LPAREN stds COMMA number RPAREN
2698
| BUFF_T LPAREN expr COMMA number RPAREN
2702
bufflist = self.check_stds(t[3])
2703
for map in bufflist:
2704
# Get increment format.
2706
increment = str(t[6]) + " " + t[7]
2708
increment = str(t[5])
2709
# Perform buffering.
2710
map.temporal_buffer(increment)
2717
print str(t[3]) + "* = buff_t(", str(t[3]), "," , '"', str(t[6]), str(t[7]), '"', ")"
2719
print str(t[3]) + "* = buff_t(", str(t[3]), ",", str(t[5]), ")"
2721
def p_expr_t_snap(self, t):
2723
# tsnap(A : B) # Snap the maps of A temporally.
2725
expr : TSNAP LPAREN stds RPAREN
2726
| TSNAP LPAREN expr RPAREN
2730
maplist = self.check_stds(t[3])
2732
snaplist = AbstractSpaceTimeDataset.snap_map_list(maplist)
2738
print str(t[3]) + "* = tsnap(", str(t[3]), ")"
2740
def p_expr_t_shift(self, t):
2742
# tshift(A : B, "10 minutes") # Shift the selection from A temporally
2745
expr : TSHIFT LPAREN stds COMMA QUOTE number NAME QUOTE RPAREN
2746
| TSHIFT LPAREN expr COMMA QUOTE number NAME QUOTE RPAREN
2747
| TSHIFT LPAREN stds COMMA number RPAREN
2748
| TSHIFT LPAREN expr COMMA number RPAREN
2752
maplist = self.check_stds(t[3])
2753
# Get increment format.
2755
increment = str(t[6]) + " " + t[7]
2757
increment = str(t[5])
2759
shiftlist = AbstractSpaceTimeDataset.shift_map_list(maplist, increment)
2766
print str(t[3]) + "* = tshift(", str(t[3]), "," , '"', str(t[6]), str(t[7]), '"', ")"
2768
print str(t[3]) + "* = tshift(", str(t[3]), ",", str(t[5]), ")"
2771
def p_error(self, t):
2773
raise SyntaxError("syntax error on line %d, token %s near '%s' expression '%s'" %
2774
(t.lineno, t.type, t.value, self.expression))
2776
raise SyntaxError("Unexpected syntax error")
2778
###############################################################################
2780
if __name__ == "__main__":