Commit aa7247d6dad03769723529cfea0fe56213d8d1c2

Authored by Goutte
1 parent 7b5642ae

Generate a CDF file (not NetCDF)

Bump to v1.0.0-rc4
CHANGELOG.md
... ... @@ -7,8 +7,6 @@
7 7 - [ ] CRON statements to call the cache cleanup and warmup
8 8 - [ ] Cache warmup (generate for today's default interval) `/cache/warmup`
9 9 - [ ] Give the future data another color
10   -- [ ] Sort times series by closeness to the sun
11   -- [ ] Generate a CDF file (not NetCDF)
12 10  
13 11 An heliospheric propagation 1D MHD model for solar wind prediction at planets, probes and comets.
14 12  
... ... @@ -16,6 +14,8 @@ An heliospheric propagation 1D MHD model for solar wind prediction at planets, p
16 14  
17 15 ## 1.0.0-rc4
18 16  
  17 +- [x] Sort times series by closeness to the sun
  18 +- [x] Generate a CDF file (not NetCDF)
19 19 - [x] Normalize time interval for time series
20 20 - [x] Make the footer images clickable
21 21 - [x] Highlight the visits counter
... ...
VERSION
1   -1.0.0-rc3
2 1 \ No newline at end of file
  2 +1.0.0-rc4
3 3 \ No newline at end of file
... ...
requirements.txt
... ... @@ -18,3 +18,5 @@ python-slugify==1.2.4
18 18 PyYAML==3.12
19 19 six==1.10.0
20 20 Werkzeug==0.12
  21 +# spacepy==0.7 # requires a lot of system deps, like fortran
  22 +CDF==0.32
21 23 \ No newline at end of file
... ...
web/run.py
... ... @@ -9,6 +9,7 @@ import random
9 9 import tarfile
10 10 import time
11 11 import urllib
  12 +import cdf
12 13 from csv import writer as csv_writer
13 14 from math import sqrt
14 15 from os import environ, remove as removefile
... ... @@ -112,7 +113,7 @@ PARAMETERS = {
112 113 'slug': 'dens',
113 114 'name': 'Density',
114 115 'title': 'The density N.',
115   - 'units': u'cm⁻³',
  116 + 'units': 'cm^-3',
116 117 'active': False,
117 118 'position': 50,
118 119 },
... ... @@ -438,7 +439,7 @@ def get_data_for_target(target_config, started_at, stopped_at):
438 439 _s1 = min(_s1, _sto)
439 440 else:
440 441 _s1 = _sto
441   - return _s1, _s0
  442 + return _s0, _s1
442 443  
443 444 precision = "%Y-%m-%dT%H" # model and orbits times are only equal-ish
444 445 orbit_data = {} # keys are datetime as str, values arrays of XY
... ... @@ -770,7 +771,7 @@ def download_targets_tarball(targets, started_at, stopped_at):
770 771 def download_targets_netcdf(targets, params, started_at, stopped_at):
771 772 """
772 773 Grab data and orbit data for the specified `target`,
773   - rearrange it and return it as a CSV file.
  774 + rearrange it and return it as a NetCDF file.
774 775 `started_at` and `stopped_at` are expected to be UTC.
775 776  
776 777 targets: string list of targets' slugs, separated by `-`.
... ... @@ -884,6 +885,117 @@ def download_targets_netcdf(targets, params, started_at, stopped_at):
884 885 return send_from_directory(CACHE_DIR, nc_filename)
885 886  
886 887  
  888 +@app.route("/<targets>_<started_at>_<stopped_at>.cdf")
  889 +def download_targets_cdf(targets, started_at, stopped_at):
  890 + """
  891 + Grab data and orbit data for the specified `target`,
  892 + rearrange it and return it as a CDF file.
  893 + `started_at` and `stopped_at` are expected to be UTC.
  894 +
  895 + targets: string list of targets' slugs, separated by `-`.
  896 + params: string list of targets' parameters, separated by `-`.
  897 + """
  898 + separator = '-' # /!\ this char should never be in target's slugs
  899 + targets = targets.split(separator)
  900 + targets.sort()
  901 + targets_configs = []
  902 + for target in targets:
  903 + if not target:
  904 + abort(400, "Invalid targets format : `%s`." % targets)
  905 + targets_configs.append(get_target_config(target))
  906 + if 0 == len(targets_configs):
  907 + abort(400, "No valid targets specified. What are you doing?")
  908 +
  909 + params = PARAMETERS.keys()
  910 + # params = params.split(separator)
  911 + # params.sort()
  912 + # if 0 == len(params):
  913 + # abort(400, "No valid parameters specified. What are you doing?")
  914 + # if not is_list_in_list(params, PARAMETERS.keys()):
  915 + # abort(400, "Some parameters are not recognized in '%s'." % str(params))
  916 +
  917 + try:
  918 + started_at = datetime.datetime.strptime(started_at, FILE_DATE_FMT)
  919 + except:
  920 + abort(400, "Invalid started_at parameter : '%s'." % started_at)
  921 + try:
  922 + stopped_at = datetime.datetime.strptime(stopped_at, FILE_DATE_FMT)
  923 + except:
  924 + abort(400, "Invalid stopped_at parameter : '%s'." % stopped_at)
  925 + sta = started_at.strftime(FILE_DATE_FMT)
  926 + sto = stopped_at.strftime(FILE_DATE_FMT)
  927 +
  928 + cdf_filename = "%s_%s_%s.cdf" % (separator.join(targets), sta, sto)
  929 + cdf_path = join(CACHE_DIR, cdf_filename)
  930 +
  931 + if not isfile(cdf_path):
  932 + log.debug("Creating the CDF file '%s'..." % cdf_filename)
  933 + try:
  934 + cdf_handle = cdf.archive()
  935 + description = "Model and orbit data for %s." % \
  936 + ', '.join([t['name'] for t in targets_configs])
  937 + cdf_handle.attributes['Description'] = description
  938 + cdf_handle.attributes['Author'] = "Heliopropa.irap.omp.eu (CDPP)"
  939 + cdf_handle.attributes['Created'] = str(time.ctime(time.time()))
  940 +
  941 + available_params = list(PROPERTIES)
  942 + for target in targets_configs:
  943 + target_slug = target['slug']
  944 + data = get_data_for_target(target, started_at, stopped_at)
  945 + dkeys = sorted(data)
  946 +
  947 + values = []
  948 + units = "hours since 1970-01-01 00:00:00"
  949 + calendar = "standard"
  950 + for dkey in dkeys:
  951 + time_as_string = data[dkey][0][:-6] # remove +00:00 tail
  952 + date = datetime.datetime.strptime(time_as_string, FILE_DATE_FMT)
  953 + values.append(date2num(date, units=units, calendar=calendar))
  954 + k = "%s_time" % target_slug
  955 + cdf_handle[k] = values
  956 + cdf_handle[k].attributes['units'] = units
  957 +
  958 + for param in params:
  959 + k = "%s_%s" % (target_slug, param)
  960 + values = []
  961 + i = available_params.index(param)
  962 + for dkey in dkeys:
  963 + values.append(data[dkey][i])
  964 + cdf_handle[k] = values
  965 + cdf_handle[k].attributes['units'] = PARAMETERS[param]['units']
  966 +
  967 + k_xhee = "%s_xhee" % target_slug
  968 + k_yhee = "%s_yhee" % target_slug
  969 + values_xhee = []
  970 + values_yhee = []
  971 + index_x = available_params.index('xhee')
  972 + index_y = available_params.index('yhee')
  973 + for dkey in dkeys:
  974 + values_xhee.append(data[dkey][index_x])
  975 + values_yhee.append(data[dkey][index_y])
  976 + cdf_handle[k_xhee] = values_xhee
  977 + cdf_handle[k_yhee] = values_yhee
  978 + cdf_handle[k_xhee].attributes['units'] = 'Au'
  979 + cdf_handle[k_yhee].attributes['units'] = 'Au'
  980 +
  981 + log.debug("Writing CDF '%s'..." % cdf_filename)
  982 + cdf_handle.save(cdf_path)
  983 +
  984 + except Exception as e:
  985 + log.error("Failed to generate CDF '%s'." % cdf_filename)
  986 + removefile(cdf_path)
  987 + raise
  988 +
  989 + finally:
  990 + # cdf_handle.close()
  991 + pass
  992 +
  993 + if not isfile(cdf_path):
  994 + abort(500, "No CDF to serve. Looked at '%s'." % cdf_path)
  995 +
  996 + return send_from_directory(CACHE_DIR, cdf_filename)
  997 +
  998 +
887 999 # API #########################################################################
888 1000  
889 1001 @app.route("/cache/clear")
... ...
web/view/home.html.jinja2
... ... @@ -538,8 +538,8 @@ var configuration = {
538 538 orbits_container: '#orbits',
539 539 api: {
540 540 'data_for_interval': "{{ request.url_root }}<target>_<started_at>_<stopped_at>.csv",
541   - 'download': "{{ request.url_root }}<targets>_<started_at>_<stopped_at>.nc",
542   - 'samp': "{{ request.url_root }}<targets>_<params>_<started_at>_<stopped_at>.nc"
  541 + 'download': "{{ request.url_root }}<targets>_<started_at>_<stopped_at>.cdf",
  542 + 'samp': "{{ request.url_root }}<targets>_<started_at>_<stopped_at>.cdf"
543 543 },
544 544 sun: {
545 545 img: '{{ static('img/sun_128.png') }}'
... ... @@ -623,6 +623,7 @@ jQuery().ready(function($){
623 623 });
624 624 $('#download').on("click", function(e){
625 625 var url = sw.buildDownloadUrl();
  626 + console.info("Downloading " + url);
626 627 $.ajax({
627 628 type: 'GET',
628 629 url: url,
... ... @@ -677,7 +678,7 @@ jQuery().ready(function($){
677 678 }
678 679 var name = sw.buildSampName();
679 680 var url = sw.buildSampUrl();
680   - console.log(name, url);
  681 + console.info("Trying to activate SAMP…", name, url);
681 682 connector.runWithConnection(function (connection) {
682 683 var msg = new samp.Message("table.load.cdf", {
683 684 "name": name,
... ...