Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 1x 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 18x 6x 6x 6x 11x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x 6x | import path from 'path'
import fs from 'fs-extra'
import errors from '@feathersjs/errors'
import grib2json from 'weacast-grib2json'
import logger from 'winston'
import makeDebug from 'debug'
const debug = makeDebug('weacast:weacast-gfs')
export default {
// Perform conversion from input TIFF to JSON
convertForecastTime (runTime, forecastTime) {
let promise = new Promise((resolve, reject) => {
const filePath = this.getForecastTimeFilePath(runTime, forecastTime)
const convertedFilePath = this.getForecastTimeConvertedFilePath(runTime, forecastTime)
Iif (fs.existsSync(convertedFilePath)) {
logger.verbose('Already converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
fs.readJson(convertedFilePath, 'utf8')
.then(grid => {
resolve(grid)
})
.catch(error => {
logger.error('Cannot read converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
debug('Input JSON file was : ' + convertedFilePath)
reject(error)
})
return
}
grib2json(filePath, {
data: true,
bufferSize: 1024 * 1024 * 1024
})
.then(json => {
Iif (json.length === 0 || !json[0].data || !json[0].data.length > 0) {
const errorMessage = 'Converted ' + this.forecast.name + '/' + this.element.name + ' forecast data at ' + forecastTime.format() + ' for run ' + runTime.format() + ' is invalid or empty'
logger.error(errorMessage)
debug('Output JSON file was : ' + convertedFilePath)
reject(new errors.Unprocessable(errorMessage))
return
} else {
logger.verbose('Converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
}
// Change extension from tiff to json
fs.outputJson(convertedFilePath, json[0].data, 'utf8')
.then(_ => {
logger.verbose('Written ' + this.forecast.name + '/' + this.element.name + ' converted forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
resolve(json[0].data)
})
.catch(error => {
logger.error('Cannot write converted ' + this.forecast.name + '/' + this.element.name + ' forecast at ' + forecastTime.format() + ' for run ' + runTime.format())
debug('Output JSON file was : ' + convertedFilePath)
reject(error)
})
})
.catch(error => {
reject(error)
})
})
return promise
},
// Generate file name to store temporary input data with the right format extension
getForecastTimeFilePath (runTime, forecastTime) {
return path.join(this.app.get('forecastPath'), this.forecast.name, this.element.name, runTime.format('YYYY-MM-DD[_]HH-mm-ss') + '_' + forecastTime.format('YYYY-MM-DD[_]HH-mm-ss') + '.grib')
},
// Build the request options to download given forecast time from input WCS data source
getForecastTimeRequest (runTime, forecastTime) {
// Directories are organized by run time
let subDirectory = '/gfs.' + runTime.format('YYYYMMDD/HH') + '/atmos'
// Then we need to target the right file for forecast time
// Get offset from run time
let hours = forecastTime.diff(runTime, 'hours')
// Convert to string with zero padding like 006
hours = hours.toFixed(0)
while (hours.length < 3) hours = '0' + hours
// Get resolution expressed as XpXX
let resolution = this.forecast.resolution.length > 0 ? this.forecast.resolution[0] : 0.5
resolution = resolution.toFixed(2).replace('.', 'p')
// Specific case of 0.5° model
Eif (resolution === '0p50') {
resolution = 'full.' + resolution
} else {
resolution = '.' + resolution
}
let file = 'gfs.t' + runTime.format('HH') + 'z.pgrb2' + resolution + '.f' + hours
// Setup request with URL, variable, level parameters for HTTP filter
let queryParameters = {
dir: subDirectory,
file
}
Iif (this.element.variable.startsWith('var_')) {
queryParameters[this.element.variable] = 'on'
} else {
queryParameters['var_' + this.element.variable.toUpperCase()] = 'on'
}
Eif (this.element.levels) {
this.element.levels.forEach(level => {
queryParameters[level.startsWith('lev_') ? level : 'lev_' + level] = 'on'
})
}
return {
url: this.forecast.baseUrl,
qs: queryParameters
}
}
}
|