-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtimeseries.py
128 lines (105 loc) · 5.75 KB
/
timeseries.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/local/bin/python3
import math
import cgi
form = cgi.FieldStorage()
import json
import datetime
import os
import asyncio
from GEE_API_server import GEE_Service
def printErrorMessage(task_id,errorMessage,adviceMessage='Double check the inputs'):
return (400,{"Content-type":"application/json"},json.JSONEncoder().encode({'status':'error','taskID':task_id,'errorMesage':errorMessage,'advice':adviceMessage}));
class GP_timeseries_v2(GEE_Service):
def boundingTimeCollection(self,timeStart,timeEnd,coordinates):
def reduce2aPixel(im):
return im.addBands(self.ee.Image.constant(self.ee.Number(im.get('system:time_start')).divide(1000)).rename('time').toLong()).sample(region=self.ee.Geometry.Point(coordinates), scale=10, numPixels=1);
ERA5_pressur=self.ee.ImageCollection("ECMWF/ERA5_LAND/HOURLY").filterDate(timeStart,self.ee.Date(timeEnd).advance(1,'hour')).select(['surface_pressure'],['pressure']);
fc=ERA5_pressur.map(reduce2aPixel).flatten()
url=self.ee.FeatureCollection(fc).getDownloadURL(selectors=['time','pressure'])
return url;
def expliciteTimeCollection(self,time,pressure,coordinates):
def makeFeature(li):
li=self.ee.List(li);
return self.ee.Feature(None,{'system:time_start':self.ee.Number(li.get(0)).multiply(1000),'pressure':li.get(1)})
val=self.ee.List([time, pressure]).unzip();
fc=self.ee.FeatureCollection(val.map(makeFeature));
start=fc.aggregate_min('system:time_start');
end=fc.aggregate_max('system:time_start');
ERA5=self.ee.ImageCollection("ECMWF/ERA5_LAND/HOURLY");
ERA5_pressur=ERA5.filterDate(start,self.ee.Date(end).advance(1,'hour')).select(['surface_pressure','temperature_2m']);
era5_llabelFeature=self.ee.Join.saveBest(matchKey='bestERA5',measureKey='diff').apply(fc,ERA5_pressur,self.ee.Filter.maxDifference(3600*1000,leftField='system:time_start', rightField='system:time_start' ));
def getAltitude(ft):
#standard temperature lapse rate [K/m] = -0.0065 [K/m]
Lb = -0.0065;
#universal gas constant = 8.31432 [N * m / mol /K]
R = 8.31432;
#gravitational acceleration constant = 9.80665 [m/s^2]
g0 = 9.80665;
#molar mass of Earth s air = 0.0289644 [kg/mol]
M = 0.0289644;
#standard temperature (temperature at sea level) [K]
T0 = 273.15+15;
altIm=self.ee.Image('projects/earthimages4unil/assets/PostDocProjects/rafnuss/Geopot_ERA5');
dh = self.ee.Image(ft.get('bestERA5')).select('temperature_2m').divide(Lb).multiply(self.ee.Image.constant(self.ee.Number(ft.get('pressure'))).divide(self.ee.Image(ft.get('bestERA5')).select('surface_pressure')).pow(-R*Lb/g0/M).subtract(1)).add(altIm).rename('altitude');
return dh.addBands(self.ee.Image(ft.get('bestERA5')).select('surface_pressure').rename('pressure')).addBands(self.ee.Image.constant(self.ee.Number(ft.get('system:time_start'))).rename('time').divide(1000).toLong()).sample(region=self.ee.Geometry.Point(coordinates), scale=1, numPixels=1);
agregatedMap=self.ee.FeatureCollection(era5_llabelFeature.map(getAltitude)).flatten();
url=agregatedMap.getDownloadURL(selectors=['time','pressure','altitude'])
return url;
def checkPosition(self,coordinates):
lon,lat=coordinates;
ERA5=self.ee.ImageCollection("ECMWF/ERA5_LAND/HOURLY");
land=ERA5.first().select('surface_pressure').mask();
radius=1000000;
geometry=self.ee.Geometry.Point(coordinates);
isLand=land.sample(region=geometry, scale=1, numPixels=1).first().get('surface_pressure').getInfo();
if(not isLand):
land=land.focalMin(1,'circle','pixels')
aoi=self.ee.FeatureCollection(self.ee.Feature(geometry)).distance(radius).addBands(self.ee.Image.pixelLonLat()).updateMask(land);
best=aoi.reduceRegion(self.ee.Reducer.min(3),geometry.buffer(radius),land.geometry().projection().nominalScale().multiply(0.05)).getInfo();
return (best['min1'],best['min2'],best['min'],True);
else:
return (lon, lat,0,False);
def singleRequest(self, jsonObj, requestType):
timeStamp=math.floor(datetime.datetime.utcnow().timestamp());
with open("logs/{}.log".format(timeStamp), 'w') as f:
f.write(json.JSONEncoder().encode(jsonObj))
if('lon' not in jsonObj.keys() or 'lat' not in jsonObj.keys() ):
return printErrorMessage(timeStamp,'lon and lat are mendatory!')
try:
lon=float(jsonObj["lon"]);
except:
return printErrorMessage(timeStamp,'lon is not a float number');
try:
lat=float(jsonObj["lat"]);
except:
return printErrorMessage(timeStamp,'lat is not a float number');
informedTimeSeries=False;
if('time' in jsonObj.keys() and 'pressure' in jsonObj.keys()):
informedTimeSeries=True;
else:
if 'startTime' not in jsonObj.keys() or 'endTime' not in jsonObj.keys() :
return printErrorMessage(timeStamp,'startTime and endTime OR time and pressure arrays are mendatory!')
if(informedTimeSeries):
time=jsonObj["time"];
pressure=jsonObj["pressure"];
else:
try:
timeStart=int(jsonObj["startTime"]);
except:
return printErrorMessage(timeStamp,'startTime is not a int number');
try:
timeEnd=int(jsonObj["endTime"]);
except:
return printErrorMessage(timeStamp,'endTime is not a int number');
timeStart=timeStart*1000;
timeEnd=timeEnd*1000;
try:
lon,lat,dist,change=self.checkPosition([lon, lat]);
if informedTimeSeries:
url=self.expliciteTimeCollection(time,pressure,[lon, lat]);
else:
url=self.boundingTimeCollection(timeStart,timeEnd,[lon, lat]);
dic = {'status':'success', 'taskID':timeStamp,'data':{'format':'csv','url':url,'lon':lon,'lat':lat,'distInter':dist}};
return (200,{"Content-type":"application/json"},json.JSONEncoder().encode(dic));
except Exception as e:
return printErrorMessage(timeStamp,str(e),"An error has occurred. Please try again, and if the problem persists, file an issue on https://github.com/Rafnuss/GeoPressureServer/issues/new?body=task_id:{}&labels=crash".format(timeStamp));