blob: e69b5487f226b421a8f0f48ea9b957c324af1c94 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
''' Helpers for local model/observation file metadata extraction. '''
import sys
import netCDF4
import json
from bottle import Bottle, request, route, response
import ocw.utils
lfme_app = Bottle()
@lfme_app.route('/list_latlon/<file_path:path>')
def list_latlon(file_path):
''' Retrieve lat/lon information from given file.
:param file_path: Path to the NetCDF file from which lat/lon information
should be extracted
:type file_path: string:
:returns: Dictionary containing lat/lon information if successful, otherwise
failure information is returned.
**Example successful JSON return**
.. sourcecode:: javascript
{
'success': true,
'lat_name': The guessed latitude variable name,
'lon_name': the guessed longitude variable name,
'lat_min': The minimum latitude value,
'lat_max': The maximum latitude value,
'lon_min': The minimum longitude value,
'lon_max': The maximum longitude value
}
**Example failure JSON return**
.. sourcecode:: javascript
{
'success': false,
'variables': List of all variables present in the NetCDF file
}
'''
in_file = netCDF4.Dataset(file_path, mode='r')
var_names = set([key.encode().lower() for key in in_file.variables.keys()])
var_names_list = list(var_names)
lat_name_guesses = set(['latitude','lat','lats','latitudes'])
lon_name_guesses = set(['longitude','lon','lons','longitudes'])
# Attempt to determine the lat name
found_lat_name = False
# Find the intersection (if there is one) of the var names with the lat guesses
lat_guesses = list(var_names & lat_name_guesses)
if len(lat_guesses) >= 1:
found_lat_name = True
lat_name = var_names_list[var_names_list.index(lat_guesses[0])]
lats = in_file.variables[lat_name][:]
# Change 0 - 360 degree values to be -180 to 180
lats[lats > 180] = lats[lats > 180] - 360
lat_min = float(lats.min())
lat_max = float(lats.max())
# Attempt to determine the lon name
found_lon_name = False
# Find the intersection (if there is one) of the var names with the lon guesses
lon_guesses = list(var_names & lon_name_guesses)
if len(lon_guesses) >= 1:
found_lon_name = True
lon_name = var_names_list[var_names_list.index(lon_guesses[0])]
lons = in_file.variables[lon_name][:]
# Change 0 - 360 degree values to be -180 to 180
lons[lons > 180] = lons[lons > 180] - 360
lon_min = float(lons.min())
lon_max = float(lons.max())
in_file.close()
success = found_lat_name and found_lon_name
if success:
values = [success, lat_name, lon_name, lat_min, lat_max, lon_min, lon_max]
value_names = ['success', 'lat_name', 'lon_name', 'lat_min', 'lat_max', 'lon_min', 'lon_max']
output = dict(zip(value_names, values))
else:
output = {'success': success, 'variables': var_names_list}
if request.query.callback:
return '%s(%s)' % (request.query.callback, json.dumps(output))
return output
@lfme_app.route('/list_time/<file_path:path>')
def list_time(file_path):
''' Retrieve time information from provided file.
:param file_path: Path to the NetCDF file from which time information
should be extracted
:type file_path: String:
:returns: Dictionary containing time information if successful, otherwise
failure information is returned.
**Example successful JSON return**
.. sourcecode:: javascript
{
"success": true,
"time_name": The guessed time variable name,
"start_time": "1988-06-10 00:00:00",
"end_time": "2008-01-27 00:00:00"
}
**Example failure JSON return**
.. sourcecode:: javascript
{
"success": false
"variables": List of all variable names in the file
}
'''
in_file = netCDF4.Dataset(file_path, mode='r')
var_names = set([key.encode().lower() for key in in_file.variables.keys()])
var_names_list = list(var_names)
time_name_guesses = set(['time', 'times', 't', 'date', 'dates', 'julian'])
# Find the intersection (if there is one) of the var names with the lat guesses
time_guesses = list(var_names & time_name_guesses)
if len(time_guesses) >= 1:
# Convert time data to datetime objects
time_var_name = time_guesses[0]
times = ocw.utils.decode_time_values(in_file, time_var_name)
start_time = str(min(times))
end_time = str(max(times))
output = {
'success': True,
'time_name': time_var_name,
'start_time': start_time,
'end_time': end_time
}
else:
output = {'success': False, 'variables': var_names_list}
if request.query.callback:
return '%s(%s)' % (request.query.callback, json.dumps(output))
return output
@lfme_app.route('/list_vars/<file_path:path>')
def list_vars(file_path):
''' Retrieve variable names from file.
:param file_path: Path to the NetCDF file from which variable information
should be extracted
:type file_path: String:
:returns: Dictionary containing variable information if succesful, otherwise
failure information is returned.
**Example successful JSON return**
.. sourcecode:: javascript
{
"success": true,
"variables": List of variable names in the file
}
**Example failure JSON return**
.. sourcecode:: javascript
{
"success": false
}
'''
try:
in_file = netCDF4.Dataset(file_path, mode='r')
except RuntimeError:
output = {'success': False}
else:
output = {'success': True, 'variables': in_file.variables.keys()}
in_file.close()
finally:
if request.query.callback:
return "%s(%s)" % (request.query.callback, json.dumps(output))
return output
@lfme_app.hook('after_request')
def enable_cors():
''' Allow Cross-Origin Resource Sharing for all URLs. '''
response.headers['Access-Control-Allow-Origin'] = '*'