-
Notifications
You must be signed in to change notification settings - Fork 98
/
TimeDerivatives.jl
139 lines (116 loc) · 3.58 KB
/
TimeDerivatives.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
#####################
# TimeSpaceFunction #
#####################
"""
struct TimeSpaceFunction{F} <: Function end
`TimeSpaceFunction` allows for convenient ways to apply differential operators to
functions that depend on time and space. More precisely, if `f` is a function that, to
a given time, returns a function of space (i.e. `f` is evaluated at time `t` and position
`x` via `f(t)(x)`), then `F = TimeSpaceFunction(f)` supports the following syntax:
* `op(F)`: a `TimeSpaceFunction` representing both `t -> x -> op(f)(t)(x)` and `(t, x) -> op(f)(t)(x)`,
* `op(F)(t)`: a function of space representing `x -> op(f)(t)(x)`
* `op(F)(t, x)`: the quantity `op(f)(t)(x)` (this notation is equivalent to `op(F)(t)(x)`),
for all spatial and temporal differential operator, i.e. `op` in `(time_derivative,
gradient, symmetric_gradient, divergence, curl, laplacian)` and their symbolic aliases
(`∂t`, `∂tt`, `∇`, ...).
"""
struct TimeSpaceFunction{F} <: Function
f::F
end
(ts::TimeSpaceFunction)(t) = ts.f(t)
(ts::TimeSpaceFunction)(t, x) = ts.f(t)(x)
##################################
# Spatial differential operators #
##################################
# Using the rule spatial_op(ts)(t)(x) = spatial_op(ts(t))(x)
for op in (:(Fields.gradient), :(Fields.symmetric_gradient), :(Fields.divergence),
:(Fields.curl), :(Fields.laplacian))
@eval begin
function ($op)(ts::TimeSpaceFunction)
function _op(t)
_op_t(x) = $op(ts(t))(x)
_op_t
end
TimeSpaceFunction(_op)
end
end
end
#############################
# time_derivative interface #
#############################
"""
time_derivative(f::DerivableType) -> DerivableType
Build the first-order time derivative operator for `f`.
"""
function time_derivative(f)
@abstractmethod
end
"""
time_derivative(f::DerivableType, ::Val{k}) -> DerivableType
Build the `k`-th-order time derivative operator for `f`.
"""
function time_derivative(f, ::Val{0})
f
end
function time_derivative(f, ::Val{1})
time_derivative(f)
end
function time_derivative(f, ::Val{k}) where {k}
time_derivative(time_derivative(f), Val(k - 1))
end
"""
∂t(f::DerivableType) -> DerivableType
Build the first-th-order time derivative operator for `f`.
Alias for `time_derivative(f)`.
"""
function ∂t(f)
time_derivative(f)
end
"""
∂t(f::DerivableType, ::Val{k}) -> DerivableType
Build the `k`-th-order time derivative operator for `f`.
Alias for `time_derivative(f, Val(k))`.
"""
function ∂t(f, ::Val{k}) where {k}
time_derivative(f, Val(k))
end
"""
∂tt(f::DerivableType) -> DerivableType
Second-order time derivative operator for `f`.
Alias for `time_derivative(f, Val(2))`.
"""
function ∂tt(f)
time_derivative(f, Val(2))
end
#################################
# Specialisation for `Function` #
#################################
function time_derivative(f::Function)
function dfdt(t)
ft = f(t)
function dfdt_t(x)
T = return_type(ft, x)
_time_derivative(T, f, t, x)
end
dfdt_t
end
dfdt
end
function _time_derivative(T::Type{<:Real}, f, t, x)
partial(t) = f(t)(x)
ForwardDiff.derivative(partial, t)
end
function _time_derivative(T::Type{<:MultiValue}, f, t, x)
partial(t) = get_array(f(t)(x))
T(ForwardDiff.derivative(partial, t))
end
##########################################
# Specialisation for `TimeSpaceFunction` #
##########################################
function time_derivative(ts::TimeSpaceFunction)
TimeSpaceFunction(time_derivative(ts.f))
end
###############################
# Specialisation for `Number` #
###############################
time_derivative(x::Number) = zero(x)