Spaces:
Sleeping
Sleeping
File size: 6,719 Bytes
6ee917b | 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 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | import Foundation
/// Required additions to a GFS variable to make it downloadable
protocol GfsGraphCastVariableDownloadable: GenericVariable {
var multiplyAdd: (multiply: Float, add: Float)? { get }
}
enum GfsGraphCastSurfaceVariable: String, CaseIterable, GenericVariableMixable, GfsGraphCastVariableDownloadable {
case temperature_2m
case cloud_cover
case cloud_cover_low
case cloud_cover_mid
case cloud_cover_high
case pressure_msl
case wind_v_component_10m
case wind_u_component_10m
case precipitation
var storePreviousForecast: Bool {
switch self {
case .temperature_2m: return true
case .precipitation: return true
case .pressure_msl: return true
case .cloud_cover: return true
case .wind_u_component_10m, .wind_v_component_10m: return true
default: return false
}
}
var requiresOffsetCorrectionForMixing: Bool {
return false
}
var multiplyAdd: (multiply: Float, add: Float)? {
switch self {
case .temperature_2m:
return (1, -273.15)
case .pressure_msl:
return (1/100, 0)
default:
return nil
}
}
var omFileName: (file: String, level: Int) {
return (rawValue, 0)
}
var scalefactor: Float {
switch self {
case .temperature_2m: return 20
case .cloud_cover: return 1
case .cloud_cover_low: return 1
case .cloud_cover_mid: return 1
case .cloud_cover_high: return 1
case .precipitation: return 10
case .wind_v_component_10m: return 10
case .wind_u_component_10m: return 10
case .pressure_msl: return 10
}
}
var interpolation: ReaderInterpolation {
switch self {
case .temperature_2m:
return .hermite(bounds: nil)
case .cloud_cover:
return .linear
case .cloud_cover_low:
return .linear
case .cloud_cover_mid:
return .linear
case .cloud_cover_high:
return .linear
case .pressure_msl:
return .hermite(bounds: nil)
case .precipitation:
return .backwards_sum
case .wind_v_component_10m:
return .hermite(bounds: nil)
case .wind_u_component_10m:
return .hermite(bounds: nil)
}
}
var unit: SiUnit {
switch self {
case .temperature_2m: return .celsius
case .cloud_cover: return .percentage
case .cloud_cover_low: return .percentage
case .cloud_cover_mid: return .percentage
case .cloud_cover_high: return .percentage
case .precipitation: return .millimetre
case .wind_v_component_10m: return .metrePerSecond
case .wind_u_component_10m: return .metrePerSecond
case .pressure_msl: return .hectopascal
}
}
var isElevationCorrectable: Bool {
switch self {
case .temperature_2m:
return true
default:
return false
}
}
}
/**
Types of pressure level variables
*/
enum GfsGraphCastPressureVariableType: String, CaseIterable {
case temperature
case wind_u_component
case wind_v_component
case geopotential_height
case vertical_velocity
case relative_humidity
case specific_humdity
}
/**
A pressure level variable on a given level in hPa / mb
*/
struct GfsGraphCastPressureVariable: PressureVariableRespresentable, Hashable, GenericVariableMixable, GfsGraphCastVariableDownloadable {
let variable: GfsGraphCastPressureVariableType
let level: Int
var storePreviousForecast: Bool {
return false
}
var requiresOffsetCorrectionForMixing: Bool {
return false
}
var multiplyAdd: (multiply: Float, add: Float)? {
switch variable {
case .temperature:
return (1, -273.15)
case .specific_humdity:
return (1000, 0)
default:
return nil
}
}
var omFileName: (file: String, level: Int) {
return (rawValue, 0)
}
var scalefactor: Float {
// Upper level data are more dynamic and that is bad for compression. Use lower scalefactors
switch variable {
case .temperature:
// Use scalefactor of 2 for everything higher than 300 hPa
return (2..<10).interpolated(atFraction: (300..<1000).fraction(of: Float(level)))
case .wind_u_component:
fallthrough
case .wind_v_component:
// Use scalefactor 3 for levels higher than 500 hPa.
return (3..<10).interpolated(atFraction: (500..<1000).fraction(of: Float(level)))
case .geopotential_height:
return (0.05..<1).interpolated(atFraction: (0..<500).fraction(of: Float(level)))
case .relative_humidity:
return (0.2..<1).interpolated(atFraction: (0..<800).fraction(of: Float(level)))
case .vertical_velocity:
return (20..<100).interpolated(atFraction: (0..<500).fraction(of: Float(level)))
case .specific_humdity:
fatalError("should never be written to disk")
}
}
var interpolation: ReaderInterpolation {
switch variable {
case .temperature:
return .hermite(bounds: nil)
case .wind_u_component:
return .hermite(bounds: nil)
case .wind_v_component:
return .hermite(bounds: nil)
case .geopotential_height:
return .linear
case .relative_humidity:
return .hermite(bounds: 0...100)
case .vertical_velocity:
return .hermite(bounds: nil)
case .specific_humdity:
return .hermite(bounds: nil)
}
}
var unit: SiUnit {
switch variable {
case .temperature:
return .celsius
case .wind_u_component:
return .metrePerSecond
case .wind_v_component:
return .metrePerSecond
case .geopotential_height:
return .metre
case .relative_humidity:
return .percentage
case .vertical_velocity:
return .metrePerSecondNotUnitConverted
case .specific_humdity:
return .gramPerKilogram
}
}
var isElevationCorrectable: Bool {
return false
}
}
/**
Combined surface and pressure level variables with all definitions for downloading and API
*/
typealias GfsGraphCastVariable = SurfaceAndPressureVariable<GfsGraphCastSurfaceVariable, GfsGraphCastPressureVariable>
|