-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStations.jl
223 lines (151 loc) · 5.12 KB
/
Stations.jl
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
module Stations
using Utils
import Utils.GeoLoc
using Calendar
import Calendar.CalendarTime
import Base.show
abstract AbstractStation
type Observation
# station of origin
station::AbstractStation
# observation time
tm::CalendarTime
# observed value
value::Float64
# name of the variable
obs_type::String
# variance of the observation
var :: Float64
# default constructor
Observation(s, tm, value, obs_type, var) = new(s, tm, value, obs_type, var)
end
type Station <: AbstractStation
# station id
id::String
# station name
name::String
# station location (lat/lon decimal)
loc::GeoLoc
# nearest grid point (tuple)
ngp::(Int64, Int64)
# station elevation (meters)
elevation::Float64
# dictionary mapping variable names to observations
obs::Dict{String,Array{Observation}}
# available observation types from the station
sensors :: Array{String}
Station() = new("", "", GeoLoc(0.0, 0.0), (-1,-1), 0.0, Dict{String,Array{Observation}}(), Array(String,0))
Station(id, name, loc, elevation) = new(id, name, loc, (-1,-1), elevation, Dict{String,Array{Observation}}(), Array(String,0))
end
obs_variance(o::Observation) = o.var
obs_value(o::Observation) = o.value
obs_type(o::Observation) = o.obs_type
obs_station(o::Observation) = o.station
obs_station_id(o::Observation) = o.station.id
nearest_grid_point(o::Observation) = o.station.ngp
function show(io::IO, o::Observation)
# write(io, "Obs($o.value of $o.obs_type at $o.station.id, $o.tm with var $o.var)")
print(io, "Obs(", o.obs_type, "=", o.value, " at ", o.station.id, ", ", o.tm, " with var ", o.var, ")")
end
obs_times(s::Station, obs_type::String) = [o.tm for o in observations(s, obs_type)]
obs_var(s::Station, obs_type::String) = s.obs[obs_type]
id(s::Station) = s.id
name(s::Station) = s.name
observations(s::Station, obs_type::String) = s.obs[obs_type]
function register_to_grid(s::Station, lat::Array{Float64,2}, lon::Array{Float64,2})
s.ngp = ind2sub(size(lat), indmin( (s.loc.lat - lat).^2 + (s.loc.lon - lon).^2 ))
end
function observations(s::Station, obs_type::String, tm::Array{CalendarTime})
# retrieve all the observations for the given type
obs = s.obs[obs_type]
otm = [o.tm for o in obs]
obs_ret = Dict(CalendarTime, Observation)
i, j = 1, 1
while (i <= length(tm)) && (j <= length(otm))
if tm[i] == otm[j]
obs_ret[tm[i]] = obs[i]
i += 1
j += 1
elseif tm[i] > obst[j]
j += 1
elseif tm[i] < obst[j]
j += 1
end
end
return obs_ret
end
function load_station_info(fname :: String)
s = Station()
# open file
io = open(fname, "r")
# read station id
s.id = strip(readline_skip_comments(io))
# read station name
s.name = strip(readline_skip_comments(io))
# read station geo location
s.loc = Utils.parse_geolocation(readline_skip_comments(io))
# read elevation
s.elevation = float(strip(readline_skip_comments(io)))
# read all observation types acquired by the station
s.sensors = map(x -> strip(x), split(readline_skip_comments(io), ","))
# create var time series containers
for v in s.sensors
s.obs[v] = Array(Float64, 0)
end
# close the info file
close(io)
return s
end
function load_station_data(s::Station, fname::String)
# open file
io = open(fname, "r")
# read observations, time is first (and in GMT), then one value per measurement or nan if not available
while !eof(io)
# read the date (if cannot read date, file is empty)
tm_line = readline_skip_comments(io)
if tm_line == nothing break end
tm_str = strip(tm_line)
tm = Calendar.parse("yyyy-MM-dd_HH:mm", tm_str, "GMT")
# read in observed variables
variables = map(x -> strip(x), split(readline_skip_comments(io), ","))
# read in observed values
vals = map(x -> float(x), split(readline_skip_comments(io), ","))
# read in variances of observations
variances = map(x -> float(x), split(readline_skip_comments(io), ","))
# add each observation to the station dictionary
for i in 1:length(variables)
var = variables[i]
push!(s.obs[var], Observation(s, tm, vals[i], var, variances[i]))
end
end
# cleanup
close(io)
# return the created station
return s
end
function build_observation_data(ss::Array{Station}, obs_type::String)
Ns = length(ss)
obs = Observation[]
# observation data
for s in ss
append!(obs, observations(s, obs_type))
end
# repackage into a time-indexed structure
obs_data = Dict{CalendarTime,Array{Observation}}()
for o in obs
if haskey(obs_data, o.tm) push!(obs_data[o.tm], o) else obs_data[o.tm] = [o] end
end
return obs_data
end
function readline_skip_comments(io :: IO)
s = "#"
while (length(s) == 0) || (s[1] == '#')
if !eof(io)
s = readline(io)
else
return nothing
end
end
return s
end
end