Commit 8644387c4775291d14c8a1f2f8f5467e21614ea5

Authored by Goutte
1 parent c15a50cb

Use real data.

CHANGELOG.md
  1 +- Start/Stop datetime fields
  2 +- Play button to start time dimension
  3 +- Download raw data for time interval
  4 +- Same via SAMP
  5 +
  6 +- Planets
  7 +- Probes
  8 + - Rosetta
  9 + - Juno
  10 +- Comets (the one visited by rosetta)
  11 +
1 12 ## 0.0.0
2 13  
3 14 - Initial website skeleton
4   -- Initial data bridge between netCDF and CSV
5 15 \ No newline at end of file
  16 +- Initial data bridge between netCDF and CSV
  17 +- New parameters
  18 + - Temperature `T` (K)
  19 + - Density `N` (cm^-3)
  20 + - Angle Planet-Sun-Earth `Delta_angle` (degrees)
  21 + - Magnetism => B Tangential
  22 +- Orbits axes titles
  23 +- Logo Europlanet
... ...
config.yml
... ... @@ -35,6 +35,27 @@ authors:
35 35 role: Project Coordinator
36 36 mail: vincent.genot@irap.omp.eu
37 37  
  38 +
  39 +amda: "http://cdpp.irap.omp.eu/BASE/DDService/getDataUrl.php?dataSet={dataSet}&StartTime={startTime}&StopTime={stopTime}"
  40 +
  41 +#Targets
  42 +#Earth earth_orb_all
  43 +#Jupiter jupiter_orb_all
  44 +#Mars mars_orb_all
  45 +#Mercury mercury_orb_all
  46 +#Neptune neptune_orb_all
  47 +#Venus venus_orb_all
  48 +#Uranus uranus_orb_all
  49 +#
  50 +#Comets
  51 +#67P p67_orb_all
  52 +#
  53 +#Probes
  54 +#Maven maven_orb_cruise
  55 +#Juno juno_cruise_all
  56 +#Exomars exomars_cruise_all
  57 +#Rosetta ros_orb_cruise
  58 +
38 59 # `slug` used internally, and should match [a-z0-9]+
39 60 # `name` is displayed
40 61 # `title` appears on mouse hover
... ... @@ -45,54 +66,94 @@ sources:
45 66 slug: 'mercury'
46 67 name: 'Mercury'
47 68 title: 'Mercury (coming soon)'
  69 + orbit: 'mercury_orb_all'
  70 + models:
  71 + - slug: 'tao_mercury_sw'
  72 + started_at: "1990-01-01T01:30:00"
  73 + stopped_at: "2017-02-19T00:00:00"
48 74 locked: true
49 75 default: true
50 76 - type: 'planet'
51 77 slug: 'venus'
52 78 name: 'Venus'
53 79 title: 'Venus (coming soon)'
  80 + orbit: 'venus_orb_all'
  81 + models:
  82 + - slug: 'tao_venus_sw'
  83 + started_at: "1990-01-01T01:30:00"
  84 + stopped_at: "2017-02-19T00:00:00"
54 85 locked: true
55 86 default: true
56 87 - type: 'planet'
57 88 slug: 'earth'
58 89 name: 'Earth'
59 90 title: 'Earth (coming soon)'
  91 + orbit: 'earth_orb_all'
  92 + #model: 'tao_earth_sw'
60 93 locked: true
61 94 default: true
62 95 - type: 'planet'
63 96 slug: 'mars'
64 97 name: 'Mars'
65 98 title: 'Mars (coming soon)'
  99 + orbit: 'mars_orb_all'
  100 + models:
  101 + - slug: 'tao_mars_sw'
  102 + started_at: "1990-01-01T01:30:00"
  103 + stopped_at: "2017-02-19T00:00:00"
66 104 locked: true
67 105 default: true
68 106 - type: 'planet'
69 107 slug: 'jupiter'
70 108 name: 'Jupiter'
71 109 title: 'Jupiter'
  110 + orbit: 'jupiter_orb_all'
  111 + models:
  112 + - slug: 'tao_jup_sw'
  113 + started_at: "1990-01-01T01:30:00"
  114 + stopped_at: "2017-02-19T00:00:00"
  115 + started_at: "1990-01-01T01:30:00"
  116 + stopped_at: "2017-02-19T00:00:00"
72 117 locked: false
73 118 default: true
74 119 - type: 'planet'
75 120 slug: 'saturn'
76 121 name: 'Saturn'
77 122 title: 'Saturn (coming soon)'
  123 + orbit: 'saturn_orb_all'
  124 + models:
  125 + - slug: 'tao_sat_sw'
  126 + started_at: "1990-01-01T01:30:00"
  127 + stopped_at: "2017-02-19T00:00:00"
78 128 locked: true
79 129 default: true
80 130 - type: 'probe'
81 131 slug: 'rosetta'
82 132 name: 'Rosetta'
83 133 title: 'Rosetta (coming soon)'
  134 + orbit: 'ros_orb_cruise'
  135 + models:
  136 + - slug: 'tao_ros_sw'
  137 + started_at: "1990-01-01T01:30:00"
  138 + stopped_at: "2017-02-19T00:00:00"
84 139 locked: true
85 140 default: false
86 141 - type: 'probe'
87 142 slug: 'juno'
88 143 name: 'Juno'
89 144 title: 'Juno (coming soon)'
  145 + orbit: 'juno_cruise_all'
  146 + models:
  147 + - slug: 'tao_juno_sw'
  148 + started_at: "1990-01-01T01:30:00"
  149 + stopped_at: "2017-02-19T00:00:00"
90 150 locked: true
91 151 default: false
92 152 - type: 'comet'
93 153 slug: 'tchouri'
94 154 name: 'Tchouri'
95 155 title: 'Tchouri (coming soon)'
  156 + orbit: 'p67_orb_all'
96 157 locked: true
97 158 default: false
98 159  
... ...
web/run.py
... ... @@ -7,6 +7,9 @@ from os import listdir, environ
7 7 from os.path import isfile, join, abspath, dirname
8 8  
9 9 import csv
  10 +import json
  11 +import gzip
  12 +import urllib
10 13 from pprint import pprint
11 14 from csv import writer as csv_writer
12 15 from yaml import load as yaml_load
... ... @@ -143,6 +146,60 @@ def datetime_from_list(time_list):
143 146 )
144 147  
145 148  
  149 +def get_source_config(slug):
  150 + for s in config['sources']:
  151 + if s['slug'] == slug:
  152 + return s
  153 + raise Exception("No source found for slug '%s'." % slug)
  154 +
  155 +
  156 +def retrieve_data(orbiter, what, started_at, stopped_at):
  157 + """
  158 + Handles remote querying Myriam's API, downloading, extracting and caching
  159 + the netCDF files.
  160 + :param orbiter: key of the source in the YAML config
  161 + :param what: either 'model' or 'orbit', a key in the config of the source
  162 + :param started_at:
  163 + :param stopped_at:
  164 + :return: a list of local file paths to netCDF (.nc) files
  165 + """
  166 +
  167 + url = config['amda'].format(
  168 + dataSet=what,
  169 + startTime=started_at.isoformat(),
  170 + stopTime=stopped_at.isoformat()
  171 + )
  172 + response = urllib.urlopen(url)
  173 + remote_gzip_files = json.loads(response.read())
  174 + if not remote_gzip_files or remote_gzip_files == 'NODATASET':
  175 + abort(400, "Failed to fetch data at '%s'." % url)
  176 +
  177 + # retriever = urllib.URLopener() # would we need to do this every time ?
  178 + local_gzip_files = []
  179 + for remote_gzip_file in remote_gzip_files:
  180 + # removeme @Myriam
  181 + if remote_gzip_file.endswith('/.gz'):
  182 + continue
  183 + remote_gzip_file = remote_gzip_file.replace('cdpp1', 'cdpp', 1)
  184 + #########################
  185 + filename = "%s_%s" % (orbiter, str(remote_gzip_file).split('/')[-1])
  186 + local_gzip_file = get_path("../cache/%s" % filename)
  187 + local_gzip_files.append(local_gzip_file)
  188 + if not isfile(local_gzip_file):
  189 + urllib.urlretrieve(remote_gzip_file, local_gzip_file)
  190 +
  191 + local_netc_files = []
  192 + for local_gzip_file in local_gzip_files:
  193 + local_netc_file = local_gzip_file[0:-3]
  194 + local_netc_files.append(local_netc_file)
  195 + with gzip.open(local_gzip_file, 'rb') as f:
  196 + file_content = f.read()
  197 + with open(local_netc_file, 'w+b') as g:
  198 + g.write(file_content)
  199 +
  200 + return local_netc_files
  201 +
  202 +
146 203 # ROUTING #####################################################################
147 204  
148 205 @app.route('/favicon.ico')
... ... @@ -188,40 +245,6 @@ def analyze_cdf():
188 245 return si.getvalue()
189 246  
190 247  
191   -@app.route("/test.csv")
192   -def get_csv():
193   - si = StringIO.StringIO()
194   - cw = csv_writer(si)
195   -
196   - # Time, StartTime, StopTime, V, B, N, T, Delta_angle, P_dyn, QualityFlag
197   - cdf_handle = Dataset(get_path("../res/dummy.nc"), "r", format="NETCDF4")
198   - # YYYY DOY HH MM SS .ms
199   - times = cdf_handle.variables['Time']
200   - data_v = cdf_handle.variables['V']
201   - data_b = cdf_handle.variables['B']
202   - data_t = cdf_handle.variables['T']
203   - data_n = cdf_handle.variables['N']
204   - data_p = cdf_handle.variables['P_dyn']
205   - data_a = cdf_handle.variables['Delta_angle']
206   - cw.writerow((
207   - 'time',
208   - 'vrad', 'vtan', 'vlen',
209   - 'magn', 'temp', 'pdyn', 'dens', 'angl'
210   - ))
211   - for time, datum_v, datum_b, datum_t, datum_p, datum_n, datum_a in \
212   - zip(times, data_v, data_b, data_t, data_n, data_p, data_a):
213   - vrad = datum_v[0]
214   - vtan = datum_v[1]
215   - cw.writerow((
216   - datetime_from_list(time).strftime("%Y-%m-%dT%H:%M:%S+00:00"),
217   - vrad, vtan, sqrt(vrad * vrad + vtan * vtan),
218   - datum_b, datum_t, datum_n, datum_p, datum_a
219   - ))
220   - cdf_handle.close()
221   -
222   - return si.getvalue()
223   -
224   -
225 248 @app.route("/<orbiter>_data.csv")
226 249 def get_orbiter_csv(orbiter):
227 250 # http://cdpp1.cesr.fr/BASE/DDService/getDataUrl.php?dataSet=tao_ros_sw&StartTime=2014-02-23T10:00&StopTime=2016-02-24T23:59
... ... @@ -242,55 +265,74 @@ def get_orbiter_csv(orbiter):
242 265  
243 266 # Grab the list of netCDF files from Myriam's API todo
244 267 #
  268 + # http://cdpp.irap.omp.eu/BASE/DDService/getDataUrl.php?dataSet=jupiter_orb_all&StartTime=2014-02-23T10:00:10&StopTime=2017-02-24T23:59:00
  269 + # http://cdpp.irap.omp.eu/BASE/DATA/TAO/JUPITER/SW/sw_2014.nc.gz
  270 +
  271 + source_config = get_source_config(orbiter)
  272 + try:
  273 + model_slug = source_config['models'][0]['slug']
  274 + except:
  275 + abort(500, "Invalid model configuration for '%s'." % orbiter)
  276 + model_files = retrieve_data(orbiter, model_slug, started_at, stopped_at)
  277 + orbits_files = retrieve_data(orbiter, source_config['orbit'], started_at, stopped_at)
245 278  
246 279 si = StringIO.StringIO()
247 280 cw = csv_writer(si)
248   -
249   - # Time, StartTime, StopTime, V, B, N, T, Delta_angle, P_dyn, QualityFlag
250   - cdf_handle = Dataset(get_path("../res/dummy.nc"), "r", format="NETCDF4")
251   -
252   - # YYYY DOY HH MM SS .ms
253   - times = cdf_handle.variables['Time']
254   - data_v = cdf_handle.variables['V']
255   - data_b = cdf_handle.variables['B']
256   - data_p = cdf_handle.variables['P_dyn']
257   - cw.writerow((
  281 + cw.writerow(( # the order matters !
258 282 'time',
259 283 'vrad', 'vtan', 'vlen',
260   - 'magn', 'pdyn'
  284 + 'magn', 'temp', 'pdyn', 'dens', 'angl',
  285 + 'xhci', 'yhci'
261 286 ))
262   - for time, datum_v, datum_b, datum_p in zip(times, data_v, data_b, data_p):
263   - vrad = datum_v[0]
264   - vtan = datum_v[1]
265   - cw.writerow((
266   - datetime_from_list(time).strftime("%Y-%m-%dT%H:%M:%S+00:00"),
267   - vrad, vtan, sqrt(vrad * vrad + vtan * vtan),
268   - datum_b, datum_p
269   - ))
270   - cdf_handle.close()
271 287  
272   - return si.getvalue()
273   -
274   -
275   -@app.route("/astral_coordinates.csv")
276   -def get_astral_coordinates_csv():
277   - si = StringIO.StringIO()
278   - cw = csv_writer(si)
279   -
280   - # Time, StartTime, StopTime, XYZ_HCI, XYZ_IAU_SUN, XYZ_HEE
281   - cdf_handle = Dataset(get_path("../res/dummy_jupiter_coordinates.nc"), "r", format="NETCDF4")
282   - times = cdf_handle.variables['Time']
283   - data_xyz_hci = cdf_handle.variables['XYZ_HCI']
284   - cw.writerow(('time', 'x_hci', 'y_hci'))
285   - for time, datum_xyz_hci in zip(times, data_xyz_hci):
286   - cw.writerow((
287   - datetime_from_list(time).strftime("%Y-%m-%dT%H:%M:%S+00:00"),
288   - datum_xyz_hci[0], datum_xyz_hci[1]
289   - ))
290   - cdf_handle.close()
  288 + precision = "%Y-%m-%dT%H" # model and orbits times are equal-ish
  289 + orbits_data = {} # keys are datetime as str, values arrays of XY
  290 + for orbits_file in orbits_files:
  291 + cdf_handle = Dataset(orbits_file, "r", format="NETCDF4")
  292 + times = cdf_handle.variables['Time'] # YYYY DOY HH MM SS .ms
  293 + data_hci = cdf_handle.variables['HCI']
  294 + for time, datum_hci in zip(times, data_hci):
  295 + dtime = datetime_from_list(time)
  296 + if started_at <= dtime <= stopped_at:
  297 + dkey = dtime.strftime(precision)
  298 + orbits_data[dkey] = datum_hci
  299 + all_data = {} # keys are datetime as str, values tuples of data
  300 + for model_file in model_files:
  301 + # Time, StartTime, StopTime, V, B, N, T, Delta_angle, P_dyn
  302 + cdf_handle = Dataset(model_file, "r", format="NETCDF4")
  303 + times = cdf_handle.variables['Time'] # YYYY DOY HH MM SS .ms
  304 + data_v = cdf_handle.variables['V']
  305 + data_b = cdf_handle.variables['B']
  306 + data_t = cdf_handle.variables['T']
  307 + data_n = cdf_handle.variables['N']
  308 + data_p = cdf_handle.variables['P_dyn']
  309 + data_d = cdf_handle.variables['Delta_angle']
  310 + for time, datum_v, datum_b, datum_t, datum_p, datum_n, datum_d \
  311 + in zip(times, data_v, data_b, data_t, data_n, data_p, data_d):
  312 + vrad = datum_v[0]
  313 + vtan = datum_v[1]
  314 + dtime = datetime_from_list(time)
  315 + if started_at <= dtime <= stopped_at:
  316 + dkey = dtime.strftime(precision)
  317 + x_hci = None
  318 + y_hci = None
  319 + if dkey in orbits_data:
  320 + x_hci = orbits_data[dkey][0]
  321 + y_hci = orbits_data[dkey][1]
  322 + all_data[dkey] = (
  323 + dtime.strftime("%Y-%m-%dT%H:%M:%S+00:00"),
  324 + vrad, vtan, sqrt(vrad * vrad + vtan * vtan),
  325 + datum_b, datum_t, datum_n, datum_p, datum_d,
  326 + x_hci, y_hci
  327 + )
  328 + cdf_handle.close()
  329 +
  330 + for dkey in sorted(all_data):
  331 + cw.writerow(all_data[dkey])
291 332  
292 333 return si.getvalue()
293 334  
  335 +
294 336 # MAIN ########################################################################
295 337  
296 338 if __name__ == "__main__":
... ...
web/view/home.html.jinja2
... ... @@ -176,16 +176,20 @@ jQuery().ready(function($){
176 176  
177 177 var sw = new SpaceWeather(configuration);
178 178  
179   - d3.csv('{{ url_for('get_csv') }}', function(csv){
  179 + d3.csv('{{ url_for('get_orbiter_csv', orbiter='jupiter', started_at='2016-03-19T00:00:00', stopped_at='2022-01-01T00:00:00') }}', function(csv){
180 180 var timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z');
181   - var data = {'pdyn': [], 'magn': [], 'vlen': [], 'temp': [], 'dens': [], 'angl': []};
  181 + var data = {'pdyn': [], 'magn': [], 'vlen': [], 'temp': [], 'dens': [], 'angl': [], 'hci': []};
182 182 csv.forEach(function (d) {
183   - data['pdyn'].push({x: timeFormat(d['time']), y: parseFloat(d['pdyn'])});
184   - data['magn'].push({x: timeFormat(d['time']), y: parseFloat(d['magn'])});
185   - data['vlen'].push({x: timeFormat(d['time']), y: parseFloat(d['vlen'])});
186   - data['temp'].push({x: timeFormat(d['time']), y: parseFloat(d['temp'])});
187   - data['dens'].push({x: timeFormat(d['time']), y: parseFloat(d['dens'])});
188   - data['angl'].push({x: timeFormat(d['time']), y: parseFloat(d['angl'])});
  183 + var dtime = timeFormat(d['time']);
  184 + data['pdyn'].push({x: dtime, y: parseFloat(d['pdyn'])});
  185 + data['magn'].push({x: dtime, y: parseFloat(d['magn'])});
  186 + data['vlen'].push({x: dtime, y: parseFloat(d['vlen'])});
  187 + data['temp'].push({x: dtime, y: parseFloat(d['temp'])});
  188 + data['dens'].push({x: dtime, y: parseFloat(d['dens'])});
  189 + data['angl'].push({x: dtime, y: parseFloat(d['angl'])});
  190 + if (d['xhci'] && d['yhci']) {
  191 + data['hci'].push({t: dtime, x: parseFloat(d['xhci']), y: parseFloat(d['yhci'])});
  192 + }
189 193 });
190 194  
191 195 var container = '#time_series';
... ... @@ -221,16 +225,9 @@ jQuery().ready(function($){
221 225 };
222 226 });
223 227  
224   - });
225 228  
226   - d3.csv('{{ url_for('get_astral_coordinates_csv') }}', function(csv){
227   - var timeFormat = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z');
228   - var data = [];
229   - csv.forEach(function (d) {
230   - data.push({t: timeFormat(d['time']), x: parseFloat(d['x_hci']), y: parseFloat(d['y_hci'])});
231   - });
  229 + orbits = new Orbits(configuration.sources, data['hci'], configuration.orbits_container);
232 230  
233   - orbits = new Orbits(configuration.sources, data, '#orbits');
234 231 });
235 232  
236 233 var toggleTimeSeries = function(slug) {
... ...