temporal_algebra.py 127 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343
  1. """@package grass.temporal
  2. Temporal algebra parser class
  3. (C) 2014 by the GRASS Development Team
  4. This program is free software under the GNU General Public
  5. License (>=v2). Read the file COPYING that comes with GRASS
  6. for details.
  7. :authors: Thomas Leppelt and Soeren Gebbert
  8. .. code-block:: python
  9. >>> import grass.temporal as tgis
  10. >>> tgis.init(True)
  11. >>> p = tgis.TemporalAlgebraLexer()
  12. >>> p.build()
  13. >>> p.debug = True
  14. >>> expression = "C = A : B"
  15. >>> p.test(expression)
  16. C = A : B
  17. LexToken(NAME,'C',1,0)
  18. LexToken(EQUALS,'=',1,2)
  19. LexToken(NAME,'A',1,4)
  20. LexToken(T_SELECT,':',1,6)
  21. LexToken(NAME,'B',1,8)
  22. >>> expression = "C = test1 !: test2"
  23. >>> p.test(expression)
  24. C = test1 !: test2
  25. LexToken(NAME,'C',1,0)
  26. LexToken(EQUALS,'=',1,2)
  27. LexToken(NAME,'test1',1,4)
  28. LexToken(T_NOT_SELECT,'!:',1,10)
  29. LexToken(NAME,'test2',1,13)
  30. >>> expression = "C = test1 {:,equal} test2"
  31. >>> p.test(expression)
  32. C = test1 {:,equal} test2
  33. LexToken(NAME,'C',1,0)
  34. LexToken(EQUALS,'=',1,2)
  35. LexToken(NAME,'test1',1,4)
  36. LexToken(T_SELECT_OPERATOR,'{:,equal}',1,10)
  37. LexToken(NAME,'test2',1,20)
  38. >>> expression = "C = test1 {!:,equal} test2"
  39. >>> p.test(expression)
  40. C = test1 {!:,equal} test2
  41. LexToken(NAME,'C',1,0)
  42. LexToken(EQUALS,'=',1,2)
  43. LexToken(NAME,'test1',1,4)
  44. LexToken(T_SELECT_OPERATOR,'{!:,equal}',1,10)
  45. LexToken(NAME,'test2',1,21)
  46. >>> expression = "C = test1 # test2"
  47. >>> p.test(expression)
  48. C = test1 # test2
  49. LexToken(NAME,'C',1,0)
  50. LexToken(EQUALS,'=',1,2)
  51. LexToken(NAME,'test1',1,4)
  52. LexToken(HASH,'#',1,10)
  53. LexToken(NAME,'test2',1,12)
  54. >>> expression = "C = test1 {#} test2"
  55. >>> p.test(expression)
  56. C = test1 {#} test2
  57. LexToken(NAME,'C',1,0)
  58. LexToken(EQUALS,'=',1,2)
  59. LexToken(NAME,'test1',1,4)
  60. LexToken(T_HASH_OPERATOR,'{#}',1,10)
  61. LexToken(NAME,'test2',1,14)
  62. >>> expression = "C = test1 {#,equal} test2"
  63. >>> p.test(expression)
  64. C = test1 {#,equal} test2
  65. LexToken(NAME,'C',1,0)
  66. LexToken(EQUALS,'=',1,2)
  67. LexToken(NAME,'test1',1,4)
  68. LexToken(T_HASH_OPERATOR,'{#,equal}',1,10)
  69. LexToken(NAME,'test2',1,20)
  70. >>> expression = "C = test1 {#,equal|during} test2"
  71. >>> p.test(expression)
  72. C = test1 {#,equal|during} test2
  73. LexToken(NAME,'C',1,0)
  74. LexToken(EQUALS,'=',1,2)
  75. LexToken(NAME,'test1',1,4)
  76. LexToken(T_HASH_OPERATOR,'{#,equal|during}',1,10)
  77. LexToken(NAME,'test2',1,27)
  78. >>> expression = "E = test1 : test2 !: test1"
  79. >>> p.test(expression)
  80. E = test1 : test2 !: test1
  81. LexToken(NAME,'E',1,0)
  82. LexToken(EQUALS,'=',1,2)
  83. LexToken(NAME,'test1',1,4)
  84. LexToken(T_SELECT,':',1,10)
  85. LexToken(NAME,'test2',1,12)
  86. LexToken(T_NOT_SELECT,'!:',1,18)
  87. LexToken(NAME,'test1',1,21)
  88. >>> expression = 'D = buff_t(test1,"10 months")'
  89. >>> p.test(expression)
  90. D = buff_t(test1,"10 months")
  91. LexToken(NAME,'D',1,0)
  92. LexToken(EQUALS,'=',1,2)
  93. LexToken(BUFF_T,'buff_t',1,4)
  94. LexToken(LPAREN,'(',1,10)
  95. LexToken(NAME,'test1',1,11)
  96. LexToken(COMMA,',',1,16)
  97. LexToken(QUOTE,'"',1,17)
  98. LexToken(INT,10,1,18)
  99. LexToken(NAME,'months',1,21)
  100. LexToken(QUOTE,'"',1,27)
  101. LexToken(RPAREN,')',1,28)
  102. >>> expression = 'H = tsnap(test1)'
  103. >>> p.test(expression)
  104. H = tsnap(test1)
  105. LexToken(NAME,'H',1,0)
  106. LexToken(EQUALS,'=',1,2)
  107. LexToken(TSNAP,'tsnap',1,4)
  108. LexToken(LPAREN,'(',1,9)
  109. LexToken(NAME,'test1',1,10)
  110. LexToken(RPAREN,')',1,15)
  111. >>> expression = 'H = tsnap(test2 {:,during} buff_t(test1, "1 days"))'
  112. >>> p.test(expression)
  113. H = tsnap(test2 {:,during} buff_t(test1, "1 days"))
  114. LexToken(NAME,'H',1,0)
  115. LexToken(EQUALS,'=',1,2)
  116. LexToken(TSNAP,'tsnap',1,4)
  117. LexToken(LPAREN,'(',1,9)
  118. LexToken(NAME,'test2',1,10)
  119. LexToken(T_SELECT_OPERATOR,'{:,during}',1,16)
  120. LexToken(BUFF_T,'buff_t',1,27)
  121. LexToken(LPAREN,'(',1,33)
  122. LexToken(NAME,'test1',1,34)
  123. LexToken(COMMA,',',1,39)
  124. LexToken(QUOTE,'"',1,41)
  125. LexToken(INT,1,1,42)
  126. LexToken(NAME,'days',1,44)
  127. LexToken(QUOTE,'"',1,48)
  128. LexToken(RPAREN,')',1,49)
  129. LexToken(RPAREN,')',1,50)
  130. >>> expression = 'H = tshift(test2 {:,during} buff_t(test1, "1 days"), "1 months")'
  131. >>> p.test(expression)
  132. H = tshift(test2 {:,during} buff_t(test1, "1 days"), "1 months")
  133. LexToken(NAME,'H',1,0)
  134. LexToken(EQUALS,'=',1,2)
  135. LexToken(TSHIFT,'tshift',1,4)
  136. LexToken(LPAREN,'(',1,10)
  137. LexToken(NAME,'test2',1,11)
  138. LexToken(T_SELECT_OPERATOR,'{:,during}',1,17)
  139. LexToken(BUFF_T,'buff_t',1,28)
  140. LexToken(LPAREN,'(',1,34)
  141. LexToken(NAME,'test1',1,35)
  142. LexToken(COMMA,',',1,40)
  143. LexToken(QUOTE,'"',1,42)
  144. LexToken(INT,1,1,43)
  145. LexToken(NAME,'days',1,45)
  146. LexToken(QUOTE,'"',1,49)
  147. LexToken(RPAREN,')',1,50)
  148. LexToken(COMMA,',',1,51)
  149. LexToken(QUOTE,'"',1,53)
  150. LexToken(INT,1,1,54)
  151. LexToken(NAME,'months',1,56)
  152. LexToken(QUOTE,'"',1,62)
  153. LexToken(RPAREN,')',1,63)
  154. >>> expression = 'H = tshift(A , 10)'
  155. >>> p.test(expression)
  156. H = tshift(A , 10)
  157. LexToken(NAME,'H',1,0)
  158. LexToken(EQUALS,'=',1,2)
  159. LexToken(TSHIFT,'tshift',1,4)
  160. LexToken(LPAREN,'(',1,10)
  161. LexToken(NAME,'A',1,11)
  162. LexToken(COMMA,',',1,13)
  163. LexToken(INT,10,1,15)
  164. LexToken(RPAREN,')',1,17)
  165. >>> expression = 'H = if(td(A) > 10, A)'
  166. >>> p.test(expression)
  167. H = if(td(A) > 10, A)
  168. LexToken(NAME,'H',1,0)
  169. LexToken(EQUALS,'=',1,2)
  170. LexToken(IF,'if',1,4)
  171. LexToken(LPAREN,'(',1,6)
  172. LexToken(TD,'td',1,7)
  173. LexToken(LPAREN,'(',1,9)
  174. LexToken(NAME,'A',1,10)
  175. LexToken(RPAREN,')',1,11)
  176. LexToken(GREATER,'>',1,13)
  177. LexToken(INT,10,1,15)
  178. LexToken(COMMA,',',1,17)
  179. LexToken(NAME,'A',1,19)
  180. LexToken(RPAREN,')',1,20)
  181. >>> expression = 'H = if(td(A) > 10, A, B)'
  182. >>> p.test(expression)
  183. H = if(td(A) > 10, A, B)
  184. LexToken(NAME,'H',1,0)
  185. LexToken(EQUALS,'=',1,2)
  186. LexToken(IF,'if',1,4)
  187. LexToken(LPAREN,'(',1,6)
  188. LexToken(TD,'td',1,7)
  189. LexToken(LPAREN,'(',1,9)
  190. LexToken(NAME,'A',1,10)
  191. LexToken(RPAREN,')',1,11)
  192. LexToken(GREATER,'>',1,13)
  193. LexToken(INT,10,1,15)
  194. LexToken(COMMA,',',1,17)
  195. LexToken(NAME,'A',1,19)
  196. LexToken(COMMA,',',1,20)
  197. LexToken(NAME,'B',1,22)
  198. LexToken(RPAREN,')',1,23)
  199. >>> expression = 'I = if(equals,td(A) > 10 {||,equals} td(B) < 10, A)'
  200. >>> p.test(expression)
  201. I = if(equals,td(A) > 10 {||,equals} td(B) < 10, A)
  202. LexToken(NAME,'I',1,0)
  203. LexToken(EQUALS,'=',1,2)
  204. LexToken(IF,'if',1,4)
  205. LexToken(LPAREN,'(',1,6)
  206. LexToken(NAME,'equals',1,7)
  207. LexToken(COMMA,',',1,13)
  208. LexToken(TD,'td',1,14)
  209. LexToken(LPAREN,'(',1,16)
  210. LexToken(NAME,'A',1,17)
  211. LexToken(RPAREN,')',1,18)
  212. LexToken(GREATER,'>',1,20)
  213. LexToken(INT,10,1,22)
  214. LexToken(T_COMP_OPERATOR,'{||,equals}',1,25)
  215. LexToken(TD,'td',1,37)
  216. LexToken(LPAREN,'(',1,39)
  217. LexToken(NAME,'B',1,40)
  218. LexToken(RPAREN,')',1,41)
  219. LexToken(LOWER,'<',1,43)
  220. LexToken(INT,10,1,45)
  221. LexToken(COMMA,',',1,47)
  222. LexToken(NAME,'A',1,49)
  223. LexToken(RPAREN,')',1,50)
  224. >>> expression = 'I = if(equals,td(A) > 10 || start_day() < 10, A)'
  225. >>> p.test(expression)
  226. I = if(equals,td(A) > 10 || start_day() < 10, A)
  227. LexToken(NAME,'I',1,0)
  228. LexToken(EQUALS,'=',1,2)
  229. LexToken(IF,'if',1,4)
  230. LexToken(LPAREN,'(',1,6)
  231. LexToken(NAME,'equals',1,7)
  232. LexToken(COMMA,',',1,13)
  233. LexToken(TD,'td',1,14)
  234. LexToken(LPAREN,'(',1,16)
  235. LexToken(NAME,'A',1,17)
  236. LexToken(RPAREN,')',1,18)
  237. LexToken(GREATER,'>',1,20)
  238. LexToken(INT,10,1,22)
  239. LexToken(OR,'|',1,25)
  240. LexToken(OR,'|',1,26)
  241. LexToken(START_DAY,'start_day',1,28)
  242. LexToken(LPAREN,'(',1,37)
  243. LexToken(RPAREN,')',1,38)
  244. LexToken(LOWER,'<',1,40)
  245. LexToken(INT,10,1,42)
  246. LexToken(COMMA,',',1,44)
  247. LexToken(NAME,'A',1,46)
  248. LexToken(RPAREN,')',1,47)
  249. >>> expression = 'E = if({equals},td(A) >= 4 {&&,contain} td(B) == 2, C : D)'
  250. >>> p.test(expression)
  251. E = if({equals},td(A) >= 4 {&&,contain} td(B) == 2, C : D)
  252. LexToken(NAME,'E',1,0)
  253. LexToken(EQUALS,'=',1,2)
  254. LexToken(IF,'if',1,4)
  255. LexToken(LPAREN,'(',1,6)
  256. LexToken(T_REL_OPERATOR,'{equals}',1,7)
  257. LexToken(COMMA,',',1,15)
  258. LexToken(TD,'td',1,16)
  259. LexToken(LPAREN,'(',1,18)
  260. LexToken(NAME,'A',1,19)
  261. LexToken(RPAREN,')',1,20)
  262. LexToken(GREATER_EQUALS,'>=',1,22)
  263. LexToken(INT,4,1,25)
  264. LexToken(T_COMP_OPERATOR,'{&&,contain}',1,27)
  265. LexToken(TD,'td',1,40)
  266. LexToken(LPAREN,'(',1,42)
  267. LexToken(NAME,'B',1,43)
  268. LexToken(RPAREN,')',1,44)
  269. LexToken(CEQUALS,'==',1,46)
  270. LexToken(INT,2,1,49)
  271. LexToken(COMMA,',',1,50)
  272. LexToken(NAME,'C',1,52)
  273. LexToken(T_SELECT,':',1,54)
  274. LexToken(NAME,'D',1,56)
  275. LexToken(RPAREN,')',1,57)
  276. >>> expression = 'F = if({equals},A {#,equal}, B, C : D)'
  277. >>> p.test(expression)
  278. F = if({equals},A {#,equal}, B, C : D)
  279. LexToken(NAME,'F',1,0)
  280. LexToken(EQUALS,'=',1,2)
  281. LexToken(IF,'if',1,4)
  282. LexToken(LPAREN,'(',1,6)
  283. LexToken(T_REL_OPERATOR,'{equals}',1,7)
  284. LexToken(COMMA,',',1,15)
  285. LexToken(NAME,'A',1,16)
  286. LexToken(T_HASH_OPERATOR,'{#,equal}',1,18)
  287. LexToken(COMMA,',',1,27)
  288. LexToken(NAME,'B',1,29)
  289. LexToken(COMMA,',',1,30)
  290. LexToken(NAME,'C',1,32)
  291. LexToken(T_SELECT,':',1,34)
  292. LexToken(NAME,'D',1,36)
  293. LexToken(RPAREN,')',1,37)
  294. >>> p = tgis.TemporalAlgebraParser()
  295. >>> p.run = False
  296. >>> p.debug = True
  297. >>> expression = "D = A {!:} B {:,during} C"
  298. >>> print(expression)
  299. D = A {!:} B {:,during} C
  300. >>> ret = p.parse(expression)
  301. A* = A {!:} B
  302. A** = A* {:,during} C
  303. D = A**
  304. >>> expression = "D = A {:} B {!:,during} C"
  305. >>> print(expression)
  306. D = A {:} B {!:,during} C
  307. >>> ret = p.parse(expression)
  308. A* = A {:} B
  309. A** = A* {!:,during} C
  310. D = A**
  311. >>> p.run = False
  312. >>> p.debug = False
  313. >>> expression = "C = test1 : test2"
  314. >>> print(expression)
  315. C = test1 : test2
  316. >>> ret = p.parse(expression, 'stvds')
  317. >>> expression = 'D = buff_t(test1,"10 months")'
  318. >>> print(expression)
  319. D = buff_t(test1,"10 months")
  320. >>> ret = p.parse(expression, 'stvds')
  321. >>> expression = 'E = test2 {:,during} buff_t(test1,"1 days")'
  322. >>> print(expression)
  323. E = test2 {:,during} buff_t(test1,"1 days")
  324. >>> ret = p.parse(expression, 'stvds')
  325. >>> expression = 'F = test2 {:,equal} buff_t(test1,"1 days")'
  326. >>> print(expression)
  327. F = test2 {:,equal} buff_t(test1,"1 days")
  328. >>> ret = p.parse(expression, 'stvds')
  329. >>> p.debug = True
  330. >>> expression = 'H = tsnap(test2 {:,during} buff_t(test1, "1 days"))'
  331. >>> ret = p.parse(expression, 'stvds')
  332. test1* = buff_t( test1 , " 1 days " )
  333. test2* = test2 {:,during} test1*
  334. test2** = tsnap( test2* )
  335. H = test2**
  336. >>> expression = 'H = tshift(test2 {:,during} test1, "1 days")'
  337. >>> ret = p.parse(expression, 'stvds')
  338. test2* = test2 {:,during} test1
  339. test2** = tshift( test2* , " 1 days " )
  340. H = test2**
  341. >>> expression = 'H = tshift(H, 3)'
  342. >>> ret = p.parse(expression, 'stvds')
  343. H* = tshift( H , 3 )
  344. H = H*
  345. >>> expression = 'C = if(td(A) == 2, A)'
  346. >>> ret = p.parse(expression, 'stvds')
  347. td(A)
  348. td(A) == 2
  349. A* = if condition None then A
  350. C = A*
  351. >>> expression = 'C = if(td(A) == 5, A, B)'
  352. >>> ret = p.parse(expression, 'stvds')
  353. td(A)
  354. td(A) == 5
  355. A* = if condition None then A else B
  356. C = A*
  357. >>> expression = 'C = if(td(A) == 5 || start_date(A) > "2010-01-01", A, B)'
  358. >>> ret = p.parse(expression, 'stvds')
  359. td(A)
  360. td(A) == 5
  361. start_date A > "2010-01-01"
  362. None || None
  363. A* = if condition None then A else B
  364. C = A*
  365. >>> p = tgis.TemporalAlgebraLexer()
  366. >>> p.build()
  367. >>> p.debug = True
  368. >>> expression = "D = strds(A) : stvds(B) : str3ds(C)"
  369. >>> p.test(expression)
  370. D = strds(A) : stvds(B) : str3ds(C)
  371. LexToken(NAME,'D',1,0)
  372. LexToken(EQUALS,'=',1,2)
  373. LexToken(STRDS,'strds',1,4)
  374. LexToken(LPAREN,'(',1,9)
  375. LexToken(NAME,'A',1,10)
  376. LexToken(RPAREN,')',1,11)
  377. LexToken(T_SELECT,':',1,13)
  378. LexToken(STVDS,'stvds',1,15)
  379. LexToken(LPAREN,'(',1,20)
  380. LexToken(NAME,'B',1,21)
  381. LexToken(RPAREN,')',1,22)
  382. LexToken(T_SELECT,':',1,24)
  383. LexToken(STR3DS,'str3ds',1,26)
  384. LexToken(LPAREN,'(',1,32)
  385. LexToken(NAME,'C',1,33)
  386. LexToken(RPAREN,')',1,34)
  387. >>> p = tgis.TemporalAlgebraLexer()
  388. >>> p.build()
  389. >>> p.debug = True
  390. >>> expression = "R = if(A {#,during} stvds(C) == 1, A)"
  391. >>> p.test(expression)
  392. R = if(A {#,during} stvds(C) == 1, A)
  393. LexToken(NAME,'R',1,0)
  394. LexToken(EQUALS,'=',1,2)
  395. LexToken(IF,'if',1,4)
  396. LexToken(LPAREN,'(',1,6)
  397. LexToken(NAME,'A',1,7)
  398. LexToken(T_HASH_OPERATOR,'{#,during}',1,9)
  399. LexToken(STVDS,'stvds',1,20)
  400. LexToken(LPAREN,'(',1,25)
  401. LexToken(NAME,'C',1,26)
  402. LexToken(RPAREN,')',1,27)
  403. LexToken(CEQUALS,'==',1,29)
  404. LexToken(INT,1,1,32)
  405. LexToken(COMMA,',',1,33)
  406. LexToken(NAME,'A',1,35)
  407. LexToken(RPAREN,')',1,36)
  408. >>> p = tgis.TemporalAlgebraLexer()
  409. >>> p.build()
  410. >>> p.debug = True
  411. >>> expression = "R = if({during}, stvds(C) {#,contains} A == 2, A)"
  412. >>> p.test(expression)
  413. R = if({during}, stvds(C) {#,contains} A == 2, A)
  414. LexToken(NAME,'R',1,0)
  415. LexToken(EQUALS,'=',1,2)
  416. LexToken(IF,'if',1,4)
  417. LexToken(LPAREN,'(',1,6)
  418. LexToken(T_REL_OPERATOR,'{during}',1,7)
  419. LexToken(COMMA,',',1,15)
  420. LexToken(STVDS,'stvds',1,17)
  421. LexToken(LPAREN,'(',1,22)
  422. LexToken(NAME,'C',1,23)
  423. LexToken(RPAREN,')',1,24)
  424. LexToken(T_HASH_OPERATOR,'{#,contains}',1,26)
  425. LexToken(NAME,'A',1,39)
  426. LexToken(CEQUALS,'==',1,41)
  427. LexToken(INT,2,1,44)
  428. LexToken(COMMA,',',1,45)
  429. LexToken(NAME,'A',1,47)
  430. LexToken(RPAREN,')',1,48)
  431. """
  432. from __future__ import print_function
  433. try:
  434. import ply.lex as lex
  435. import ply.yacc as yacc
  436. except:
  437. pass
  438. import os
  439. import sys
  440. import copy
  441. from datetime import datetime
  442. import grass.pygrass.modules as pymod
  443. from .core import (
  444. init_dbif,
  445. get_tgis_message_interface,
  446. get_current_mapset,
  447. SQLDatabaseInterfaceConnection,
  448. )
  449. from .temporal_granularity import (
  450. compute_common_absolute_time_granularity,
  451. compute_common_relative_time_granularity,
  452. )
  453. from .abstract_dataset import AbstractDatasetComparisonKeyStartTime
  454. from .abstract_map_dataset import AbstractMapDataset
  455. from .space_time_datasets import RasterDataset
  456. from .factory import dataset_factory
  457. from .open_stds import open_new_stds, open_old_stds
  458. from .temporal_operator import TemporalOperatorParser
  459. from .spatio_temporal_relationships import SpatioTemporalTopologyBuilder
  460. from .datetime_math import time_delta_to_relative_time, string_to_datetime
  461. from .abstract_space_time_dataset import AbstractSpaceTimeDataset
  462. from .temporal_granularity import compute_absolute_time_granularity
  463. from .datetime_math import create_suffix_from_datetime
  464. from .datetime_math import create_time_suffix
  465. from .datetime_math import create_numeric_suffix
  466. if sys.version_info[0] >= 3:
  467. unicode = str
  468. class TemporalAlgebraLexer(object):
  469. """Lexical analyzer for the GRASS GIS temporal algebra"""
  470. # Functions that defines an if condition, temporal buffering, snapping and
  471. # selection of maps with temporal extent.
  472. conditional_functions = {
  473. "if": "IF",
  474. "buff_t": "BUFF_T",
  475. "tsnap": "TSNAP",
  476. "tshift": "TSHIFT",
  477. "tmap": "TMAP",
  478. "merge": "MERGE",
  479. "strds": "STRDS",
  480. "str3ds": "STR3DS",
  481. "stvds": "STVDS",
  482. }
  483. # Variables with date and time strings
  484. datetime_functions = {
  485. "start_time": "START_TIME", # start time as HH::MM:SS
  486. "start_date": "START_DATE", # start date as yyyy-mm-DD
  487. "start_datetime": "START_DATETIME", # start datetime as yyyy-mm-DD HH:MM:SS
  488. "end_time": "END_TIME", # end time as HH:MM:SS
  489. "end_date": "END_DATE", # end date as yyyy-mm-DD
  490. "end_datetime": "END_DATETIME", # end datetime as yyyy-mm-DD HH:MM:SS
  491. }
  492. # Time functions
  493. time_functions = {
  494. "td": "TD", # The size of the current
  495. # sample time interval in days and
  496. # fraction of days for absolute time,
  497. # and in relative units in case of relative time.
  498. # 'start_td' : 'START_TD', # The time difference between the start
  499. # time of the sample space time raster
  500. # dataset and the start time of the
  501. # current sample interval or instance.
  502. # The time is measured in days and
  503. # fraction of days for absolute time,
  504. # and in relative units in case of relative time.
  505. # 'end_td' : 'END_TD', # The time difference between the
  506. # start time of the sample
  507. # space time raster dataset and the
  508. # end time of the current sample interval.
  509. # The time is measured in days and
  510. # fraction of days for absolute time,
  511. # and in relative units in case of relative time.
  512. # The end_time() will be represented by null() in case of a time instance.
  513. "start_doy": "START_DOY", # Day of year (doy) from the start time [1 - 366]
  514. "start_dow": "START_DOW", # Day of week (dow) from the start time [1 - 7], the start of the week is Monday == 1
  515. "start_year": "START_YEAR", # The year of the start time [0 - 9999]
  516. "start_month": "START_MONTH", # The month of the start time [1 - 12]
  517. "start_week": "START_WEEK", # Week of year of the start time [1 - 54]
  518. "start_day": "START_DAY", # Day of month from the start time [1 - 31]
  519. "start_hour": "START_HOUR", # The hour of the start time [0 - 23]
  520. "start_minute": "START_MINUTE", # The minute of the start time [0 - 59]
  521. "start_second": "START_SECOND", # The second of the start time [0 - 59]
  522. "end_doy": "END_DOY", # Day of year (doy) from the end time [1 - 366]
  523. "end_dow": "END_DOW", # Day of week (dow) from the end time [1 - 7], the start of the week is Monday == 1
  524. "end_year": "END_YEAR", # The year of the end time [0 - 9999]
  525. "end_month": "END_MONTH", # The month of the end time [1 - 12]
  526. "end_week": "END_WEEK", # Week of year of the end time [1 - 54]
  527. "end_day": "END_DAY", # Day of month from the start time [1 - 31]
  528. "end_hour": "END_HOUR", # The hour of the end time [0 - 23]
  529. "end_minute": "END_MINUTE", # The minute of the end time [0 - 59]
  530. "end_second": "END_SECOND", # The second of the end time [0 - 59]
  531. }
  532. # This is the list of token names.
  533. tokens = (
  534. "DATETIME",
  535. "TIME",
  536. "DATE",
  537. "INT",
  538. "FLOAT",
  539. "LPAREN",
  540. "RPAREN",
  541. "COMMA",
  542. "CEQUALS",
  543. "EQUALS",
  544. "UNEQUALS",
  545. "LOWER",
  546. "LOWER_EQUALS",
  547. "GREATER",
  548. "GREATER_EQUALS",
  549. "HASH",
  550. "OR",
  551. "AND",
  552. "T_SELECT_OPERATOR",
  553. "T_HASH_OPERATOR",
  554. "T_COMP_OPERATOR",
  555. "T_REL_OPERATOR",
  556. "T_SELECT",
  557. "T_NOT_SELECT",
  558. "NAME",
  559. "QUOTE",
  560. )
  561. # Build the token list
  562. tokens = (
  563. tokens
  564. + tuple(datetime_functions.values())
  565. + tuple(time_functions.values())
  566. + tuple(conditional_functions.values())
  567. )
  568. # Regular expression rules for simple tokens
  569. t_T_SELECT_OPERATOR = r"\{[!]?[:][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}"
  570. t_T_HASH_OPERATOR = (
  571. r"\{[#][,]?[a-zA-Z\| ]*([,])?([lrudi]|left|right|union|disjoint|intersect)?\}"
  572. )
  573. t_T_COMP_OPERATOR = r"\{(\|\||&&)[,][a-zA-Z\| ]*[,]?[\|&]?([,])?([lrudi]|left|right|union|disjoint|intersect)?\}"
  574. t_T_REL_OPERATOR = r"\{([a-zA-Z\| ])+\}"
  575. t_T_SELECT = r":"
  576. t_T_NOT_SELECT = r"!:"
  577. t_LPAREN = r"\("
  578. t_RPAREN = r"\)"
  579. t_COMMA = r","
  580. t_CEQUALS = r"=="
  581. t_EQUALS = r"="
  582. t_UNEQUALS = r"!="
  583. t_LOWER = r"<"
  584. t_LOWER_EQUALS = r"<="
  585. t_GREATER = r">"
  586. t_GREATER_EQUALS = r">="
  587. t_HASH = r"\#"
  588. t_OR = r"[\|]"
  589. t_AND = r"[&]"
  590. t_QUOTE = r"[\"\']"
  591. # These are the things that should be ignored.
  592. t_ignore = " \t\n"
  593. # Read time string and convert it into a date object
  594. def t_DATETIME(self, t):
  595. 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)"'
  596. # t.value = int(t.value)
  597. return t
  598. # Read date string and convert it into a date object
  599. def t_DATE(self, t):
  600. r'"\d\d\d\d-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])"'
  601. # t.value = int(t.value)
  602. return t
  603. # Read time string and convert it into a date object
  604. def t_TIME(self, t):
  605. 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)"'
  606. # t.value = int(t.value)
  607. return t
  608. # Read in a float. This rule has to be done before the int rule.
  609. def t_FLOAT(self, t):
  610. r"-?\d+\.\d*(e-?\d+)?"
  611. t.value = float(t.value)
  612. return t
  613. # Read in an int.
  614. def t_INT(self, t):
  615. r"-?\d+"
  616. t.value = int(t.value)
  617. return t
  618. # Read in a list of maps.
  619. def t_LIST(self, t):
  620. r"[\[][.]*[\]]"
  621. t.value = list(t.value)
  622. return t
  623. # Ignore comments.
  624. # def t_comment(self, t):
  625. # r'^[#][^\n]*'
  626. # pass
  627. # Track line numbers.
  628. def t_newline(self, t):
  629. r"\n+"
  630. t.lineno += len(t.value)
  631. def t_NAME(self, t):
  632. r"[a-zA-Z_][a-zA-Z_0-9\@]*"
  633. self.temporal_symbol(t)
  634. return t
  635. # Parse symbols
  636. def temporal_symbol(self, t):
  637. # Check for reserved words
  638. if t.value in TemporalAlgebraLexer.time_functions.keys():
  639. t.type = TemporalAlgebraLexer.time_functions.get(t.value)
  640. elif t.value in TemporalAlgebraLexer.datetime_functions.keys():
  641. t.type = TemporalAlgebraLexer.datetime_functions.get(t.value)
  642. elif t.value in TemporalAlgebraLexer.conditional_functions.keys():
  643. t.type = TemporalAlgebraLexer.conditional_functions.get(t.value)
  644. else:
  645. t.type = "NAME"
  646. return t
  647. # Handle errors.
  648. def t_error(self, t):
  649. raise SyntaxError(
  650. "syntax error on line %d position %i near '%s'"
  651. % (t.lineno, t.lexpos, t.value)
  652. )
  653. # Build the lexer
  654. def build(self, **kwargs):
  655. self.lexer = lex.lex(
  656. module=self, optimize=False, nowarn=True, debug=0, **kwargs
  657. )
  658. # Just for testing
  659. def test(self, data):
  660. self.name_list = {}
  661. print(data)
  662. self.lexer.input(data)
  663. while True:
  664. tok = self.lexer.token()
  665. if not tok:
  666. break
  667. print(tok)
  668. class GlobalTemporalVar(object):
  669. """This class handles global temporal variable conditional expressions,
  670. like start_doy() == 3.
  671. The three parts of the statement are stored separately in
  672. tfunc (START_DOY), compop (==) and value (3).
  673. But also boolean values, time differences and relation operators for comparison in
  674. if-statements can be stored in this class.
  675. """
  676. def __init__(self):
  677. self.tfunc = None
  678. self.compop = None
  679. self.value = None
  680. self.boolean = None
  681. self.relationop = None
  682. self.topology = []
  683. self.td = None
  684. def get_type(self):
  685. if (
  686. self.tfunc is not None
  687. and self.compop is not None
  688. and self.value is not None
  689. ):
  690. return "global"
  691. elif self.boolean is not None:
  692. return "boolean"
  693. elif self.relationop is not None and self.topology != []:
  694. return "operator"
  695. elif self.td is not None:
  696. return "timediff"
  697. def get_type_value(self):
  698. typename = self.get_type()
  699. valuelist = []
  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)
  709. return valuelist
  710. def __str__(self):
  711. return str(self.tfunc) + str(self.compop) + str(self.value)
  712. class FatalError(Exception):
  713. def __init__(self, msg):
  714. self.value = msg
  715. def __str__(self):
  716. return self.value
  717. class TemporalAlgebraParser(object):
  718. """The temporal algebra class"""
  719. # Get the tokens from the lexer class
  720. tokens = TemporalAlgebraLexer.tokens
  721. # Setting equal precedence level for select and hash operations.
  722. precedence = (
  723. (
  724. "left",
  725. "T_SELECT_OPERATOR",
  726. "T_SELECT",
  727. "T_NOT_SELECT",
  728. "T_HASH_OPERATOR",
  729. "HASH",
  730. ), # 1
  731. ("left", "AND", "OR", "T_COMP_OPERATOR"), # 2
  732. )
  733. def __init__(
  734. self,
  735. pid=None,
  736. run=True,
  737. debug=False,
  738. spatial=False,
  739. register_null=False,
  740. dry_run=False,
  741. nprocs=1,
  742. time_suffix=None,
  743. ):
  744. self.run = run
  745. self.dry_run = (
  746. dry_run # Compute the processes and output but Do not start the processes
  747. )
  748. self.process_chain_dict = (
  749. {}
  750. ) # This dictionary stores all processes, as well as the maps to register and remove
  751. self.process_chain_dict[
  752. "processes"
  753. ] = [] # The mapcalc and v.patch module calls
  754. self.process_chain_dict[
  755. "register"
  756. ] = [] # Maps that must be registered/updated or inserted in a new STDS
  757. self.process_chain_dict["remove"] = [] # The g.remove module calls
  758. self.process_chain_dict["STDS"] = {} # The STDS that must be created
  759. self.debug = debug
  760. self.pid = pid
  761. # Intermediate vector map names
  762. self.names = {}
  763. # Count map names
  764. self.spatial = spatial
  765. self.mapset = get_current_mapset()
  766. self.temporaltype = None
  767. self.msgr = get_tgis_message_interface()
  768. self.dbif = SQLDatabaseInterfaceConnection()
  769. self.dbif.connect()
  770. self.register_null = register_null
  771. self.removable_maps = {}
  772. self.m_mremove = pymod.Module("g.remove")
  773. self.m_copy = pymod.Module("g.copy")
  774. self.nprocs = nprocs
  775. self.use_granularity = False
  776. self.time_suffix = time_suffix
  777. # Topology lists
  778. self.temporal_topology_list = [
  779. "EQUAL",
  780. "FOLLOWS",
  781. "PRECEDES",
  782. "OVERLAPS",
  783. "OVERLAPPED",
  784. "DURING",
  785. "STARTS",
  786. "FINISHES",
  787. "CONTAINS",
  788. "STARTED",
  789. "FINISHED",
  790. ]
  791. self.spatial_topology_list = [
  792. "EQUIVALENT",
  793. "COVER",
  794. "OVERLAP",
  795. "IN",
  796. "CONTAIN",
  797. "MEET",
  798. ]
  799. def __del__(self):
  800. if self.dbif.connected:
  801. self.dbif.close()
  802. def setup_common_granularity(self, expression, stdstype="strds", lexer=None):
  803. """Configure the temporal algebra to use the common granularity of all
  804. space time datasets in the expression to generate the map lists.
  805. This function will analyze the expression to detect space time datasets
  806. and computes the common granularity from all granularities of the input space time datasets.
  807. This granularity is then be used to generate the map lists. Hence, all
  808. maps from all STDS will have equidistant temporal extents. The only meaningful
  809. temporal relation is therefore "equal".
  810. :param expression: The algebra expression to analyze
  811. :param lexer: The temporal algebra lexer (select, raster, voxel, vector) that should be used to
  812. parse the expression, default is TemporalAlgebraLexer
  813. :return: True if successful, False otherwise
  814. """
  815. l = lexer
  816. # Split the expression to ignore the left part
  817. expressions = expression.split("=")[1:]
  818. expression = " ".join(expressions)
  819. # Check if spatio-temporal operators are present in the expression
  820. if "{" in expression or "}" in expression:
  821. self.msgr.error(
  822. _(
  823. "Spatio-temporal topological operators are not"
  824. " supported in granularity algebra mode"
  825. )
  826. )
  827. return False
  828. # detect all STDS
  829. if l is None:
  830. l = TemporalAlgebraLexer()
  831. l.build()
  832. l.lexer.input(expression)
  833. name_list = []
  834. tokens = []
  835. count = 0
  836. while True:
  837. tok = l.lexer.token()
  838. if not tok:
  839. break
  840. # Ignore map layer
  841. tokens.append(tok.type)
  842. ignore = False
  843. if count > 1:
  844. if tokens[count - 2] == "MAP" or tokens[count - 2] == "TMAP":
  845. ignore = True
  846. if tok.type == "NAME" and ignore is False:
  847. name_list.append(tok.value)
  848. count += 1
  849. grans = []
  850. start_times = []
  851. ttypes = {}
  852. dbif, connection_state_changed = init_dbif(self.dbif)
  853. for name in name_list:
  854. stds = open_old_stds(name, stdstype, dbif)
  855. # We need valid temporal topology
  856. if stds.check_temporal_topology() is False:
  857. self.msgr.error(
  858. _(
  859. "All input space time datasets must have a valid temporal topology."
  860. )
  861. )
  862. return False
  863. grans.append(stds.get_granularity())
  864. start_times.append(stds.get_temporal_extent_as_tuple()[0])
  865. ttypes[stds.get_temporal_type()] = stds.get_temporal_type()
  866. # Only one temporal type is allowed
  867. if len(ttypes) > 1:
  868. self.msgr.error(
  869. _("All input space time datasets must have the same temporal type.")
  870. )
  871. return False
  872. # Compute the common granularity
  873. if "absolute" in ttypes.keys():
  874. self.granularity = compute_common_absolute_time_granularity(
  875. grans, start_times
  876. )
  877. else:
  878. self.granularity = compute_common_relative_time_granularity(grans)
  879. self.use_granularity = True
  880. return True
  881. def parse(
  882. self,
  883. expression,
  884. stdstype="strds",
  885. maptype="rast",
  886. mapclass=RasterDataset,
  887. basename=None,
  888. overwrite=False,
  889. ):
  890. """Parse the algebra expression and run the computation
  891. :param expression:
  892. :param stdstype:
  893. :param maptype:
  894. :param mapclass:
  895. :param basename:
  896. :param overwrite:
  897. :return: The process chain dictionary is dry-run was enabled, None otherwise
  898. """
  899. self.lexer = TemporalAlgebraLexer()
  900. self.lexer.build()
  901. self.parser = yacc.yacc(module=self, debug=self.debug, write_tables=False)
  902. self.overwrite = overwrite
  903. self.count = 0
  904. self.stdstype = stdstype
  905. self.maptype = maptype
  906. self.mapclass = mapclass
  907. self.basename = basename
  908. self.expression = expression
  909. self.parser.parse(expression)
  910. return self.process_chain_dict
  911. def generate_map_name(self):
  912. """Generate an unique map name and register it in the objects map list
  913. The map names are unique between processes. Do not use the
  914. same object for map name generation in multiple threads.
  915. """
  916. self.count += 1
  917. if self.pid is not None:
  918. pid = self.pid
  919. else:
  920. pid = os.getpid()
  921. name = "tmp_map_name_%i_%i" % (pid, self.count)
  922. self.names[name] = name
  923. return name
  924. def generate_new_map(
  925. self, base_map, bool_op="and", copy=True, rename=True, remove=False
  926. ):
  927. """Generate a new map using the spatio-temporal extent of the base map
  928. :param base_map: This map is used to create the new map
  929. :param bool_op: The boolean operator specifying the spatial extent
  930. operation (intersection, union, disjoint union)
  931. :param copy: Specifies if the temporal extent of mapB should be
  932. copied to mapA
  933. :param rename: Specifies if the generated map get a random name or get
  934. the id from the base map.
  935. :param remove: Set this True if this map is an intermediate or empty map that should be removed
  936. :return: Map object
  937. """
  938. # Generate an intermediate name for the result map list.
  939. name = self.generate_map_name()
  940. # Check for mapset in given stds input.
  941. mapname = name + "@" + self.mapset
  942. # Create new map based on the related map list.
  943. map_new = base_map.get_new_instance(mapname)
  944. # Set initial map extend of new vector map.
  945. self.overlay_map_extent(map_new, base_map, bool_op=bool_op, copy=copy)
  946. if not rename:
  947. name = base_map.get_id()
  948. map_new.set_id(name)
  949. if remove is True:
  950. self.removable_maps[name] = map_new
  951. # Make sure to set the uid that is used in several dictionaries
  952. map_new.uid = name
  953. return map_new
  954. def overlay_map_extent(self, mapA, mapB, bool_op=None, temp_op="l", copy=False):
  955. """Compute the spatio-temporal extent of two topological related maps
  956. :param mapA: The first map
  957. :param mapB: The second maps
  958. :param bool_op: The boolean operator specifying the spatial extent
  959. operation (intersection, union, disjoint union)
  960. :param temp_op: The temporal operator specifying the temporal
  961. extent operation (intersection, union, disjoint union, right reference)
  962. Left reference is the default temporal extent behaviour.
  963. :param copy: Specifies if the temporal extent of mapB should be
  964. copied to mapA
  965. :return: 0 if there is no overlay
  966. """
  967. returncode = 1
  968. if copy:
  969. map_extent_temporal = mapB.get_temporal_extent()
  970. map_extent_spatial = mapB.get_spatial_extent()
  971. # Set initial map extend of new vector map.
  972. mapA.set_spatial_extent(map_extent_spatial)
  973. mapA.set_temporal_extent(map_extent_temporal)
  974. if "cmd_list" in dir(mapB):
  975. mapA.cmd_list = mapB.cmd_list
  976. if "condition_value" in dir(mapB):
  977. mapA.condition_value = mapB.condition_value
  978. else:
  979. # Calculate spatial extent for different overlay operations.
  980. if bool_op == "and":
  981. overlay_ext = mapA.spatial_intersection(mapB)
  982. if overlay_ext is not None:
  983. mapA.set_spatial_extent(overlay_ext)
  984. else:
  985. returncode = 0
  986. elif bool_op in ["or", "xor"]:
  987. overlay_ext = mapA.spatial_union(mapB)
  988. if overlay_ext is not None:
  989. mapA.set_spatial_extent(overlay_ext)
  990. else:
  991. returncode = 0
  992. elif bool_op == "disor":
  993. overlay_ext = mapA.spatial_disjoint_union(mapB)
  994. if overlay_ext is not None:
  995. mapA.set_spatial_extent(overlay_ext)
  996. else:
  997. returncode = 0
  998. # Calculate temporal extent for different temporal operators.
  999. if temp_op == "i":
  1000. temp_ext = mapA.temporal_intersection(mapB)
  1001. if temp_ext is not None:
  1002. mapA.set_temporal_extent(temp_ext)
  1003. else:
  1004. returncode = 0
  1005. elif temp_op == "u":
  1006. temp_ext = mapA.temporal_union(mapB)
  1007. if temp_ext is not None:
  1008. mapA.set_temporal_extent(temp_ext)
  1009. else:
  1010. returncode = 0
  1011. elif temp_op == "d":
  1012. temp_ext = mapA.temporal_disjoint_union(mapB)
  1013. if temp_ext is not None:
  1014. mapA.set_temporal_extent(temp_ext)
  1015. else:
  1016. returncode = 0
  1017. elif temp_op == "r":
  1018. temp_ext = mapB.get_temporal_extent()
  1019. if temp_ext is not None:
  1020. mapA.set_temporal_extent(temp_ext)
  1021. else:
  1022. returncode = 0
  1023. return returncode
  1024. def set_temporal_extent_list(self, maplist, topolist=["EQUAL"], temporal="l"):
  1025. """Change temporal extent of map list based on temporal relations to
  1026. other map list and given temporal operator.
  1027. :param maplist: List of map objects for which relations has been build
  1028. correctly.
  1029. :param topolist: List of strings of temporal relations.
  1030. :param temporal: The temporal operator specifying the temporal
  1031. extent operation (intersection, union, disjoint
  1032. union, right reference, left reference).
  1033. :return: Map list with specified temporal extent.
  1034. """
  1035. resultdict = {}
  1036. temporal_topo_list, spatial_topo_list = self._check_topology(topolist=topolist)
  1037. for map_i in maplist:
  1038. # Loop over temporal related maps and create overlay modules.
  1039. tbrelations = map_i.get_temporal_relations()
  1040. # Generate an intermediate map for the result map list.
  1041. map_new = self.generate_new_map(
  1042. base_map=map_i, bool_op="and", copy=True, rename=True
  1043. )
  1044. # Combine temporal and spatial extents of intermediate map with related maps.
  1045. for topo in topolist:
  1046. if topo in tbrelations.keys():
  1047. for map_j in tbrelations[topo]:
  1048. if (
  1049. self._check_spatial_topology_relation(
  1050. spatial_topo_list, map_i, map_j
  1051. )
  1052. is True
  1053. ):
  1054. if temporal == "r":
  1055. # Generate an intermediate map for the result map list.
  1056. map_new = self.generate_new_map(
  1057. base_map=map_i,
  1058. bool_op="and",
  1059. copy=True,
  1060. rename=True,
  1061. )
  1062. # Create overlaid map extent.
  1063. returncode = self.overlay_map_extent(
  1064. map_new, map_j, "and", temp_op=temporal
  1065. )
  1066. print(map_new.get_id(), map_j.get_id())
  1067. # Stop the loop if no temporal or spatial relationship exist.
  1068. if returncode == 0:
  1069. break
  1070. # Append map to result map list.
  1071. elif returncode == 1:
  1072. # print(map_new.get_id() + " " + str(map_new.get_temporal_extent_as_tuple()))
  1073. # print(map_new.condition_value)
  1074. # print(map_new.cmd_list)
  1075. # resultlist.append(map_new)
  1076. resultdict[map_new.get_id()] = map_new
  1077. # Create r.mapcalc expression string for the operation.
  1078. # cmdstring = self.build_command_string(s_expr_a = map_new,
  1079. # s_expr_b = map_j,
  1080. # operator = function)
  1081. # Conditional append of module command.
  1082. # map_new.cmd_list = cmdstring
  1083. if returncode == 0:
  1084. break
  1085. # Append map to result map list.
  1086. # if returncode == 1:
  1087. # resultlist.append(map_new)
  1088. # Get sorted map objects as values from result dictionary.
  1089. resultlist = resultdict.values()
  1090. resultlist = sorted(resultlist, key=AbstractDatasetComparisonKeyStartTime)
  1091. return resultlist
  1092. def remove_maps(self):
  1093. """Removes empty or intermediate maps of different type."""
  1094. map_names = {}
  1095. map_names["raster"] = []
  1096. map_names["raster3d"] = []
  1097. map_names["vector"] = []
  1098. if self.removable_maps:
  1099. for map in self.removable_maps.values():
  1100. map_names[map.get_type()].append(map.get_name())
  1101. for key in map_names.keys():
  1102. if map_names[key]:
  1103. self.msgr.message(_("Removing un-needed or empty %s maps" % (key)))
  1104. self._remove_maps(map_names[key], key)
  1105. def _remove_maps(self, namelist, map_type):
  1106. """Remove maps of specific type
  1107. :param namelist: List of map names to be removed
  1108. :param map_type: The type of the maps (raster, raster_3d or vector)
  1109. """
  1110. max = 100
  1111. chunklist = [namelist[i : i + max] for i in range(0, len(namelist), max)]
  1112. for chunk in chunklist:
  1113. stringlist = ",".join(chunk)
  1114. if self.run:
  1115. m = copy.deepcopy(self.m_mremove)
  1116. m.inputs["type"].value = map_type
  1117. m.inputs["name"].value = stringlist
  1118. m.flags["f"].value = True
  1119. # print(m.get_bash())
  1120. self.process_chain_dict["remove"].append(m.get_dict())
  1121. if self.dry_run is False:
  1122. m.run()
  1123. def check_stds(self, input, clear=False, stds_type=None, check_type=True):
  1124. """Check if input space time dataset exist in database and return its map list.
  1125. :param input: Name of space time data set as string or list of maps.
  1126. :param clear: Reset the stored conditional values to empty list.
  1127. :param check_type: Check the type of the space time dataset to match the global stds type
  1128. :param stds_type: The type of the space time dataset to be opened, if not provided
  1129. then self.stdstype will be used
  1130. :return: List of maps.
  1131. """
  1132. if isinstance(input, unicode) or isinstance(input, str):
  1133. # Check for mapset in given stds input.
  1134. if input.find("@") >= 0:
  1135. id_input = input
  1136. else:
  1137. id_input = input + "@" + self.mapset
  1138. # Create empty spacetime dataset.
  1139. if stds_type:
  1140. stds = dataset_factory(stds_type, id_input)
  1141. else:
  1142. stds = dataset_factory(self.stdstype, id_input)
  1143. # Check for occurrence of space time dataset.
  1144. if stds.is_in_db(dbif=self.dbif) is False:
  1145. raise FatalError(
  1146. _("Space time %s dataset <%s> not found")
  1147. % (stds.get_new_map_instance(None).get_type(), id_input)
  1148. )
  1149. else:
  1150. # Select temporal dataset entry from database.
  1151. stds.select(dbif=self.dbif)
  1152. if self.use_granularity:
  1153. # We create the maplist out of the map array from none-gap objects
  1154. maplist = []
  1155. map_array = stds.get_registered_maps_as_objects_by_granularity(
  1156. gran=self.granularity, dbif=self.dbif
  1157. )
  1158. for entry in map_array:
  1159. # Ignore gap objects
  1160. if entry[0].get_id() is not None:
  1161. maplist.append(entry[0])
  1162. else:
  1163. maplist = stds.get_registered_maps_as_objects(dbif=self.dbif)
  1164. # Create map_value as empty list item.
  1165. for map_i in maplist:
  1166. if "map_value" not in dir(map_i):
  1167. map_i.map_value = []
  1168. if "condition_value" not in dir(map_i):
  1169. map_i.condition_value = []
  1170. # Set and check global temporal type variable and map.
  1171. if map_i.is_time_absolute() and self.temporaltype is None:
  1172. self.temporaltype = "absolute"
  1173. elif map_i.is_time_relative() and self.temporaltype is None:
  1174. self.temporaltype = "relative"
  1175. elif map_i.is_time_absolute() and self.temporaltype == "relative":
  1176. self.msgr.fatal(
  1177. _(
  1178. "Wrong temporal type of space time dataset <%s> \
  1179. <%s> time is required"
  1180. )
  1181. % (id_input, self.temporaltype)
  1182. )
  1183. elif map_i.is_time_relative() and self.temporaltype == "absolute":
  1184. self.msgr.fatal(
  1185. _(
  1186. "Wrong temporal type of space time dataset <%s> \
  1187. <%s> time is required"
  1188. )
  1189. % (id_input, self.temporaltype)
  1190. )
  1191. elif isinstance(input, self.mapclass):
  1192. # Check if the input is a single map and return it as list with one entry.
  1193. maplist = [input]
  1194. elif isinstance(input, list):
  1195. maplist = input
  1196. # Create map_value as empty list item.
  1197. for map_i in maplist:
  1198. if "map_value" not in dir(map_i):
  1199. map_i.map_value = []
  1200. elif clear:
  1201. map_i.map_value = []
  1202. if "condition_value" not in dir(map_i):
  1203. map_i.condition_value = []
  1204. elif clear:
  1205. map_i.condition_value = []
  1206. else:
  1207. self.msgr.fatal(_("Wrong type of input " + str(input)))
  1208. # We generate a unique map id that will be used
  1209. # in the topology analysis, since the maplist can
  1210. # contain maps with equal map ids
  1211. for map in maplist:
  1212. map.uid = self.generate_map_name()
  1213. if self.debug:
  1214. print(map.get_name(), map.uid, map.get_temporal_extent_as_tuple())
  1215. return maplist
  1216. def _check_spatial_topology_entries(self, spatial_topo_list, spatial_relations):
  1217. """Check the spatial topology entries in the spatial relation list
  1218. Return True if no spatial relation list is provided or if one spatial relation
  1219. was found
  1220. :param spatial_topo_list: The spatial relations that were defined in the expression
  1221. :param spatial_relations: The spatial relations of a single map object
  1222. :return: True if a spatial topological relation was found, False if not
  1223. """
  1224. # Check spatial topology
  1225. spatial_topo_check = False
  1226. if len(spatial_topo_list) == 0:
  1227. spatial_topo_check = True
  1228. else:
  1229. for spatial_topology in spatial_topo_list:
  1230. if spatial_topology in spatial_relations.keys():
  1231. spatial_topo_check = True
  1232. if self.debug is True:
  1233. print("Spatial topology list", spatial_topo_list, spatial_topo_check)
  1234. return spatial_topo_check
  1235. def _check_spatial_topology_relation(self, spatial_topo_list, map_a, map_b):
  1236. """Check if map_b has one of the spatial topological relations to map_a that is defined
  1237. in spatial_topo_list
  1238. :param spatial_topo_list:
  1239. :param map_a:
  1240. :param map_b:
  1241. :return:
  1242. """
  1243. # Check spatial topology
  1244. spatial_topo_check = False
  1245. if len(spatial_topo_list) == 0:
  1246. spatial_topo_check = True
  1247. else:
  1248. map_a_sr = map_a.get_spatial_relations()
  1249. for spatial_topology in spatial_topo_list:
  1250. if spatial_topology in map_a_sr.keys():
  1251. if map_b in map_a_sr[spatial_topology]:
  1252. spatial_topo_check = True
  1253. if self.debug is True:
  1254. print("Spatial topology list", spatial_topo_list, spatial_topo_check)
  1255. return spatial_topo_check
  1256. def _check_topology(self, topolist):
  1257. """Check the topology definitions of the expression
  1258. :param topolist: List of strings of temporal and spatial relations.
  1259. :return: A tuple of spatial and temporal topology lists (temporal_topo_list, spatial_topo_list)
  1260. :raises: This method will raise a syntax error in case the topology name is unknown
  1261. """
  1262. temporal_topo_list = []
  1263. spatial_topo_list = []
  1264. # Check if given temporal relation are valid.
  1265. for topo in topolist:
  1266. if (
  1267. topo.upper() not in self.temporal_topology_list
  1268. and topo.upper() not in self.spatial_topology_list
  1269. ):
  1270. raise SyntaxError(
  1271. "Unpermitted topological relation name '" + topo + "'"
  1272. )
  1273. if topo.upper() in self.spatial_topology_list:
  1274. spatial_topo_list.append(topo.upper())
  1275. if topo.upper() in self.temporal_topology_list:
  1276. temporal_topo_list.append(topo.upper())
  1277. return temporal_topo_list, spatial_topo_list
  1278. def build_spatio_temporal_topology_list(
  1279. self,
  1280. maplistA,
  1281. maplistB=None,
  1282. topolist=["EQUAL"],
  1283. assign_val=False,
  1284. count_map=False,
  1285. compare_bool=False,
  1286. compop=None,
  1287. aggregate=None,
  1288. ):
  1289. """Build spatio-temporal topology for two space time data sets, copy map objects
  1290. for given relation into map list.
  1291. :param maplistA: List of maps.
  1292. :param maplistB: List of maps.
  1293. :param topolist: List of strings of spatio-temporal relations.
  1294. :param assign_val: Boolean for assigning a boolean map value based on
  1295. the map_values from the compared map list by
  1296. topological relationships.
  1297. :param count_map: Boolean if the number of topological related maps
  1298. should be returned.
  1299. :param compare_bool: Boolean for comparing boolean map values based on
  1300. related map list and comparison operator.
  1301. :param compop: Comparison operator, && or ||.
  1302. :param aggregate: Aggregation operator for relation map list, & or |.
  1303. :return: List of maps from maplistA that fulfil the topological relationships
  1304. to maplistB specified in topolist.
  1305. .. code-block:: python
  1306. # Example with two lists of maps
  1307. >>> import grass.temporal as tgis
  1308. >>> tgis.init(True)
  1309. >>> l = tgis.TemporalAlgebraParser()
  1310. >>> # Create two list of maps with equal time stamps
  1311. >>> mapsA = []
  1312. >>> mapsB = []
  1313. >>> for i in range(10):
  1314. ... idA = "a%i@B"%(i)
  1315. ... mapA = tgis.RasterDataset(idA)
  1316. ... mapA.uid = idA
  1317. ... idB = "b%i@B"%(i)
  1318. ... mapB = tgis.RasterDataset(idB)
  1319. ... mapB.uid = idB
  1320. ... check = mapA.set_relative_time(i, i + 1, "months")
  1321. ... check = mapB.set_relative_time(i, i + 1, "months")
  1322. ... mapsA.append(mapA)
  1323. ... mapsB.append(mapB)
  1324. >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB, ['EQUAL'])
  1325. >>> for map in resultlist:
  1326. ... if map.get_equal():
  1327. ... relations = map.get_equal()
  1328. ... print("Map %s has equal relation to map %s"%(map.get_name(),
  1329. ... relations[0].get_name()))
  1330. Map a0 has equal relation to map b0
  1331. Map a1 has equal relation to map b1
  1332. Map a2 has equal relation to map b2
  1333. Map a3 has equal relation to map b3
  1334. Map a4 has equal relation to map b4
  1335. Map a5 has equal relation to map b5
  1336. Map a6 has equal relation to map b6
  1337. Map a7 has equal relation to map b7
  1338. Map a8 has equal relation to map b8
  1339. Map a9 has equal relation to map b9
  1340. >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB, ['DURING'])
  1341. >>> print(resultlist)
  1342. []
  1343. >>> # Create two list of maps with equal time stamps
  1344. >>> mapsA = []
  1345. >>> mapsB = []
  1346. >>> for i in range(10):
  1347. ... idA = "a%i@B"%(i)
  1348. ... mapA = tgis.RasterDataset(idA)
  1349. ... mapA.uid = idA
  1350. ... idB = "b%i@B"%(i)
  1351. ... mapB = tgis.RasterDataset(idB)
  1352. ... mapB.uid = idB
  1353. ... check = mapA.set_relative_time(i, i + 1, "months")
  1354. ... check = mapB.set_relative_time(i, i + 2, "months")
  1355. ... mapsA.append(mapA)
  1356. ... mapsB.append(mapB)
  1357. >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB, ['starts','during'])
  1358. >>> for map in resultlist:
  1359. ... if map.get_starts():
  1360. ... relations = map.get_starts()
  1361. ... print("Map %s has start relation to map %s"%(map.get_name(),
  1362. ... relations[0].get_name()))
  1363. Map a0 has start relation to map b0
  1364. Map a1 has start relation to map b1
  1365. Map a2 has start relation to map b2
  1366. Map a3 has start relation to map b3
  1367. Map a4 has start relation to map b4
  1368. Map a5 has start relation to map b5
  1369. Map a6 has start relation to map b6
  1370. Map a7 has start relation to map b7
  1371. Map a8 has start relation to map b8
  1372. Map a9 has start relation to map b9
  1373. >>> for map in resultlist:
  1374. ... if map.get_during():
  1375. ... relations = map.get_during()
  1376. ... print("Map %s has during relation to map %s"%(map.get_name(),
  1377. ... relations[0].get_name()))
  1378. Map a0 has during relation to map b0
  1379. Map a1 has during relation to map b0
  1380. Map a2 has during relation to map b1
  1381. Map a3 has during relation to map b2
  1382. Map a4 has during relation to map b3
  1383. Map a5 has during relation to map b4
  1384. Map a6 has during relation to map b5
  1385. Map a7 has during relation to map b6
  1386. Map a8 has during relation to map b7
  1387. Map a9 has during relation to map b8
  1388. >>> # Create two list of maps with equal time stamps and map_value method.
  1389. >>> mapsA = []
  1390. >>> mapsB = []
  1391. >>> for i in range(10):
  1392. ... idA = "a%i@B"%(i)
  1393. ... mapA = tgis.RasterDataset(idA)
  1394. ... mapA.uid = idA
  1395. ... idB = "b%i@B"%(i)
  1396. ... mapB = tgis.RasterDataset(idB)
  1397. ... mapB.uid = idB
  1398. ... check = mapA.set_relative_time(i, i + 1, "months")
  1399. ... check = mapB.set_relative_time(i, i + 1, "months")
  1400. ... mapB.map_value = True
  1401. ... mapsA.append(mapA)
  1402. ... mapsB.append(mapB)
  1403. >>> # Create two list of maps with equal time stamps
  1404. >>> mapsA = []
  1405. >>> mapsB = []
  1406. >>> for i in range(10):
  1407. ... idA = "a%i@B"%(i)
  1408. ... mapA = tgis.RasterDataset(idA)
  1409. ... mapA.uid = idA
  1410. ... mapA.map_value = True
  1411. ... idB = "b%i@B"%(i)
  1412. ... mapB = tgis.RasterDataset(idB)
  1413. ... mapB.uid = idB
  1414. ... mapB.map_value = False
  1415. ... check = mapA.set_absolute_time(datetime(2000,1,i+1),
  1416. ... datetime(2000,1,i + 2))
  1417. ... check = mapB.set_absolute_time(datetime(2000,1,i+6),
  1418. ... datetime(2000,1,i + 7))
  1419. ... mapsA.append(mapA)
  1420. ... mapsB.append(mapB)
  1421. >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB)
  1422. >>> for map in resultlist:
  1423. ... print(map.get_id())
  1424. a5@B
  1425. a6@B
  1426. a7@B
  1427. a8@B
  1428. a9@B
  1429. >>> resultlist = l.build_spatio_temporal_topology_list(mapsA, mapsB, ['during'])
  1430. >>> for map in resultlist:
  1431. ... print(map.get_id())
  1432. """
  1433. # Check the topology definitions and return the list of temporal and spatial
  1434. # topological relations that must be fulfilled
  1435. temporal_topo_list, spatial_topo_list = self._check_topology(topolist=topolist)
  1436. resultdict = {}
  1437. # Create spatio-temporal topology for maplistA to maplistB.
  1438. tb = SpatioTemporalTopologyBuilder()
  1439. if len(spatial_topo_list) > 0:
  1440. # Dictionary with different spatial variables used for topology builder.
  1441. spatialdict = {"strds": "2D", "stvds": "2D", "str3ds": "3D"}
  1442. tb.build(maplistA, maplistB, spatial=spatialdict[self.stdstype])
  1443. else:
  1444. tb.build(maplistA, maplistB)
  1445. # Iterate through maps in maplistA and search for relationships given
  1446. # in topolist.
  1447. for map_i in maplistA:
  1448. if assign_val:
  1449. self.assign_bool_value(map_i, temporal_topo_list, spatial_topo_list)
  1450. elif compare_bool:
  1451. self.compare_bool_value(
  1452. map_i, compop, aggregate, temporal_topo_list, spatial_topo_list
  1453. )
  1454. temporal_relations = map_i.get_temporal_relations()
  1455. spatial_relations = map_i.get_spatial_relations()
  1456. for temporal_topology in temporal_topo_list:
  1457. if temporal_topology.upper() in temporal_relations.keys():
  1458. if (
  1459. self._check_spatial_topology_entries(
  1460. spatial_topo_list, spatial_relations
  1461. )
  1462. is True
  1463. ):
  1464. if count_map:
  1465. relationmaplist = temporal_relations[
  1466. temporal_topology.upper()
  1467. ]
  1468. gvar = GlobalTemporalVar()
  1469. gvar.td = len(relationmaplist)
  1470. if "map_value" in dir(map_i):
  1471. map_i.map_value.append(gvar)
  1472. else:
  1473. map_i.map_value = gvar
  1474. # Use unique identifier, since map names may be equal
  1475. resultdict[map_i.uid] = map_i
  1476. resultlist = resultdict.values()
  1477. # Sort list of maps chronological.
  1478. resultlist = sorted(resultlist, key=AbstractDatasetComparisonKeyStartTime)
  1479. return resultlist
  1480. def assign_bool_value(
  1481. self, map_i, temporal_topo_list=["EQUAL"], spatial_topo_list=[]
  1482. ):
  1483. """Function to assign boolean map value based on the map_values from the
  1484. compared map list by topological relationships.
  1485. :param map_i: Map object with temporal extent.
  1486. :param temporal_topo_list: List of strings for given temporal relations.
  1487. :param spatial_topo_list: List of strings for given spatial relations.
  1488. :return: Map object with conditional value that has been assigned by
  1489. relation maps that fulfil the topological relationships to
  1490. maplistB specified in temporal_topo_list.
  1491. """
  1492. temporal_relations = map_i.get_temporal_relations()
  1493. condition_value_list = []
  1494. for topo in temporal_topo_list:
  1495. if topo.upper() in temporal_relations.keys():
  1496. relationmaplist = temporal_relations[topo.upper()]
  1497. for relationmap in relationmaplist:
  1498. if (
  1499. self._check_spatial_topology_relation(
  1500. spatial_topo_list, map_i, relationmap
  1501. )
  1502. is True
  1503. ):
  1504. for boolean in relationmap.condition_value:
  1505. if isinstance(boolean, bool):
  1506. condition_value_list.append(boolean)
  1507. if self.debug:
  1508. print(
  1509. "assign_bool_value",
  1510. str(relationmap.get_temporal_extent_as_tuple())
  1511. + str(boolean),
  1512. )
  1513. if all(condition_value_list):
  1514. resultbool = True
  1515. else:
  1516. resultbool = False
  1517. map_i.condition_value = [resultbool]
  1518. return resultbool
  1519. def compare_bool_value(
  1520. self,
  1521. map_i,
  1522. compop,
  1523. aggregate,
  1524. temporal_topo_list=["EQUAL"],
  1525. spatial_topo_list=[],
  1526. ):
  1527. """Function to evaluate two map lists with boolean values by boolean
  1528. comparison operator.
  1529. :param map_i: Map object with temporal extent.
  1530. :param compop: Comparison operator, && or ||.
  1531. :param aggregate: Aggregation operator for relation map list, & or |.
  1532. :param temporal_topo_list: List of strings for given temporal relations.
  1533. :param spatial_topo_list: List of strings for given spatial relations.
  1534. :return: Map object with conditional value that has been evaluated by
  1535. comparison operators.
  1536. """
  1537. temporal_relations = map_i.get_temporal_relations()
  1538. # Build conditional list with elements from related maps and given relation operator.
  1539. leftbool = map_i.condition_value[0]
  1540. condition_value_list = [leftbool]
  1541. count = 0
  1542. for topo in temporal_topo_list:
  1543. if topo.upper() in temporal_relations.keys():
  1544. relationmaplist = temporal_relations[topo.upper()]
  1545. for relationmap in relationmaplist:
  1546. if (
  1547. self._check_spatial_topology_relation(
  1548. spatial_topo_list, map_i, relationmap
  1549. )
  1550. is True
  1551. ):
  1552. if count == 0:
  1553. condition_value_list.append(compop[0])
  1554. condition_value_list.append("(")
  1555. for boolean in relationmap.condition_value:
  1556. if isinstance(boolean, bool):
  1557. if count > 0:
  1558. condition_value_list.append(aggregate)
  1559. condition_value_list.append(boolean)
  1560. count = count + 1
  1561. if self.debug:
  1562. print(
  1563. "compare_bool_value",
  1564. map_i.get_id(),
  1565. relationmap.get_id(),
  1566. )
  1567. if count > 0:
  1568. condition_value_list.append(")")
  1569. # Convert conditional list to concatenated string and evaluate booleans.
  1570. condition_value_str = "".join(map(str, condition_value_list))
  1571. if self.debug:
  1572. print(condition_value_str)
  1573. resultbool = eval(condition_value_str)
  1574. if self.debug:
  1575. print(resultbool)
  1576. # Add boolean value to result list.
  1577. map_i.condition_value = [resultbool]
  1578. return resultbool
  1579. def eval_toperator(self, operator, optype="relation"):
  1580. """This function evaluates a string containing temporal operations.
  1581. :param operator: String of temporal operations, e.g. {!=,equal|during,l}.
  1582. :param optype: String to define operator type.
  1583. :return :List of temporal relations (equal, during), the given function
  1584. (!:) and the interval/instances (l).
  1585. .. code-block:: python
  1586. >>> import grass.temporal as tgis
  1587. >>> tgis.init()
  1588. >>> p = tgis.TemporalOperatorParser()
  1589. >>> operator = "{+, during}"
  1590. >>> p.parse(operator, optype = 'raster')
  1591. >>> print((p.relations, p.temporal, p.function))
  1592. (['during'], 'l', '+')
  1593. """
  1594. p = TemporalOperatorParser()
  1595. p.parse(operator, optype)
  1596. p.relations = [rel.upper() for rel in p.relations]
  1597. return (p.relations, p.temporal, p.function, p.aggregate)
  1598. def perform_temporal_selection(
  1599. self, maplistA, maplistB, topolist=["EQUAL"], inverse=False, assign_val=False
  1600. ):
  1601. """This function performs temporal selection operation.
  1602. :param maplistA: List of maps representing the left side of a temporal
  1603. expression.
  1604. :param maplistB: List of maps representing the right side of a temporal
  1605. expression.
  1606. :param topolist: List of strings of temporal relations.
  1607. :param inverse: Boolean value that specifies if the selection should be
  1608. inverted.
  1609. :param assign_val: Boolean for assigning a boolean map value based on
  1610. the map_values from the compared map list by
  1611. topological relationships.
  1612. :return: List of selected maps from maplistA.
  1613. .. code-block:: python
  1614. >>> import grass.temporal as tgis
  1615. >>> tgis.init()
  1616. >>> l = tgis.TemporalAlgebraParser()
  1617. >>> # Example with two lists of maps
  1618. >>> # Create two list of maps with equal time stamps
  1619. >>> mapsA = []
  1620. >>> mapsB = []
  1621. >>> for i in range(10):
  1622. ... idA = "a%i@B"%(i)
  1623. ... mapA = tgis.RasterDataset(idA)
  1624. ... mapA.uid = idA
  1625. ... idB = "b%i@B"%(i)
  1626. ... mapB = tgis.RasterDataset(idB)
  1627. ... mapB.uid = idB
  1628. ... check = mapA.set_relative_time(i, i + 1, "months")
  1629. ... check = mapB.set_relative_time(i + 5, i + 6, "months")
  1630. ... mapsA.append(mapA)
  1631. ... mapsB.append(mapB)
  1632. >>> resultlist = l.perform_temporal_selection(mapsA, mapsB, ['EQUAL'],
  1633. ... False)
  1634. >>> for map in resultlist:
  1635. ... if map.get_equal():
  1636. ... relations = map.get_equal()
  1637. ... print("Map %s has equal relation to map %s"%(map.get_name(),
  1638. ... relations[0].get_name()))
  1639. Map a5 has equal relation to map b0
  1640. Map a6 has equal relation to map b1
  1641. Map a7 has equal relation to map b2
  1642. Map a8 has equal relation to map b3
  1643. Map a9 has equal relation to map b4
  1644. >>> resultlist = l.perform_temporal_selection(mapsA, mapsB, ['EQUAL'],
  1645. ... True)
  1646. >>> for map in resultlist:
  1647. ... if not map.get_equal():
  1648. ... print("Map %s has no equal relation to mapset mapsB"%(map.get_name()))
  1649. Map a0 has no equal relation to mapset mapsB
  1650. Map a1 has no equal relation to mapset mapsB
  1651. Map a2 has no equal relation to mapset mapsB
  1652. Map a3 has no equal relation to mapset mapsB
  1653. Map a4 has no equal relation to mapset mapsB
  1654. """
  1655. if not inverse:
  1656. topolist = self.build_spatio_temporal_topology_list(
  1657. maplistA, maplistB, topolist, assign_val=assign_val
  1658. )
  1659. resultlist = topolist
  1660. else:
  1661. topolist = self.build_spatio_temporal_topology_list(
  1662. maplistA, maplistB, topolist, assign_val=assign_val
  1663. )
  1664. resultlist = []
  1665. for map_i in maplistA:
  1666. if map_i not in topolist:
  1667. resultlist.append(map_i)
  1668. # if assign_val:
  1669. # if "condition_value" in dir(map_i):
  1670. # map_i.condition_value.append(False)
  1671. # Sort list of maps chronological.
  1672. resultlist = sorted(resultlist, key=AbstractDatasetComparisonKeyStartTime)
  1673. return resultlist
  1674. def set_granularity(self, maplistA, maplistB, toperator="l", topolist=["EQUAL"]):
  1675. """This function sets the temporal extends of a list of maps based on
  1676. another map list.
  1677. :param maplistB: List of maps.
  1678. :param maplistB: List of maps.
  1679. :param toperator: String containing the temporal operator: l, r, d, i, u.
  1680. :param topolist: List of topological relations.
  1681. :return: List of maps with the new temporal extends.
  1682. .. code-block:: python
  1683. >>> import grass.temporal as tgis
  1684. >>> tgis.init()
  1685. >>> p = tgis.TemporalAlgebraParser()
  1686. >>> # Create two list of maps with equal time stamps
  1687. >>> mapsA = []
  1688. >>> mapsB = []
  1689. >>> for i in range(10):
  1690. ... idA = "a%i@B"%(i)
  1691. ... mapA = tgis.RasterDataset(idA)
  1692. ... mapA.uid = idA
  1693. ... idB = "b%i@B"%(i)
  1694. ... mapB = tgis.RasterDataset(idB)
  1695. ... mapB.uid = idB
  1696. ... check = mapA.set_relative_time(i, i + 1, "months")
  1697. ... check = mapB.set_relative_time(i*2, i*2 + 2, "months")
  1698. ... mapsA.append(mapA)
  1699. ... mapsB.append(mapB)
  1700. >>> resultlist = p.set_granularity(mapsA, mapsB, toperator = "u", topolist = ["during"])
  1701. >>> for map in resultlist:
  1702. ... start,end,unit = map.get_relative_time()
  1703. ... print(map.get_id() + ' - start: ' + str(start) + ' end: ' + str(end))
  1704. a1@B - start: 0 end: 2
  1705. a0@B - start: 0 end: 2
  1706. a3@B - start: 2 end: 4
  1707. a2@B - start: 2 end: 4
  1708. a5@B - start: 4 end: 6
  1709. a4@B - start: 4 end: 6
  1710. a7@B - start: 6 end: 8
  1711. a6@B - start: 6 end: 8
  1712. a9@B - start: 8 end: 10
  1713. a8@B - start: 8 end: 10
  1714. """
  1715. topologylist = [
  1716. "EQUAL",
  1717. "FOLLOWS",
  1718. "PRECEDES",
  1719. "OVERLAPS",
  1720. "OVERLAPPED",
  1721. "DURING",
  1722. "STARTS",
  1723. "FINISHES",
  1724. "CONTAINS",
  1725. "STARTED",
  1726. "FINISHED",
  1727. ]
  1728. for topo in topolist:
  1729. if topo.upper() not in topologylist:
  1730. raise SyntaxError("Unpermitted temporal relation name '" + topo + "'")
  1731. # Create temporal topology for maplistA to maplistB.
  1732. tb = SpatioTemporalTopologyBuilder()
  1733. # Dictionary with different spatial variables used for topology builder.
  1734. spatialdict = {"strds": "2D", "stvds": "2D", "str3ds": "3D"}
  1735. # Build spatial temporal topology for maplistB to maplistB.
  1736. if self.spatial:
  1737. tb.build(maplistA, maplistB, spatial=spatialdict[self.stdstype])
  1738. else:
  1739. tb.build(maplistA, maplistB)
  1740. resultdict = {}
  1741. # Iterate through maps in maplistA and search for relationships given
  1742. # in topolist.
  1743. for map_i in maplistA:
  1744. tbrelations = map_i.get_temporal_relations()
  1745. map_extent = map_i.get_temporal_extent()
  1746. map_start = map_extent.get_start_time()
  1747. map_end = map_extent.get_end_time()
  1748. unchanged = True
  1749. for topo in topolist:
  1750. if topo.upper() in tbrelations.keys():
  1751. relationmaplist = tbrelations[topo.upper()]
  1752. for relationmap in relationmaplist:
  1753. newextent = None
  1754. if toperator == "i":
  1755. newextent = map_i.temporal_intersection(relationmap)
  1756. elif toperator == "u":
  1757. newextent = map_i.temporal_union(relationmap)
  1758. elif toperator == "d":
  1759. newextent = map_i.temporal_disjoint_union(relationmap)
  1760. elif toperator == "l":
  1761. newextent = map_i.get_temporal_extent()
  1762. elif toperator == "r":
  1763. newextent = relationmap.get_temporal_extent()
  1764. if newextent is not None:
  1765. start = newextent.get_start_time()
  1766. end = newextent.get_end_time()
  1767. # print(map_i.get_id() + ' - start: ' + str(start) + ' end: ' + str(end))
  1768. # Track changes in temporal extents of maps.
  1769. if map_start != start or map_end != end:
  1770. unchanged = False
  1771. if map_i.is_time_absolute():
  1772. map_i.set_absolute_time(start, end)
  1773. else:
  1774. relunit = map_i.get_relative_time_unit()
  1775. map_i.set_relative_time(int(start), int(end), relunit)
  1776. resultdict[map_i.get_id()] = map_i
  1777. else:
  1778. if self.debug:
  1779. print("Topologic relation: " + topo.upper() + " not found.")
  1780. resultdict[map_i.get_id()] = map_i
  1781. if unchanged is True:
  1782. if self.debug:
  1783. print(
  1784. "Leave temporal extend of result map: "
  1785. + map_i.get_map_id()
  1786. + " unchanged."
  1787. )
  1788. resultlist = resultdict.values()
  1789. # Sort list of maps chronological.
  1790. resultlist = sorted(resultlist, key=AbstractDatasetComparisonKeyStartTime)
  1791. # Get relations to maplistB per map in A.
  1792. # Loop over all relations from list
  1793. # temporal extent = map.temporal_intersection(map)
  1794. # if temporal extend is None = delete map.
  1795. return resultlist
  1796. def get_temporal_func_dict(self, map):
  1797. """This function creates a dictionary containing temporal functions for a
  1798. map dataset with time stamp.
  1799. :param map: Map object with time stamps.
  1800. :return: Dictionary with temporal functions for given input map.
  1801. .. code-block:: python
  1802. >>> import grass.temporal as tgis
  1803. >>> import datetime
  1804. >>> tgis.init()
  1805. >>> l = tgis.TemporalAlgebraParser()
  1806. >>> # Example with one list of maps
  1807. >>> # Create one list of maps with equal time stamps
  1808. >>> for i in range(1):
  1809. ... idA = "a%i@B"%(i)
  1810. ... mapA = tgis.RasterDataset(idA)
  1811. ... mapA.uid = idA
  1812. ... check = mapA.set_absolute_time(datetime.datetime(2000,1,1),
  1813. ... datetime.datetime(2000,10,1))
  1814. ... tfuncdict = l.get_temporal_func_dict(mapA)
  1815. >>> print(tfuncdict["START_YEAR"])
  1816. 2000
  1817. >>> print(tfuncdict["START_TIME"])
  1818. 00:00:00
  1819. >>> print(tfuncdict["START_DATE"])
  1820. 2000-01-01
  1821. >>> print(tfuncdict["START_DATETIME"])
  1822. 2000-01-01 00:00:00
  1823. """
  1824. tvardict = {
  1825. "START_DOY": None,
  1826. "START_DOW": None,
  1827. "START_YEAR": None,
  1828. "START_MONTH": None,
  1829. "START_WEEK": None,
  1830. "START_DAY": None,
  1831. "START_HOUR": None,
  1832. "START_MINUTE": None,
  1833. "START_SECOND": None,
  1834. "END_DOY": None,
  1835. "END_DOW": None,
  1836. "END_YEAR": None,
  1837. "END_MONTH": None,
  1838. "END_WEEK": None,
  1839. "END_DAY": None,
  1840. "END_HOUR": None,
  1841. "END_MINUTE": None,
  1842. "END_SECOND": None,
  1843. "START_DATE": None,
  1844. "START_DATETIME": None,
  1845. "START_TIME": None,
  1846. "END_DATE": None,
  1847. "END_DATETIME": None,
  1848. "END_TIME": None,
  1849. }
  1850. # Compute temporal function only for maps with absolute time reference.
  1851. if map.is_time_absolute:
  1852. # Get datetime of map.
  1853. start, end = map.get_absolute_time()
  1854. # Compute DOY via time deltas.
  1855. yearstart = datetime(start.year, 1, 1)
  1856. yearend = datetime(end.year, 1, 1)
  1857. deltastart = start - yearstart
  1858. deltaend = end - yearend
  1859. # Evaluate datetime objects and fill in into dict.
  1860. tvardict["START_DOY"] = deltastart.days + 1
  1861. tvardict["START_DOW"] = start.isoweekday()
  1862. tvardict["START_YEAR"] = start.year
  1863. tvardict["START_MONTH"] = start.month
  1864. tvardict["START_WEEK"] = start.isocalendar()[1]
  1865. tvardict["START_DAY"] = start.day
  1866. tvardict["START_HOUR"] = start.hour
  1867. tvardict["START_MINUTE"] = start.minute
  1868. tvardict["START_SECOND"] = start.second
  1869. tvardict["END_DOY"] = deltaend.days + 1
  1870. tvardict["END_DOW"] = end.isoweekday()
  1871. tvardict["END_YEAR"] = end.year
  1872. tvardict["END_MONTH"] = end.month
  1873. tvardict["END_WEEK"] = end.isocalendar()[1]
  1874. tvardict["END_DAY"] = end.day
  1875. tvardict["END_HOUR"] = end.hour
  1876. tvardict["END_MINUTE"] = end.minute
  1877. tvardict["END_SECOND"] = end.second
  1878. tvardict["START_DATE"] = start.date()
  1879. tvardict["START_DATETIME"] = start
  1880. tvardict["START_TIME"] = start.time()
  1881. tvardict["END_DATE"] = end.date()
  1882. tvardict["END_DATETIME"] = end
  1883. tvardict["END_TIME"] = end.time()
  1884. if not map.is_time_absolute:
  1885. tvardict["START_DATE"] = start.date()
  1886. tvardict["START_DATETIME"] = start
  1887. tvardict["START_TIME"] = start.time()
  1888. tvardict["END_DATE"] = end.date()
  1889. tvardict["END_DATETIME"] = end
  1890. tvardict["END_TIME"] = end.time()
  1891. # core.fatal(_("The temporal functions for map <%s> only "
  1892. # "supported for absolute time." % (str(map.get_id()))))
  1893. return tvardict
  1894. def eval_datetime_str(self, tfuncval, comp, value):
  1895. # Evaluate date object comparison expression.
  1896. if comp == "<":
  1897. boolname = eval(str(tfuncval < value))
  1898. elif comp == ">":
  1899. boolname = eval(str(tfuncval > value))
  1900. elif comp == "==":
  1901. boolname = eval(str(tfuncval == value))
  1902. elif comp == "<=":
  1903. boolname = eval(str(tfuncval <= value))
  1904. elif comp == ">=":
  1905. boolname = eval(str(tfuncval >= value))
  1906. elif comp == "!=":
  1907. boolname = eval(str(tfuncval != value))
  1908. return boolname
  1909. def eval_global_var(self, gvar, maplist):
  1910. """This function evaluates a global variable expression for a map list.
  1911. For example: start_day() > 5 , end_month() == 2.
  1912. :param gvar: Object of type GlobalTemporalVar containing temporal.
  1913. :param maplist: List of map objects.
  1914. :return: List of maps from maplist with added conditional boolean values.
  1915. """
  1916. boollist = []
  1917. # Loop over maps of input map list.
  1918. for map_i in maplist:
  1919. # Get dictionary with temporal variables for the map.
  1920. tfuncdict = self.get_temporal_func_dict(map_i)
  1921. # Get value from global variable.
  1922. value = gvar.value
  1923. # Get comparison operator from global variable, like <, >, <=, >=, ==, !=
  1924. comp_op = gvar.compop
  1925. # Get temporal function name for global variable.
  1926. tfunc = gvar.tfunc.upper()
  1927. # Get value for function name from dictionary.
  1928. tfuncval = tfuncdict[tfunc]
  1929. # Check if value has to be transferred to datetime object for comparison.
  1930. if tfunc in [
  1931. "START_DATE",
  1932. "END_DATE",
  1933. "START_TIME",
  1934. "END_TIME",
  1935. "START_DATETIME",
  1936. "END_DATETIME",
  1937. ]:
  1938. timeobj = string_to_datetime(value.replace('"', ""))
  1939. value = timeobj.date()
  1940. boolname = self.eval_datetime_str(tfuncval, comp_op, value)
  1941. else:
  1942. boolname = eval(str(tfuncval) + comp_op + str(value))
  1943. # Add conditional boolean value to the map.
  1944. if "condition_value" in dir(map_i):
  1945. map_i.condition_value.append(boolname)
  1946. else:
  1947. map_i.condition_value = boolname
  1948. return maplist
  1949. def eval_map_list(self, maplist, thenlist, topolist=["EQUAL"]):
  1950. """This function transfers boolean values from temporal expression
  1951. from one map list to another by their topology. These boolean
  1952. values are added to the maps as condition_value.
  1953. :param maplist: List of map objects containing boolean map values.
  1954. :param thenlist: List of map objects where the boolean values
  1955. should be added.
  1956. :return: List of maps from thenlist with added conditional boolean values.
  1957. """
  1958. # Get topology of then statement map list in relation to the other maplist
  1959. # and assign boolean values of the maplist to the thenlist.
  1960. containlist = self.perform_temporal_selection(
  1961. thenlist, maplist, assign_val=True, topolist=topolist
  1962. )
  1963. # Inverse selection of maps from thenlist and assigning False values.
  1964. # excludelist = self.perform_temporal_selection(thenlist, maplist,
  1965. # assign_val = True,
  1966. # inverse = True,
  1967. # topolist = topolist)
  1968. # Combining the selection and inverse selection list.
  1969. resultlist = containlist # + excludelist
  1970. return resultlist
  1971. def build_condition_list(self, tvarexpr, thenlist, topolist=["EQUAL"]):
  1972. """This function evaluates temporal variable expressions of a conditional
  1973. expression in two steps.
  1974. At first it combines stepwise the single conditions by their relations with LALR.
  1975. In this process sub condition map lists will be created which will include
  1976. information of the underlying single conditions. Important: The temporal
  1977. relations between conditions are evaluated by implicit aggregation.
  1978. In the second step the aggregated condition map list will be compared with the
  1979. map list of conclusion statements by the given temporal relation.
  1980. The result is written as 'condition_value' attribute to the resulting map objects.
  1981. These attribute consists of boolean expressions and operators which can be
  1982. evaluated with the eval_condition_list function.
  1983. [True, '||', False, '&&', True]
  1984. For example: td(A) == 1 && start_day() > 5 --> [True || False]
  1985. (for one map.condition_value in a then map list)
  1986. :param tvarexpr: List of GlobalTemporalVar objects and map lists.
  1987. The list is constructed by the TemporalAlgebraParser
  1988. in order of expression evaluation in the parser.
  1989. :param thenlist: Map list object of the conclusion statement.
  1990. It will be compared and evaluated by the conditions.
  1991. :param topolist: List of temporal relations between the conditions and the
  1992. conclusions.
  1993. :return: Map list with conditional values for all temporal expressions.
  1994. """
  1995. # Evaluate the temporal variable expression and compute the temporal combination
  1996. # of conditions.
  1997. # Check if the input expression is a valid single global variable.
  1998. if isinstance(tvarexpr, GlobalTemporalVar) and tvarexpr.get_type() == "global":
  1999. # Use method eval_global_var to evaluate expression.
  2000. resultlist = self.eval_global_var(tvarexpr, thenlist)
  2001. # Check if a given list is a list of maps.
  2002. elif all([issubclass(type(ele), AbstractMapDataset) for ele in tvarexpr]):
  2003. # Use method eval_map_list to evaluate map_list in comparison to thenlist.
  2004. resultlist = self.eval_map_list(tvarexpr, thenlist, topolist)
  2005. elif len(tvarexpr) % 2 != 0:
  2006. # Define variables for map list comparisons.
  2007. # self.msgr.fatal("Condition list is not complete. Elements missing")
  2008. for iter in range(len(tvarexpr)):
  2009. expr = tvarexpr[iter]
  2010. operator = tvarexpr[iter + 1]
  2011. relexpr = tvarexpr[iter + 2]
  2012. if all([issubclass(type(ele), list) for ele in [expr, relexpr]]):
  2013. resultlist = self.build_spatio_temporal_topology_list(expr, relexpr)
  2014. # Loop through the list, search for map lists or global variables.
  2015. for expr in tvarexpr:
  2016. if isinstance(expr, list):
  2017. if all([issubclass(type(ele), AbstractMapDataset) for ele in expr]):
  2018. # Use method eval_map_list to evaluate map_list
  2019. resultlist = self.eval_map_list(expr, thenlist, topolist)
  2020. else:
  2021. # Recursive function call to look into nested list elements.
  2022. self.build_condition_list(expr, thenlist)
  2023. elif isinstance(expr, GlobalTemporalVar):
  2024. # Use according functions for different global variable types.
  2025. if expr.get_type() == "operator":
  2026. if all(["condition_value" in dir(map_i) for map_i in thenlist]):
  2027. # Add operator string to the condition list.
  2028. [
  2029. map_i.condition_value.extend(expr.get_type_value())
  2030. for map_i in thenlist
  2031. ]
  2032. if expr.get_type() == "global":
  2033. # Use method eval_global_var to evaluate expression.
  2034. resultlist = self.eval_global_var(expr, thenlist)
  2035. # Sort resulting list of maps chronological.
  2036. resultlist = sorted(resultlist, key=AbstractDatasetComparisonKeyStartTime)
  2037. return resultlist
  2038. def eval_condition_list(self, maplist, inverse=False):
  2039. """This function evaluates conditional values of a map list.
  2040. A recursive function is used to evaluate comparison statements
  2041. from left to right in the given conditional list.
  2042. For example::
  2043. - [True, '||', False, '&&', True] -> True
  2044. - [True, '||', False, '&&', False] -> False
  2045. - [True, '&&', False, '&&', True] -> False
  2046. - [False, '||', True, '||', False] -> True
  2047. - [False, '&&', True, '&&', True] -> False
  2048. - [True, '&&', True, '&&', True] -> True
  2049. - [True, '&&', True] -> True
  2050. - [True, '&&', False] -> False
  2051. - [False, '||', True] -> True
  2052. :param tvarexpr: List of GlobalTemporalVar objects and map lists.
  2053. The list is constructed by the TemporalAlgebraParser
  2054. in order of expression evaluation in the parser.
  2055. :return: Map list with conditional values for all temporal expressions.
  2056. """
  2057. def recurse_compare(conditionlist):
  2058. for ele in conditionlist:
  2059. if ele == "||":
  2060. ele_index = conditionlist.index(ele)
  2061. right = conditionlist.pop(ele_index)
  2062. left = conditionlist.pop(ele_index - 2)
  2063. if any([left, right]):
  2064. result = True
  2065. else:
  2066. result = False
  2067. conditionlist[ele_index - 2] = result
  2068. recurse_compare(conditionlist)
  2069. if ele == "&&":
  2070. ele_index = conditionlist.index(ele)
  2071. right = conditionlist.pop(ele_index)
  2072. left = conditionlist.pop(ele_index - 2)
  2073. if all([left, right]):
  2074. result = True
  2075. else:
  2076. result = False
  2077. conditionlist[ele_index - 2] = result
  2078. recurse_compare(conditionlist)
  2079. resultlist = conditionlist
  2080. return resultlist
  2081. resultlist = []
  2082. inverselist = []
  2083. # Loop through map list and evaluate conditional values.
  2084. for map_i in maplist:
  2085. if "condition_value" in dir(map_i):
  2086. # Get condition values from map object.
  2087. conditionlist = map_i.condition_value
  2088. # Evaluate conditions in list with recursive function.
  2089. resultbool = recurse_compare(conditionlist)
  2090. # Set conditional value of map to resulting boolean.
  2091. map_i.condition_value = resultbool
  2092. # Add all maps that fulfill the conditions to result list.
  2093. if resultbool[0]:
  2094. resultlist.append(map_i)
  2095. if self.debug:
  2096. print(map_i.get_map_id() + " " + str(map_i.condition_value))
  2097. else:
  2098. inverselist.append(map_i)
  2099. if inverse:
  2100. return inverselist
  2101. else:
  2102. return resultlist
  2103. def p_statement_assign(self, t):
  2104. # The expression should always return a list of maps
  2105. # This function starts all the work and is the last one that is called from the parser
  2106. """
  2107. statement : stds EQUALS expr
  2108. """
  2109. if self.run:
  2110. dbif, connection_state_changed = init_dbif(self.dbif)
  2111. map_type = None
  2112. if isinstance(t[3], list):
  2113. num = len(t[3])
  2114. count = 0
  2115. register_list = []
  2116. if num > 0:
  2117. # Compute the granularity for suffix creation
  2118. granularity = None
  2119. if len(t[3]) > 0 and self.time_suffix == "gran":
  2120. map_i = t[3][0]
  2121. if map_i.is_time_absolute() is True:
  2122. granularity = compute_absolute_time_granularity(t[3])
  2123. # compute the size of the numerical suffix
  2124. num = len(t[3])
  2125. leadzero = len(str(num))
  2126. if self.dry_run is False:
  2127. process_queue = pymod.ParallelModuleQueue(int(self.nprocs))
  2128. for map_i in t[3]:
  2129. # Check if the map type and stds type are compatible
  2130. if count == 0:
  2131. maps_stds_type = map_i.get_new_stds_instance(
  2132. None
  2133. ).get_type()
  2134. map_type = map_i.get_type()
  2135. if maps_stds_type != self.stdstype:
  2136. self.msgr.warning(
  2137. _(
  2138. "The resulting space time dataset type <%(a)s> is "
  2139. "different from the requested type <%(b)s>"
  2140. % ({"a": maps_stds_type, "b": self.stdstype})
  2141. )
  2142. )
  2143. else:
  2144. map_type_2 = map_i.get_type()
  2145. if map_type != map_type_2:
  2146. self.msgr.fatal(
  2147. _(
  2148. "Maps that should be registered in the "
  2149. "resulting space time dataset have different types."
  2150. )
  2151. )
  2152. count += 1
  2153. # Test if temporal extents was been modified by temporal
  2154. # relation operators (i|r).
  2155. # If it was modified, then the map will be copied
  2156. map_a_extent = map_i.get_temporal_extent_as_tuple()
  2157. map_b = map_i.get_new_instance(map_i.get_id())
  2158. map_b.select(dbif)
  2159. map_b_extent = map_b.get_temporal_extent_as_tuple()
  2160. if map_a_extent != map_b_extent:
  2161. # Create new map with basename
  2162. newident = create_numeric_suffix(
  2163. self.basename, count, "%0" + str(leadzero)
  2164. )
  2165. if (
  2166. map_i.is_time_absolute() is True
  2167. and self.time_suffix
  2168. and granularity is not None
  2169. and self.time_suffix == "gran"
  2170. ):
  2171. suffix = create_suffix_from_datetime(
  2172. map_i.temporal_extent.get_start_time(), granularity
  2173. )
  2174. newident = "{ba}_{su}".format(
  2175. ba=self.basename, su=suffix
  2176. )
  2177. # If set use the time suffix to create the map name
  2178. elif (
  2179. map_i.is_time_absolute() is True
  2180. and self.time_suffix
  2181. and self.time_suffix == "time"
  2182. ):
  2183. suffix = create_time_suffix(map_i)
  2184. newident = "{ba}_{su}".format(
  2185. ba=self.basename, su=suffix
  2186. )
  2187. map_result = map_i.get_new_instance(
  2188. newident + "@" + self.mapset
  2189. )
  2190. if map_result.map_exists() and self.overwrite is False:
  2191. self.msgr.fatal(
  2192. "Error raster maps with basename %s exist. "
  2193. "Use --o flag to overwrite existing file"
  2194. % map_i.get_id()
  2195. )
  2196. map_result.set_temporal_extent(map_i.get_temporal_extent())
  2197. map_result.set_spatial_extent(map_i.get_spatial_extent())
  2198. # Attention we attach a new attribute
  2199. map_result.is_new = True
  2200. register_list.append(map_result)
  2201. # Copy the map
  2202. m = copy.deepcopy(self.m_copy)
  2203. m.flags["overwrite"].value = self.overwrite
  2204. if map_i.get_type() == "raster":
  2205. m.inputs["raster"].value = map_i.get_id(), newident
  2206. elif map_i.get_type() == "raster3d":
  2207. m.inputs["raster_3d"].value = map_i.get_id(), newident
  2208. elif map_i.get_type() == "vector":
  2209. m.inputs["vector"].value = map_i.get_id(), newident
  2210. # Add the process description to the dict
  2211. self.process_chain_dict["processes"].append(m.get_dict())
  2212. if self.dry_run is False:
  2213. process_queue.put(m)
  2214. else:
  2215. register_list.append(map_i)
  2216. # Wait for running processes
  2217. if self.dry_run is False:
  2218. process_queue.wait()
  2219. # Open connection to temporal database.
  2220. # Create result space time dataset based on the map stds type
  2221. if self.dry_run is False:
  2222. resultstds = open_new_stds(
  2223. t[1],
  2224. maps_stds_type,
  2225. "absolute",
  2226. t[1],
  2227. t[1],
  2228. "mean",
  2229. self.dbif,
  2230. overwrite=self.overwrite,
  2231. )
  2232. for map_i in register_list:
  2233. # Get meta data from grass database.
  2234. map_i.load()
  2235. # Put the map into the process dictionary
  2236. start, end = map_i.get_temporal_extent_as_tuple()
  2237. self.process_chain_dict["register"].append(
  2238. (map_i.get_name(), str(start), str(end))
  2239. )
  2240. if hasattr(map_i, "is_new") is True:
  2241. # Do not register empty maps if not required
  2242. # In case of a null map continue, do not register null maps
  2243. if (
  2244. map_i.get_type() == "raster"
  2245. or map_i.get_type() == "raster3d"
  2246. ):
  2247. if (
  2248. map_i.metadata.get_min() is None
  2249. and map_i.metadata.get_max() is None
  2250. ):
  2251. if not self.register_null:
  2252. self.removable_maps[map_i.get_name()] = map_i
  2253. continue
  2254. if map_i.is_in_db(dbif) and self.overwrite:
  2255. # Update map in temporal database.
  2256. if self.dry_run is False:
  2257. map_i.update_all(dbif)
  2258. elif map_i.is_in_db(dbif) and self.overwrite is False:
  2259. # Raise error if map exists and no overwrite flag is given.
  2260. self.msgr.fatal(
  2261. "Error map %s exist in temporal database. "
  2262. "Use overwrite flag." % map_i.get_map_id()
  2263. )
  2264. else:
  2265. # Insert map into temporal database.
  2266. if self.dry_run is False:
  2267. map_i.insert(dbif)
  2268. # Register map in result space time dataset.
  2269. if self.dry_run is False:
  2270. success = resultstds.register_map(map_i, dbif)
  2271. if not success:
  2272. self.msgr.warning(
  2273. "Unabe to register map layers "
  2274. "in STDS %s" % (t[1])
  2275. )
  2276. if self.dry_run is False:
  2277. resultstds.update_from_registered_maps(dbif)
  2278. self.process_chain_dict["STDS"]["name"] = t[1]
  2279. self.process_chain_dict["STDS"]["stdstype"] = self.stdstype
  2280. self.process_chain_dict["STDS"]["temporal_type"] = "absolute"
  2281. elif num == 0:
  2282. self.msgr.warning(
  2283. "Empty result space time dataset. "
  2284. "No map has been registered in %s" % (t[1])
  2285. )
  2286. # Open connection to temporal database.
  2287. # Create result space time dataset.
  2288. if self.dry_run is False:
  2289. resultstds = open_new_stds(
  2290. t[1],
  2291. self.stdstype,
  2292. "absolute",
  2293. t[1],
  2294. t[1],
  2295. "mean",
  2296. dbif,
  2297. overwrite=self.overwrite,
  2298. )
  2299. if connection_state_changed:
  2300. dbif.close()
  2301. t[0] = t[3]
  2302. else:
  2303. t[0] = t[3]
  2304. if self.debug:
  2305. print(t[1], "=", t[3])
  2306. def p_stds_1(self, t):
  2307. # Definition of a space time dataset
  2308. """
  2309. stds : NAME
  2310. """
  2311. t[0] = t[1]
  2312. def p_paren_expr(self, t):
  2313. """expr : LPAREN expr RPAREN"""
  2314. t[0] = t[2]
  2315. def p_number(self, t):
  2316. """number : INT
  2317. | FLOAT
  2318. """
  2319. t[0] = t[1]
  2320. def p_expr_strds_function(self, t):
  2321. # Explicitly specify a space time raster dataset
  2322. # R = A : strds(B)
  2323. """
  2324. expr : STRDS LPAREN stds RPAREN
  2325. """
  2326. if self.run:
  2327. t[0] = self.check_stds(t[3], stds_type="strds", check_type=False)
  2328. else:
  2329. t[0] = t[3]
  2330. if self.debug:
  2331. print("Opening STRDS: ", t[0])
  2332. def p_expr_str3ds_function(self, t):
  2333. # Explicitly specify a space time raster dataset
  2334. # R = A : str3ds(B)
  2335. """
  2336. expr : STR3DS LPAREN stds RPAREN
  2337. """
  2338. if self.run:
  2339. t[0] = self.check_stds(t[3], stds_type="str3ds", check_type=False)
  2340. else:
  2341. t[0] = t[3]
  2342. if self.debug:
  2343. print("Opening STR3DS: ", t[0])
  2344. def p_expr_stvds_function(self, t):
  2345. # Explicitly specify a space time vector dataset
  2346. # R = A : stvds(B)
  2347. """
  2348. expr : STVDS LPAREN stds RPAREN
  2349. """
  2350. if self.run:
  2351. print(t[3])
  2352. t[0] = self.check_stds(t[3], stds_type="stvds", check_type=False)
  2353. else:
  2354. t[0] = t[3]
  2355. if self.debug:
  2356. print("Opening STVDS: ", t[0])
  2357. def p_expr_tmap_function(self, t):
  2358. # Add a single map.
  2359. # Only the spatial extent of the map is evaluated.
  2360. # Temporal extent is not existing.
  2361. # Examples:
  2362. # R = tmap(A)
  2363. """
  2364. expr : TMAP LPAREN stds RPAREN
  2365. """
  2366. if self.run:
  2367. # Check input map.
  2368. input = t[3]
  2369. if not isinstance(input, list):
  2370. # Check for mapset in given stds input.
  2371. if input.find("@") >= 0:
  2372. id_input = input
  2373. else:
  2374. id_input = input + "@" + self.mapset
  2375. # Create empty map dataset.
  2376. map_i = dataset_factory(self.maptype, id_input)
  2377. # Check for occurrence of space time dataset.
  2378. if map_i.map_exists() is False:
  2379. raise FatalError(
  2380. _("%s map <%s> not found in GRASS spatial database")
  2381. % (map_i.get_type(), id_input)
  2382. )
  2383. else:
  2384. # Select dataset entry from database.
  2385. map_i.select(dbif=self.dbif)
  2386. else:
  2387. raise FatalError(
  2388. _(
  2389. "Wrong map type. TMAP only supports single "
  2390. "maps that are registered in the temporal GRASS database"
  2391. )
  2392. )
  2393. # Return map object.
  2394. t[0] = [map_i]
  2395. else:
  2396. t[0] = "tmap(", t[3], ")"
  2397. if self.debug:
  2398. print("tmap(", t[3], ")")
  2399. def p_expr_tmerge_function(self, t):
  2400. # Merge two maplists of same STDS type into a result map list.
  2401. # Only possible for same data types!
  2402. # Examples:
  2403. # R = merge(A, B)
  2404. """
  2405. expr : MERGE LPAREN stds COMMA stds RPAREN
  2406. | MERGE LPAREN expr COMMA stds RPAREN
  2407. | MERGE LPAREN stds COMMA expr RPAREN
  2408. | MERGE LPAREN expr COMMA expr RPAREN
  2409. """
  2410. if self.run:
  2411. # Check input map.
  2412. maplistA = self.check_stds(t[3])
  2413. maplistB = self.check_stds(t[5])
  2414. # Check empty lists.
  2415. if len(maplistA) == 0 and len(maplistB) == 0:
  2416. self.msgr.warning(_("Merging empty map lists"))
  2417. resultlist = maplistA + maplistB
  2418. elif len(maplistA) == 0:
  2419. self.msgr.message(
  2420. _(
  2421. "First Map list is empty, can't merge it. Return only last map list"
  2422. )
  2423. )
  2424. resultlist = maplistB
  2425. elif len(maplistB) == 0:
  2426. self.msgr.message(
  2427. _(
  2428. "Second Map list is empty, can't merge it. Return only first map list"
  2429. )
  2430. )
  2431. resultlist = maplistA
  2432. else:
  2433. # Check for identical data types in map lists.
  2434. typeA = maplistA[0].metadata.get_datatype()
  2435. typeB = maplistB[0].metadata.get_datatype()
  2436. if typeA != typeB:
  2437. raise FatalError(
  2438. _(
  2439. "Space time datasets to merge must have the same temporal type"
  2440. )
  2441. )
  2442. resultlist = maplistA + maplistB
  2443. # Return map list.
  2444. t[0] = resultlist
  2445. else:
  2446. t[0] = "merge(", t[3], ",", t[5], ")"
  2447. if self.debug:
  2448. print("merge(", t[3], ",", t[5], ")")
  2449. def p_t_hash(self, t):
  2450. """
  2451. t_hash_var : stds HASH stds
  2452. | expr HASH stds
  2453. | stds HASH expr
  2454. | expr HASH expr
  2455. """
  2456. if self.run:
  2457. maplistA = self.check_stds(t[1])
  2458. maplistB = self.check_stds(t[3])
  2459. resultlist = self.build_spatio_temporal_topology_list(
  2460. maplistA, maplistB, count_map=True
  2461. )
  2462. t[0] = resultlist
  2463. def p_t_hash2(self, t):
  2464. """
  2465. t_hash_var : stds T_HASH_OPERATOR stds
  2466. | stds T_HASH_OPERATOR expr
  2467. | expr T_HASH_OPERATOR stds
  2468. | expr T_HASH_OPERATOR expr
  2469. """
  2470. if self.run:
  2471. maplistA = self.check_stds(t[1])
  2472. maplistB = self.check_stds(t[3])
  2473. topolist = self.eval_toperator(t[2], optype="hash")[0]
  2474. resultlist = self.build_spatio_temporal_topology_list(
  2475. maplistA, maplistB, topolist, count_map=True
  2476. )
  2477. t[0] = resultlist
  2478. def p_t_hash_paren(self, t):
  2479. """
  2480. t_hash_var : LPAREN t_hash_var RPAREN
  2481. """
  2482. t[0] = t[2]
  2483. def p_t_td_var(self, t):
  2484. """
  2485. t_td_var : TD LPAREN stds RPAREN
  2486. | TD LPAREN expr RPAREN
  2487. """
  2488. if self.run:
  2489. maplist = self.check_stds(t[3])
  2490. for map_i in maplist:
  2491. if map_i.is_time_absolute:
  2492. start, end = map_i.get_absolute_time()
  2493. if end is not None:
  2494. td = time_delta_to_relative_time(end - start)
  2495. else:
  2496. start, end, unit = map_i.get_relative_time()
  2497. if end is not None:
  2498. td = end - start
  2499. if "map_value" in dir(map_i):
  2500. gvar = GlobalTemporalVar()
  2501. gvar.td = td
  2502. map_i.map_value.append(gvar)
  2503. else:
  2504. map_i.map_value = gvar
  2505. t[0] = maplist
  2506. else:
  2507. t[0] = "td(" + str(t[3]) + ")"
  2508. if self.debug:
  2509. print("td(" + str(t[3]) + ")")
  2510. def p_t_time_var(self, t):
  2511. # Temporal variables that return a double or integer value
  2512. """
  2513. t_var : START_DOY
  2514. | START_DOW
  2515. | START_YEAR
  2516. | START_MONTH
  2517. | START_WEEK
  2518. | START_DAY
  2519. | START_HOUR
  2520. | START_MINUTE
  2521. | START_SECOND
  2522. | END_DOY
  2523. | END_DOW
  2524. | END_YEAR
  2525. | END_MONTH
  2526. | END_WEEK
  2527. | END_DAY
  2528. | END_HOUR
  2529. | END_MINUTE
  2530. | END_SECOND
  2531. """
  2532. t[0] = t[1]
  2533. def p_compare_op(self, t):
  2534. # Compare operators that are supported for temporal expressions
  2535. """
  2536. comp_op : CEQUALS
  2537. | UNEQUALS
  2538. | LOWER
  2539. | LOWER_EQUALS
  2540. | GREATER
  2541. | GREATER_EQUALS
  2542. """
  2543. t[0] = t[1]
  2544. def p_t_var_expr_td_hash(self, t):
  2545. # Examples:
  2546. # A # B == 2
  2547. # td(A) < 31
  2548. """
  2549. t_var_expr : t_td_var comp_op number
  2550. | t_hash_var comp_op number
  2551. """
  2552. if self.run:
  2553. maplist = self.check_stds(t[1])
  2554. comp_op = t[2]
  2555. value = str(t[3])
  2556. for map_i in maplist:
  2557. # Evaluate time diferences and hash operator statements for each map.
  2558. try:
  2559. td = map_i.map_value[0].td
  2560. boolname = eval(str(td) + comp_op + value)
  2561. # Add conditional boolean value to the map.
  2562. if "condition_value" in dir(map_i):
  2563. map_i.condition_value.append(boolname)
  2564. else:
  2565. map_i.condition_value = boolname
  2566. except:
  2567. self.msgr.fatal(
  2568. "Error: the given expression does not contain a correct time difference object."
  2569. )
  2570. t[0] = maplist
  2571. if self.debug:
  2572. print(t[1], t[2], t[3])
  2573. def p_t_var_expr_number(self, t):
  2574. # Examples:
  2575. # start_month(A) > 2
  2576. # start_day(B) < 14
  2577. # start_day(B) < start_month(A)
  2578. """
  2579. t_var_expr : t_var LPAREN stds RPAREN comp_op number
  2580. | t_var LPAREN expr RPAREN comp_op number
  2581. """
  2582. # TODO: Implement comparison operator for map lists.
  2583. # | t_var LPAREN stds RPAREN comp_op t_var LPAREN stds RPAREN
  2584. # | t_var LPAREN stds RPAREN comp_op t_var LPAREN expr RPAREN
  2585. # | t_var LPAREN expr RPAREN comp_op t_var LPAREN expr RPAREN
  2586. # | t_var LPAREN expr RPAREN comp_op t_var LPAREN stds RPAREN
  2587. # TODO: Implement statement in backward direction:
  2588. # number comp_op t_var LPAREN stds RPAREN
  2589. if self.run:
  2590. maplist = self.check_stds(t[3])
  2591. gvar = GlobalTemporalVar()
  2592. gvar.tfunc = t[1]
  2593. gvar.compop = t[5]
  2594. gvar.value = t[6]
  2595. # Evaluate temporal variable for given maplist.
  2596. resultlist = self.eval_global_var(gvar, maplist)
  2597. t[0] = resultlist
  2598. if self.debug:
  2599. print(t[1], t[3], t[5], t[6])
  2600. def p_t_var_expr_time(self, t):
  2601. # Examples:
  2602. # start_time(A) == "12:30:00"
  2603. # start_date(B) <= "2001-01-01"
  2604. # start_datetime(C) > "2001-01-01 12:30:00"
  2605. # TODO: Implement statement in backward direction:
  2606. # TIME comp_op START_TIME LPAREN stds RPAREN
  2607. """
  2608. t_var_expr : START_TIME LPAREN stds RPAREN comp_op TIME
  2609. | START_DATE LPAREN stds RPAREN comp_op DATE
  2610. | START_DATETIME LPAREN stds RPAREN comp_op DATETIME
  2611. | END_TIME LPAREN stds RPAREN comp_op TIME
  2612. | END_DATE LPAREN stds RPAREN comp_op DATE
  2613. | END_DATETIME LPAREN stds RPAREN comp_op DATETIME
  2614. | START_TIME LPAREN expr RPAREN comp_op TIME
  2615. | START_DATE LPAREN expr RPAREN comp_op DATE
  2616. | START_DATETIME LPAREN expr RPAREN comp_op DATETIME
  2617. | END_TIME LPAREN expr RPAREN comp_op TIME
  2618. | END_DATE LPAREN expr RPAREN comp_op DATE
  2619. | END_DATETIME LPAREN expr RPAREN comp_op DATETIME
  2620. """
  2621. if self.run:
  2622. # Check input maplist.
  2623. maplist = self.check_stds(t[3])
  2624. # Build global temporal variable.
  2625. gvar = GlobalTemporalVar()
  2626. gvar.tfunc = t[1]
  2627. gvar.compop = t[5]
  2628. gvar.value = t[6]
  2629. # Evaluate temporal variable for given maplist.
  2630. resultlist = self.eval_global_var(gvar, maplist)
  2631. t[0] = resultlist
  2632. if self.debug:
  2633. print(t[1], t[3], t[5], t[6])
  2634. def p_t_var_expr_comp(self, t):
  2635. """
  2636. t_var_expr : t_var_expr AND AND t_var_expr
  2637. | t_var_expr OR OR t_var_expr
  2638. """
  2639. if self.run:
  2640. # Check input maplists and operators.
  2641. tvarexprA = t[1]
  2642. tvarexprB = t[4]
  2643. relations = ["EQUAL"]
  2644. temporal = "l"
  2645. function = t[2] + t[3]
  2646. aggregate = t[2]
  2647. # Build conditional values based on topological relationships.
  2648. complist = self.build_spatio_temporal_topology_list(
  2649. tvarexprA,
  2650. tvarexprB,
  2651. topolist=relations,
  2652. compare_bool=True,
  2653. compop=function[0],
  2654. aggregate=aggregate,
  2655. )
  2656. # Set temporal extent based on topological relationships.
  2657. resultlist = self.set_temporal_extent_list(
  2658. complist, topolist=relations, temporal=temporal
  2659. )
  2660. t[0] = resultlist
  2661. if self.debug:
  2662. print(t[1], t[2] + t[3], t[4])
  2663. def p_t_var_expr_comp_op(self, t):
  2664. """
  2665. t_var_expr : t_var_expr T_COMP_OPERATOR t_var_expr
  2666. """
  2667. if self.run:
  2668. tvarexprA = t[1]
  2669. tvarexprB = t[3]
  2670. # Evaluate temporal comparison operator.
  2671. relations, temporal, function, aggregate = self.eval_toperator(
  2672. t[2], optype="boolean"
  2673. )
  2674. # Build conditional values based on topological relationships.
  2675. complist = self.build_spatio_temporal_topology_list(
  2676. tvarexprA,
  2677. tvarexprB,
  2678. topolist=relations,
  2679. compare_bool=True,
  2680. compop=function[0],
  2681. aggregate=aggregate,
  2682. )
  2683. # Set temporal extent based on topological relationships.
  2684. resultlist = self.set_temporal_extent_list(
  2685. complist, topolist=relations, temporal=temporal
  2686. )
  2687. t[0] = resultlist
  2688. if self.debug:
  2689. print(t[1], t[2], t[3])
  2690. def p_expr_t_select(self, t):
  2691. # Temporal equal selection
  2692. # The temporal topology relation equals is implicit
  2693. # Examples:
  2694. # A : B # Select the part of A that is temporally equal B
  2695. """
  2696. expr : stds T_SELECT stds
  2697. | expr T_SELECT stds
  2698. | stds T_SELECT expr
  2699. | expr T_SELECT expr
  2700. """
  2701. if self.run:
  2702. # Setup database connection.
  2703. # Check input stds.
  2704. maplistA = self.check_stds(t[1])
  2705. maplistB = self.check_stds(t[3])
  2706. # Perform selection.
  2707. selectlist = self.perform_temporal_selection(maplistA, maplistB)
  2708. # Return map list.
  2709. t[0] = selectlist
  2710. else:
  2711. t[0] = t[1] + "*"
  2712. if self.debug:
  2713. print(str(t[1]), "* = ", t[1], t[2], t[3])
  2714. def p_expr_t_not_select(self, t):
  2715. # Temporal equal selection
  2716. # The temporal topology relation equals is implicit
  2717. # Examples:
  2718. # A !: B # Select the part of A that is temporally unequal to B
  2719. """
  2720. expr : stds T_NOT_SELECT stds
  2721. | expr T_NOT_SELECT stds
  2722. | stds T_NOT_SELECT expr
  2723. | expr T_NOT_SELECT expr
  2724. """
  2725. if self.run:
  2726. # Check input stds.
  2727. maplistA = self.check_stds(t[1])
  2728. maplistB = self.check_stds(t[3])
  2729. # Perform negative selection.
  2730. selectlist = self.perform_temporal_selection(
  2731. maplistA, maplistB, inverse=True
  2732. )
  2733. # Return map list.
  2734. t[0] = selectlist
  2735. else:
  2736. t[0] = t[1] + "*"
  2737. if self.debug:
  2738. print(t[1] + "* = ", t[1], t[2], t[3])
  2739. def p_expr_t_select_operator(self, t):
  2740. # Temporal equal selection
  2741. # The temporal topology relation equals is implicit
  2742. # Examples:
  2743. # A {!:} B # Select the part of A that is temporally unequal to B
  2744. # A { :} B # Select the part of A that is temporally equal B
  2745. # A {!:, equals} B # Select the part of A that is temporally unequal to B
  2746. # A {!:, during} B # Select the part of A that is temporally not during B
  2747. # A {:, overlaps} B # Select the part of A that temporally overlaps B
  2748. # A {:, overlaps|equals} B # Select the part of A that temporally overlaps or equals B
  2749. """
  2750. expr : stds T_SELECT_OPERATOR stds
  2751. | expr T_SELECT_OPERATOR stds
  2752. | stds T_SELECT_OPERATOR expr
  2753. | expr T_SELECT_OPERATOR expr
  2754. """
  2755. if self.run:
  2756. # Check input stds.
  2757. maplistA = self.check_stds(t[1])
  2758. maplistB = self.check_stds(t[3])
  2759. # Evaluate temporal operator.
  2760. operators = self.eval_toperator(t[2], optype="select")
  2761. # Check for negative selection.
  2762. if operators[2] == "!:":
  2763. negation = True
  2764. else:
  2765. negation = False
  2766. # Perform selection.
  2767. selectlist = self.perform_temporal_selection(
  2768. maplistA, maplistB, topolist=operators[0], inverse=negation
  2769. )
  2770. selectlist = self.set_granularity(
  2771. selectlist, maplistB, operators[1], operators[0]
  2772. )
  2773. # Return map list.
  2774. t[0] = selectlist
  2775. else:
  2776. t[0] = t[1] + "*"
  2777. if self.debug:
  2778. print(t[1] + "* = ", t[1], t[2], t[3])
  2779. def p_expr_condition_if(self, t):
  2780. # Examples
  2781. # if( start_date() < "2005-06-01", A:B)
  2782. """
  2783. expr : IF LPAREN t_var_expr COMMA stds RPAREN
  2784. | IF LPAREN t_var_expr COMMA expr RPAREN
  2785. """
  2786. if self.run:
  2787. # Get stds/map list of then statement.
  2788. thenlist = self.check_stds(t[5])
  2789. # Get temporal conditional statement.
  2790. tvarexpr = t[3]
  2791. thencond = self.build_condition_list(tvarexpr, thenlist)
  2792. thenresult = self.eval_condition_list(thencond)
  2793. # Clear the map and conditional values of the map list.
  2794. resultlist = self.check_stds(thenresult, clear=True)
  2795. # Return resulting map list.
  2796. t[0] = resultlist
  2797. else:
  2798. t[0] = t[5] + "*"
  2799. if self.debug:
  2800. print(str(t[5]) + "* = ", "if condition", str(t[3]), " then ", str(t[5]))
  2801. def p_expr_condition_if_relation(self, t):
  2802. # Examples
  2803. # if({equal} start_date() < "2005-06-01", A:B)
  2804. """
  2805. expr : IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA stds RPAREN
  2806. | IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA expr RPAREN
  2807. """
  2808. if self.run:
  2809. # Get stds/map list of then statement.
  2810. thenlist = self.check_stds(t[7])
  2811. # Get temporal conditional statement.
  2812. tvarexpr = t[5]
  2813. topolist = self.eval_toperator(t[3], optype="relation")[0]
  2814. thencond = self.build_condition_list(tvarexpr, thenlist, topolist)
  2815. thenresult = self.eval_condition_list(thencond)
  2816. # Clear the map and conditional values of the map list.
  2817. resultlist = self.check_stds(thenresult, clear=True)
  2818. # Return resulting map list.
  2819. t[0] = resultlist
  2820. else:
  2821. t[0] = t[7] + "*"
  2822. if self.debug:
  2823. print(
  2824. "result* = ",
  2825. "if ",
  2826. str(t[3]),
  2827. "condition",
  2828. str(t[5]),
  2829. " then ",
  2830. str(t[7]),
  2831. )
  2832. def p_expr_condition_elif(self, t):
  2833. # Examples
  2834. # if( start_date() < "2005-06-01", if(start_time() < "12:30:00", A:B), A!:B)
  2835. """
  2836. expr : IF LPAREN t_var_expr COMMA stds COMMA stds RPAREN
  2837. | IF LPAREN t_var_expr COMMA stds COMMA expr RPAREN
  2838. | IF LPAREN t_var_expr COMMA expr COMMA stds RPAREN
  2839. | IF LPAREN t_var_expr COMMA expr COMMA expr RPAREN
  2840. """
  2841. if self.run:
  2842. # Get stds/map list of then statement.
  2843. thenlist = self.check_stds(t[5])
  2844. elselist = self.check_stds(t[7])
  2845. # Get temporal conditional statement for then and else expressions.
  2846. tvarexpr = t[3]
  2847. thencond = self.build_condition_list(tvarexpr, thenlist)
  2848. thenresult = self.eval_condition_list(thencond)
  2849. elsecond = self.build_condition_list(tvarexpr, elselist)
  2850. elseresult = self.eval_condition_list(elsecond, inverse=True)
  2851. # Combine and sort else and then statement to result map list.
  2852. combilist = thenresult + elseresult
  2853. resultlist = sorted(combilist, key=AbstractDatasetComparisonKeyStartTime)
  2854. # Clear the map and conditional values of the map list.
  2855. resultlist = self.check_stds(resultlist, clear=True)
  2856. # Return resulting map list.
  2857. t[0] = resultlist
  2858. else:
  2859. t[0] = t[5] + "*"
  2860. if self.debug:
  2861. print(
  2862. str(t[5]) + "* = ",
  2863. "if condition",
  2864. str(t[3]),
  2865. " then ",
  2866. str(t[5]),
  2867. " else ",
  2868. str(t[7]),
  2869. )
  2870. def p_expr_condition_elif_relation(self, t):
  2871. # Examples
  2872. # if({equal}, start_date() < "2005-06-01", if(start_time() < "12:30:00", A:B), A!:B)
  2873. # The then and else statement using the same topological relationships.
  2874. # Feature request: Independent relationships for then and else to conditions.
  2875. """
  2876. expr : IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA stds COMMA stds RPAREN
  2877. | IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA stds COMMA expr RPAREN
  2878. | IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA expr COMMA stds RPAREN
  2879. | IF LPAREN T_REL_OPERATOR COMMA t_var_expr COMMA expr COMMA expr RPAREN
  2880. """
  2881. if self.run:
  2882. # Get stds/map list of then statement.
  2883. thenlist = self.check_stds(t[7])
  2884. elselist = self.check_stds(t[9])
  2885. # Get temporal conditional statement.
  2886. tvarexpr = t[5]
  2887. topolist = self.eval_toperator(t[3], optype="relation")[0]
  2888. thencond = self.build_condition_list(tvarexpr, thenlist, topolist)
  2889. thenresult = self.eval_condition_list(thencond)
  2890. elsecond = self.build_condition_list(tvarexpr, elselist, topolist)
  2891. elseresult = self.eval_condition_list(elsecond, inverse=True)
  2892. # Combine and sort else and then statement to result map list.
  2893. combilist = thenresult + elseresult
  2894. resultlist = sorted(combilist, key=AbstractDatasetComparisonKeyStartTime)
  2895. # Clear the map and conditional values of the map list.
  2896. resultlist = self.check_stds(resultlist, clear=True)
  2897. # Return resulting map list.
  2898. t[0] = resultlist
  2899. else:
  2900. if t[5]:
  2901. t[0] = str(t[7])
  2902. else:
  2903. t[0] = str(t[9])
  2904. if self.debug:
  2905. if t[5]:
  2906. print(
  2907. str(t[7]),
  2908. "* = ",
  2909. "if condition",
  2910. str(t[5]),
  2911. " then ",
  2912. str(t[7]),
  2913. " else ",
  2914. str(t[9]),
  2915. )
  2916. else:
  2917. print(
  2918. str(t[9]),
  2919. "* = ",
  2920. "if condition",
  2921. str(t[5]),
  2922. " then ",
  2923. str(t[7]),
  2924. " else ",
  2925. str(t[9]),
  2926. )
  2927. def p_expr_t_buff(self, t):
  2928. # Examples
  2929. # buff_t(A : B, "10 minutes") # Select the part of A that is temporally
  2930. # equal to B and create a buffer of 10 minutes around
  2931. """
  2932. expr : BUFF_T LPAREN stds COMMA QUOTE number NAME QUOTE RPAREN
  2933. | BUFF_T LPAREN expr COMMA QUOTE number NAME QUOTE RPAREN
  2934. | BUFF_T LPAREN stds COMMA number RPAREN
  2935. | BUFF_T LPAREN expr COMMA number RPAREN
  2936. """
  2937. if self.run:
  2938. # Check input stds.
  2939. bufflist = self.check_stds(t[3])
  2940. for map in bufflist:
  2941. # Get increment format.
  2942. if len(t) == 10:
  2943. increment = str(t[6]) + " " + t[7]
  2944. elif len(t) == 7:
  2945. increment = str(t[5])
  2946. # Perform buffering.
  2947. map.temporal_buffer(increment)
  2948. t[0] = bufflist
  2949. else:
  2950. t[0] = t[3] + "*"
  2951. if self.debug:
  2952. if len(t) == 10:
  2953. print(
  2954. str(t[3]) + "* = buff_t(",
  2955. str(t[3]),
  2956. ",",
  2957. '"',
  2958. str(t[6]),
  2959. str(t[7]),
  2960. '"',
  2961. ")",
  2962. )
  2963. elif len(t) == 7:
  2964. print(str(t[3]) + "* = buff_t(", str(t[3]), ",", str(t[5]), ")")
  2965. def p_expr_t_snap(self, t):
  2966. # Examples
  2967. # tsnap(A : B) # Snap the maps of A temporally.
  2968. """
  2969. expr : TSNAP LPAREN stds RPAREN
  2970. | TSNAP LPAREN expr RPAREN
  2971. """
  2972. if self.run:
  2973. # Check input stds.
  2974. maplist = self.check_stds(t[3])
  2975. # Perform snapping.
  2976. snaplist = AbstractSpaceTimeDataset.snap_map_list(maplist)
  2977. t[0] = snaplist
  2978. else:
  2979. t[0] = t[3] + "*"
  2980. if self.debug:
  2981. print(str(t[3]) + "* = tsnap(", str(t[3]), ")")
  2982. def p_expr_t_shift(self, t):
  2983. # Examples
  2984. # tshift(A : B, "10 minutes") # Shift the selection from A temporally
  2985. # by 10 minutes.
  2986. """
  2987. expr : TSHIFT LPAREN stds COMMA QUOTE number NAME QUOTE RPAREN
  2988. | TSHIFT LPAREN expr COMMA QUOTE number NAME QUOTE RPAREN
  2989. | TSHIFT LPAREN stds COMMA number RPAREN
  2990. | TSHIFT LPAREN expr COMMA number RPAREN
  2991. """
  2992. if self.run:
  2993. # Check input stds.
  2994. maplist = self.check_stds(t[3])
  2995. # Get increment format.
  2996. if len(t) == 10:
  2997. increment = str(t[6]) + " " + t[7]
  2998. elif len(t) == 7:
  2999. increment = str(t[5])
  3000. # Perform shifting.
  3001. shiftlist = AbstractSpaceTimeDataset.shift_map_list(maplist, increment)
  3002. t[0] = shiftlist
  3003. else:
  3004. t[0] = t[3] + "*"
  3005. if self.debug:
  3006. if len(t) == 10:
  3007. print(
  3008. str(t[3]) + "* = tshift(",
  3009. str(t[3]),
  3010. ",",
  3011. '"',
  3012. str(t[6]),
  3013. str(t[7]),
  3014. '"',
  3015. ")",
  3016. )
  3017. elif len(t) == 7:
  3018. print(str(t[3]) + "* = tshift(", str(t[3]), ",", str(t[5]), ")")
  3019. # Handle errors.
  3020. def p_error(self, t):
  3021. if t:
  3022. raise SyntaxError(
  3023. "syntax error on line %d, position %i token %s near '%s' expression '%s'"
  3024. % (t.lineno, t.lexpos, t.type, t.value, self.expression)
  3025. )
  3026. else:
  3027. raise SyntaxError("Unexpected syntax error")
  3028. if __name__ == "__main__":
  3029. import doctest
  3030. doctest.testmod()