Skip to content

Commit a165b64

Browse files
authored
Merge pull request #191 from gaelforget/TimeAxis_dev
add TimeAxis (new) to FlowFields, define TimePeriod (mutable)
2 parents c1666eb + ca57d7c commit a165b64

4 files changed

Lines changed: 122 additions & 29 deletions

File tree

src/API.jl

Lines changed: 97 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,78 @@
33

44
using Dates
55

6+
7+
abstract type AbstractTimeAxis end
8+
abstract type AbstractTimePeriod end
9+
10+
"""
11+
struct TimeAxis{Ty} <: AbstractTimeAxis
12+
13+
Time axis specification for `FlowFields` data structure. This un-mutable specification
14+
describes the overall range of simulations that can be performed using the `FlowFields`.
15+
16+
- initial : beginning of simulation period
17+
- final : end of simulation period
18+
- origin : beginning of the valid time period, when flow fields are available
19+
- horizon : end of the valid time period, when flow fields are available
20+
- climatology : false by default ; but can be set to true for time-periodic flow fields.
21+
22+
Rules :
23+
24+
- In most simple cases `origin,horizon` is just the same as `initial,final`.
25+
- By default `initial,final` and `origin,horizon` are set to the `FlowField`'s `TimePeriod`.
26+
- However, any specification where `initial,final` is within `origin,horizon` is correct.
27+
- This more general approach makes it easy to split simulations into smaller intervals.
28+
29+
```
30+
using Drifters, Dates
31+
32+
D0=DateTime(2000,1,1)
33+
D1=DateTime(2000,3,1)
34+
TA=Drifters.TimeAxis(D0,D1)
35+
TA=Drifters.TimeAxis(D0,D1,D0,D1,false)
36+
```
37+
"""
38+
struct TimeAxis{Ty} <: AbstractTimeAxis
39+
initial::Ty
40+
final::Ty
41+
origin::Ty
42+
horizon::Ty
43+
Climatology::Bool
44+
end
45+
46+
TimeAxis(t0=0.0,t1=1.0) = TimeAxis(t0,t1,t0,t1,false)
47+
48+
"""
49+
struct TimePeriod{Ty} <: AbstractTimePeriod
50+
51+
Time period for next simulation of `Individuals` displacement specified
52+
as a vector `[initial,final]`. The `value` field is a mutable vector that
53+
can be changed, e.g. within a time loop when carrying out longer simulations.
54+
55+
Rules :
56+
57+
- if `final` precedes `initial` then the simulation goes backward in time
58+
- in most simple cases, `initial,final` are the same in `TimePeriod` and `TimeAxis`.
59+
- but any `initial,final` within the periods defined in 'TimeAxis` works for `TimePeriod`.
60+
61+
```
62+
using Drifters, Dates
63+
64+
D0=DateTime(2000,1,1)
65+
D1=DateTime(2000,3,1)
66+
TP=Drifters.TimePeriod([D0,D1])
67+
TA=Drifters.TimeAxis(TP)
68+
```
69+
"""
70+
struct TimePeriod{Ty} <: AbstractTimePeriod
71+
value::Array{Ty,1}
72+
end
73+
74+
TimePeriod(T0,T1) = TimePeriod([T0,T1])
75+
76+
TimeAxis(TP::TimePeriod) = TimeAxis(TP.value...)
77+
678
"""
779
abstract type FlowFields
880
@@ -53,17 +125,20 @@ struct uvArrays{Ty} <: FlowFields
53125
v0::Array{Ty,2}
54126
v1::Array{Ty,2}
55127
T::Union{Array{Ty},Array{DateTime}}
128+
TimeAxis::AbstractTimeAxis
56129
end
57130

58131
function FlowFields(u0::Array{Ty,2},u1::Array{Ty,2},
59-
v0::Array{Ty,2},v1::Array{Ty,2},T::Union{Array,Tuple}) where Ty
132+
v0::Array{Ty,2},v1::Array{Ty,2},T::Union{Array,Tuple};
133+
time_axis=missing) where Ty
60134
#ensure T is a vector and enforce type
61135
T=time_set_type.(collect(T),Ty)
136+
TA=(ismissing(time_axis) ? TimeAxis(T...) : time_axis)
62137
#check array size concistency
63138
tst=prod([(size(u0)==size(tmp)) for tmp in (u1,v0,v1)])
64139
!tst ? error("inconsistent array sizes") : nothing
65140
#call constructor
66-
uvArrays(u0,u1,v0,v1,T)
141+
uvArrays(u0,u1,v0,v1,T,TA)
67142
end
68143

69144
struct uvwArrays{Ty} <: FlowFields
@@ -74,6 +149,7 @@ struct uvwArrays{Ty} <: FlowFields
74149
w0::Array{Ty,3}
75150
w1::Array{Ty,3}
76151
T::Union{Array{Ty},Array{DateTime}}
152+
TimeAxis::AbstractTimeAxis
77153
end
78154

79155
"""
@@ -90,7 +166,7 @@ F=FlowFields(u=uC,v=vC,period=(0,10.))
90166
```
91167
"""
92168
function FlowFields(; u::Union{Array,Tuple}=[], v::Union{Array,Tuple}=[], w::Union{Array,Tuple}=[],
93-
period::Union{Array,Tuple}=[])
169+
period::Union{Array,Tuple}=[], time_axis=missing)
94170
(isa(u,Tuple)||length(u[:])==2) ? (u0=u[1]; u1=u[2]) : (u0=u; u1=u)
95171
(isa(v,Tuple)||length(v[:])==2) ? (v0=v[1]; v1=v[2]) : (v0=v; v1=v)
96172
(isa(w,Tuple)||length(w[:])==2) ? (w0=w[1]; w1=w[2]) : (w0=w; w1=w)
@@ -99,9 +175,9 @@ function FlowFields(; u::Union{Array,Tuple}=[], v::Union{Array,Tuple}=[], w::Uni
99175
end
100176
if !isempty(u0) && !isempty(v0)
101177
if !isempty(w0)
102-
FlowFields(u0,u1,v0,v1,w0,w1,period)
178+
FlowFields(u0,u1,v0,v1,w0,w1,period,time_axis=time_axis)
103179
else
104-
FlowFields(u0,u1,v0,v1,period)
180+
FlowFields(u0,u1,v0,v1,period,time_axis=time_axis)
105181
end
106182
else
107183
[]
@@ -139,15 +215,16 @@ to_C_grid!(x;dims=0) = begin
139215
end
140216

141217
function FlowFields(u0::Array{Ty,3},u1::Array{Ty,3},v0::Array{Ty,3},v1::Array{Ty,3},
142-
w0::Array{Ty,3},w1::Array{Ty,3},T::Union{Array,Tuple}) where Ty
218+
w0::Array{Ty,3},w1::Array{Ty,3},T::Union{Array,Tuple}; time_axis=missing) where Ty
143219
#ensure T is a vector and enforce type
144220
T=time_set_type.(collect(T),Ty)
221+
TA=(ismissing(time_axis) ? TimeAxis(T...) : time_axis)
145222
#check array size concistency
146223
tst=prod([(size(u0)==size(tmp)) for tmp in (u1,v0,v1)])
147224
tst=tst*prod([(size(u0)==size(tmp).-(0,0,1)) for tmp in (w0,w1)])
148225
!tst ? error("inconsistent array sizes") : nothing
149226
#call constructor
150-
uvwArrays(u0,u1,v0,v1,w0,w1,T)
227+
uvwArrays(u0,u1,v0,v1,w0,w1,T,TA)
151228
end
152229

153230
struct uvMeshArrays{Ty} <: FlowFields
@@ -156,26 +233,28 @@ struct uvMeshArrays{Ty} <: FlowFields
156233
v0::AbstractMeshArray{Ty,1}
157234
v1::AbstractMeshArray{Ty,1}
158235
T::Union{Array{Ty},Array{DateTime}}
236+
TimeAxis::AbstractTimeAxis
159237
update_location!::Function
160238
end
161239

162240
function FlowFields(u0::MeshArrays.MeshArray_wh,u1::MeshArrays.MeshArray_wh,
163241
v0::MeshArrays.MeshArray_wh,v1::MeshArrays.MeshArray_wh,
164-
T::Union{Array,Tuple},update_location!::Function)
242+
T::Union{Array,Tuple},update_location!::Function; time_axis=missing)
165243

166-
FlowFields(u0.MA,u1.MA,v0.MA,v1.MA,T,update_location!)
244+
FlowFields(u0.MA,u1.MA,v0.MA,v1.MA,T,update_location!,time_axis=time_axis)
167245
end
168246

169247
function FlowFields(u0::AbstractMeshArray{Ty,1},u1::AbstractMeshArray{Ty,1},
170248
v0::AbstractMeshArray{Ty,1},v1::AbstractMeshArray{Ty,1},
171-
T::Union{Array,Tuple},update_location!::Function) where Ty
249+
T::Union{Array,Tuple},update_location!::Function; time_axis=missing) where Ty
172250
#ensure T is a vector and enforce type
173251
T=time_set_type.(collect(T),Ty)
252+
TA=(ismissing(time_axis) ? TimeAxis(T...) : time_axis)
174253
#check array size concistency
175254
tst=prod([(size(u0)==size(tmp))*(u0.fSize==tmp.fSize) for tmp in (u1,v0,v1)])
176255
!tst ? error("inconsistent array sizes") : nothing
177256
#call constructor
178-
uvMeshArrays(u0,u1,v0,v1,T,update_location!)
257+
uvMeshArrays(u0,u1,v0,v1,T,TA,update_location!)
179258
end
180259

181260
struct uvwMeshArrays{Ty} <: FlowFields
@@ -186,30 +265,32 @@ struct uvwMeshArrays{Ty} <: FlowFields
186265
w0::AbstractMeshArray{Ty,2}
187266
w1::AbstractMeshArray{Ty,2}
188267
T::Union{Array{Ty},Array{DateTime}}
268+
TimeAxis::AbstractTimeAxis
189269
update_location!::Function
190270
end
191271

192272
function FlowFields(u0::MeshArrays.MeshArray_wh,u1::MeshArrays.MeshArray_wh,
193273
v0::MeshArrays.MeshArray_wh,v1::MeshArrays.MeshArray_wh,
194274
w0::MeshArrays.MeshArray_wh,w1::MeshArrays.MeshArray_wh,
195-
T::Union{Array,Tuple},update_location!::Function)
275+
T::Union{Array,Tuple},update_location!::Function; time_axis=missing)
196276

197-
FlowFields(u0.MA,u1.MA,v0.MA,v1.MA,w0.MA,w1.MA,T,update_location!)
277+
FlowFields(u0.MA,u1.MA,v0.MA,v1.MA,w0.MA,w1.MA,T,update_location!,time_axis=time_axis)
198278
end
199279

200280
function FlowFields(u0::AbstractMeshArray{Ty,2},u1::AbstractMeshArray{Ty,2},
201281
v0::AbstractMeshArray{Ty,2},v1::AbstractMeshArray{Ty,2},
202282
w0::AbstractMeshArray{Ty,2},w1::AbstractMeshArray{Ty,2},
203-
T::Union{Array,Tuple},update_location!::Function) where Ty
283+
T::Union{Array,Tuple},update_location!::Function; time_axis=missing) where Ty
204284
#ensure T is a vector and enforce type
205285
T=time_set_type.(collect(T),Ty)
286+
TA=(ismissing(time_axis) ? TimeAxis(T...) : time_axis)
206287
#check array size consistency
207288
tst=prod([(size(u0)==size(tmp))*(u0.fSize==tmp.fSize) for tmp in (u1,v0,v1)])
208289
tst=tst*prod([(size(u0)==size(tmp).-(0,1))*(u0.fSize==tmp.fSize) for tmp in (w0,w1)])
209290
!tst ? error("inconsistent array sizes") : nothing
210291

211292
#call constructor
212-
uvwMeshArrays(u0,u1,v0,v1,w0,w1,T,update_location!)
293+
uvwMeshArrays(u0,u1,v0,v1,w0,w1,T,TA,update_location!)
213294
end
214295

215296
"""
@@ -230,7 +311,7 @@ function ensemble_solver(prob::ODEProblem;solver=Tsit5(),reltol=1e-8,abstol=1e-8
230311
end
231312

232313
a=fill(0.0,1,1)
233-
default_flowfields = uvArrays{Float64}(a,a,a,a,[0. 1.])
314+
default_flowfields = uvArrays{Float64}(a,a,a,a,[0. 1.],TimeAxis(0.,1.))
234315
default_recorder = DataFrame(ID=Int[], x=Float64[], y=Float64[], t=Float64[])
235316
default_postproc = (x->x)
236317

src/data_wrangling.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function convert_to_FlowFields(U::Array{T,2},V::Array{T,2},t1::T; time_option=:d
3030
error("unknown time_option")
3131
end
3232
)
33-
uvMeshArrays{eltype(u.MA)}(u.MA,u.MA,v.MA,v.MA,TT,func)
33+
uvMeshArrays{eltype(u.MA)}(u.MA,u.MA,v.MA,v.MA,TT,TimeAxis(TT...),func)
3434
end
3535

3636
"""

src/example_ECCO.jl

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Dates: DateTime, Year, Month, Day
55

66
import Drifters: postprocess_MeshArray, add_lonlat!, OrdinaryDiffEq
77
import Drifters: time_in_seconds, time_in_DateTime, monthly_records
8+
import Drifters: TimeAxis, TimePeriod
89

910
import OrdinaryDiffEq: solve, Tsit5, ODEProblem
1011
import Drifters: update_location!, Individuals, uvMeshArrays, uvwMeshArrays
@@ -67,7 +68,15 @@ function setup_FlowFields(k::Int,Γ::NamedTuple,func::Function,pth::String;
6768

6869
mon=86400.0*365.0/12.0
6970
T=(time_unit==:DateTime ? [DateTime(1999,12,15),DateTime(2000,1,15)] : [-mon/2,mon/2])
70-
71+
if time_unit==:DateTime
72+
D0=DateTime(1992,1,1)
73+
D1=DateTime(2011,1,1) #this corresponds to ECCO4 release 1
74+
TA=TimeAxis(D0,D1,D0,D1,true) #true corresponds to monthly climatology input
75+
else
76+
t_final=100*365*86400.0
77+
TA=TimeAxis(0.0,t_final,0.0,t_final,true)
78+
end
79+
7180
if k==0
7281
msk=Γ.hFacC
7382
msk=1.0*(msk .> 0.0)
@@ -76,14 +85,14 @@ function setup_FlowFields(k::Int,Γ::NamedTuple,func::Function,pth::String;
7685
P=FlowFields(exchange(MeshArray(γ,Float32,nr)),exchange(MeshArray(γ,Float32,nr)),
7786
exchange(MeshArray(γ,Float32,nr)),exchange(MeshArray(γ,Float32,nr)),
7887
exchange(MeshArray(γ,Float32,nr+1)),exchange(MeshArray(γ,Float32,nr+1)),
79-
T,func)
88+
T,func,time_axis=TA)
8089
else
8190
msk=Γ.hFacC[:, k]
8291
msk=1.0*(msk .> 0.0)
8392
exmsk=exchange(msk).MA
8493
P=FlowFields(exchange(MeshArray(γ,Float32)),exchange(MeshArray(γ,Float32)),
8594
exchange(MeshArray(γ,Float32)),exchange(MeshArray(γ,Float32)),
86-
T,func)
95+
T,func,time_axis=TA)
8796
end
8897

8998
D = (🔄 = update_FlowFields!, pth=pth, datasets=datasets,
@@ -326,7 +335,7 @@ function init_FlowFields(; k=1, backward_time=false, time_unit=:DateTime, dpth::
326335

327336
#initialize u0,u1 etc arrays
328337
P,D=setup_FlowFields(k,Γ,func,dpth,
329-
backward_time=backward_time, time_unit=time_unit,datasets=datasets)
338+
backward_time=backward_time,time_unit=time_unit,datasets=datasets)
330339

331340
#add background map for plotting
332341
λ=get_interp_coefficients(Γ)

src/example_OCCA.jl

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module OCCA
22

33
import Drifters: data_path, uvwMeshArrays, FlowFields
44
import Drifters: postprocess_MeshArray, add_lonlat!, interp_to_xy
5+
import Drifters: TimeAxis, TimePeriod
56

67
##
78

@@ -57,14 +58,12 @@ function setup(;backward_in_time::Bool=false,nmax=Inf)
5758
ii=findall([!in(i,jj) for i in keys(Γ)])
5859
Γ=(; zip(Symbol.(keys(Γ)[ii]), values(Γ)[ii])...)
5960

60-
backward_in_time ? s=-1.0 : s=1.0
61-
s=Float32(s)
6261
pth=data_path(:OCCA)
6362

64-
u=s*read(read_data("u",pth,n),MeshArray(γ,Float32,n))
65-
v=s*read(read_data("v",pth,n),MeshArray(γ,Float32,n))
63+
u=read(read_data("u",pth,n),MeshArray(γ,Float32,n))
64+
v=read(read_data("v",pth,n),MeshArray(γ,Float32,n))
6665

67-
w=s*read_data("w",pth,n)
66+
w=read_data("w",pth,n)
6867
w=-cat(w,zeros(360, 160),dims=3)
6968
w[:,:,1] .=0.0
7069
w=read(w,MeshArray(γ,Float32,n+1))
@@ -98,12 +97,16 @@ function setup(;backward_in_time::Bool=false,nmax=Inf)
9897
Γ.XG[1]=tmpx
9998
Γ.Depth[1]=circshift.Depth[1],[-180 0])
10099

101-
t0=0.0; t1=86400*366*2.0;
102-
103100
(u,v)=exchange(u,v)
104101
w=exchange(w)
105102

106-
P=FlowFields(u,u,v,v,w,w,[t0,t1],func)
103+
backward_in_time ? s=-1.0 : s=1.0
104+
t0=0.0; t1=s*86400*366*2.0;
105+
106+
t_final=100*365*86400.0
107+
TA=TimeAxis(-t_final,t_final,0.0,s*t_final,true)
108+
109+
P=FlowFields(u,u,v,v,w,w,[t0,t1],func,time_axis=TA)
107110

108111
XC=exchange.XC)
109112
YC=exchange.YC)

0 commit comments

Comments
 (0)