StreamMacros.jl
StreamMacros.call_subst
StreamMacros.has_free_symb
StreamMacros.remove_blocks
StreamMacros.signature
StreamMacros.substitute_once
StreamMacros.substitutions
StreamMacros.sym_subst
StreamMacros.@define_stream
StreamMacros.@var_velo!_from_stream
StreamMacros.@var_velo_from_stream
StreamMacros.@velo!_from_stream
StreamMacros.@velo_from_stream
StreamMacros.@vorticity_from_stream
StreamMacros.call_subst
— Methodcall_subst(expr::Expr, f_sig, f_body)
Substitute all function calls of f
in expr
.
StreamMacros.has_free_symb
— Methodhas_free_symb(ex::Expr, bound_vars)
Does ex
contain a symbol that is not bound by bound_vars
?
StreamMacros.remove_blocks
— Methodremove_blocks(ex::Expr)
Clean up enclosing blocks to get to the core expression.
StreamMacros.signature
— Methodsignature [<f_name> <arg1> <arg2> ...]
A symbol is interpreted as a function without arguments.
StreamMacros.substitute_once
— Methodsubstitute_once(defns::Expr, target::Expr)
Perform all substitutions that are defined in code
once.
StreamMacros.substitutions
— Functionsubstitutions(code::Expr, variable::Symbol, knowns = [])
Perform all substitutions that are defined in code
until the resulting expression does not contain free variables. Variables can be bound by knowns
.
StreamMacros.sym_subst
— Methodsym_subst(expr, sym, s_expr)
Replace all occurences of sym
in expr
by s_expr
.
StreamMacros.@define_stream
— Macro@define_stream(name::Symbol, code::Expr)
Define a scalar stream function on $R^2$. The defining code can be a series of definitions in an enclosing begin ... end
-block and is treated as a series of symbolic substitutions. Starting from the symbol name
, substitutions are performed until the resulting expression only depends on x
, y
and t
.
The symbol name
is not brought into the namespace. To access the resulting vector field and variational equation use @velo_from_stream name
and @var_velo_from_stream name
This is a convenience macro for the case where you want to use @velo_from_stream
and @var_velo_from_stream
without typing the code twice. If you only use one, you might as well use @velo_from_stream name code
or @var_velo_from_stream
directly.
StreamMacros.@var_velo!_from_stream
— Macro@var_velo!_from_stream(name::Symbol, [code::Expr])
Same as @var_velo_from_stream
, but returns the in-place version of the (extended) velocity field.
StreamMacros.@var_velo_from_stream
— Macro@var_velo_from_stream(name::Symbol, [code::Expr])
Get the (state and tangent space) velocity field corresponding to a stream function on $\mathbb{R}^2$. The defining code can be a series of definitions (in an enclosing begin ... end
-block and is treated as a series of symbolic substitutions. Starting from the symbol name
, substitutions are performed until the resulting expression only depends on x
, y
and t
.
The macro returns an ODEFunction
with signature (U,p,t)
that returns an SMatrix{2,3}
: in the first column, one has the usual velocity, in the second to third column, one has the linearized velocity, both at position u = U[:,1]
at time t
. The parameter slot is not used and can be filled with nothing
when calling.
The macro can be called without the code
if the stream name
has been defined beforehand via @define_stream
.
We follow the "oceanographic" sign convention, whereby the velocity $v$ is derived from the stream function $\psi$ by $v = (-\partial_y\psi, \partial_x\psi).$
StreamMacros.@velo!_from_stream
— Macro@velo!_from_stream(name::Symbol, [code::Expr])
Same as @velo_from_stream
, but returns the in-place version of the velocity field.
StreamMacros.@velo_from_stream
— Macro@velo_from_stream(name::Symbol, [code::Expr])
Get the velocity field corresponding to a stream function on $\mathbb{R}^2$. The defining code can be a series of definitions (in an enclosing begin ... end
-block and is treated as a series of symbolic substitutions. Starting from the symbol name
, substitutions are performed until the resulting expression only depends on x
, y
and t
.
The macro returns an ODEFunction
with signature (u, p, t)
that returns an SVector{2}
corresponding to the vector field at position u
at time t
. The parameter slot is not used and can be filled with nothing
when calling.
The macro can be called without the code
if the stream name
has been defined beforehand via @define_stream
.
We follow the "oceanographic" sign convention, whereby the velocity $v$ is derived from the stream function $\psi$ by $v = (-\partial_y\psi, \partial_x\psi).$
Examples
julia> using CoherentStructures
julia> f = @velo_from_stream Ψ_ellipse begin
Ψ_ellipse = a*x^2 + b*y^2
a = t
b = 3
end
(#3) #1 (generic function with 1 method)
julia> f([1.0,1.0], nothing, 1.0)
2-element StaticArrays.SArray{Tuple{2},Float64,1,2}:
-6.0
2.0
julia> using CoherentStructures
julia> @define_stream Ψ_circular begin
Ψ_circular = f(x) + g(y)
# naming of function variables
# does not matter:
f(a) = a^2
g(y) = y^2
end
julia> f2 = @velo_from_stream Ψ_circular
(#5) #1 (generic function with 1 method)
julia> f2([1.0,1.0], nothing, 0.0)
2-element StaticArrays.SArray{Tuple{2},Float64,1,2}:
-2.0
2.0
StreamMacros.@vorticity_from_stream
— Macro@vorticity_from_stream(name::Symbol, [code::Expr])
Get the vorticity field as a function of (x, y, t)
corresponding to a stream function on $\mathbb{R}^2$.
The vorticity $\omega$ of the velocity field $v = (v_x, v_y)$ is defined as derived from the stream function $\psi$ by $\omega = \partial_x v_x - \partial_y v_y = tr(\nabla^2\psi)$, i.e., the trace of the Hessian of the stream function.