Other formats: This can also be accessed as a Jupyter notebook or a plain script.
Lorenz63 example
Note: The packages for this example are documented in the Project.toml, except for some unregistered packages.
First, we'll set up the environment, which entails installing and importing packages.
# Install unregistered packages.
using Pkg: Pkg
using Ensembles
try
using Lorenz63: Lorenz63
catch
Ensembles.install(:Lorenz63)
end
try
using EnsembleKalmanFilters: EnsembleKalmanFilters
catch
Ensembles.install(:EnsembleKalmanFilters)
end
try
using NormalizingFlowFilters: NormalizingFlowFilters
catch
Ensembles.install(:NormalizingFlowFilters)
end
# Define a macro for doing imports to avoid duplicating it for remote processes later on.
macro initial_imports()
return esc(
quote
using Ensembles
using LinearAlgebra: norm
using Distributed: addprocs, rmprocs, @everywhere, remotecall, fetch, WorkerPool
using Test: @test
using Random: Random
using CairoMakie
using Lorenz63: Lorenz63
ext = Base.get_extension(Ensembles, :Lorenz63Ext)
using .ext
using EnsembleKalmanFilters: EnsembleKalmanFilters
ext = Base.get_extension(Ensembles, :EnsembleKalmanFiltersExt)
using .ext
using Statistics: Statistics, mean, var
using LinearAlgebra: Diagonal
using EnsembleKalmanFilters: EnKF
end
)
end
@initial_imports
worker_initial_imports = @macroexpand1 @initial_imports
include("../_utils/utils.jl"); Cloning git-repo `https://github.com/milankl/Lorenz63.jl#15220a7`
Updating git-repo `https://github.com/milankl/Lorenz63.jl#15220a7`
Resolving package versions...
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Project.toml`
[72db8b11] + Lorenz63 v0.1.0 `https://github.com/milankl/Lorenz63.jl#15220a7#master`
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Manifest.toml`
[72db8b11] + Lorenz63 v0.1.0 `https://github.com/milankl/Lorenz63.jl#15220a7#master`
Cloning git-repo `https://github.com/DataAssimilation/EnsembleKalmanFilters.jl`
Updating git-repo `https://github.com/DataAssimilation/EnsembleKalmanFilters.jl`
Resolving package versions...
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Project.toml`
[489b957c] + EnsembleKalmanFilters v0.0.1 `https://github.com/DataAssimilation/EnsembleKalmanFilters.jl#main`
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Manifest.toml`
[489b957c] + EnsembleKalmanFilters v0.0.1 `https://github.com/DataAssimilation/EnsembleKalmanFilters.jl#main`
Precompiling project...
15384.2 ms ✓ EnsembleKalmanFilters
5884.9 ms ✓ Ensembles → EnsembleKalmanFiltersExt
2 dependencies successfully precompiled in 22 seconds. 338 already precompiled.
1 dependency had output during precompilation:
┌ EnsembleKalmanFilters
│ CondaPkg Found dependencies: /home/runner/.julia/packages/JOLI/2dSnd/CondaPkg.toml
│ CondaPkg Found dependencies: /home/runner/.julia/packages/PythonCall/WMWY0/CondaPkg.toml
│ CondaPkg Resolving changes
│ + libstdcxx-ng
│ + openssl
│ + python
│ + pywavelets
│ CondaPkg Initialising pixi
│ │ /home/runner/.julia/artifacts/cefba4912c2b400756d043a2563ef77a0088866b/bin/pixi
│ │ init
│ │ --format pixi
│ └ /home/runner/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/.CondaPkg
│ ✔ Created /home/runner/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/.CondaPkg/pixi.toml
│ CondaPkg Wrote /home/runner/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/.CondaPkg/pixi.toml
│ │ [dependencies]
│ │ openssl = ">=3, <3.1"
│ │ libstdcxx-ng = ">=3.4,<13.0"
│ │ pywavelets = "*"
│ │
│ │ [dependencies.python]
│ │ channel = "conda-forge"
│ │ build = "*cpython*"
│ │ version = ">=3.8,<4"
│ │
│ │ [project]
│ │ name = ".CondaPkg"
│ │ platforms = ["linux-64"]
│ │ channels = ["conda-forge"]
│ │ channel-priority = "strict"
│ └ description = "automatically generated by CondaPkg.jl"
│ CondaPkg Installing packages
│ │ /home/runner/.julia/artifacts/cefba4912c2b400756d043a2563ef77a0088866b/bin/pixi
│ │ install
│ └ --manifest-path /home/runner/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/.CondaPkg/pixi.toml
│ ✔ The default environment has been installed.
└
Cloning git-repo `https://github.com/DataAssimilation/NormalizingFlowFilters.jl`
Updating git-repo `https://github.com/DataAssimilation/NormalizingFlowFilters.jl`
Resolving package versions...
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Project.toml`
⌅ [bb331ad6] ↓ JOLI v0.9.0 ⇒ v0.8.5
[bdff3154] + NormalizingFlowFilters v0.0.1 `https://github.com/DataAssimilation/NormalizingFlowFilters.jl#main`
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Manifest.toml`
[4fba245c] + ArrayInterface v7.18.0
[a9b6321e] + Atomix v1.1.1
[ab4f0b2a] + BFloat16s v0.5.1
[62783981] + BitTwiddlingConvenienceFunctions v0.1.6
[2a0fbf3d] + CPUSummary v0.2.6
[052768ef] + CUDA v5.7.2
[1af6417a] + CUDA_Runtime_Discovery v0.3.5
[aafaddc9] + CatIndices v0.2.2
[082447d4] + ChainRules v1.72.3
[fb6a15b2] + CloseOpenIntervals v0.1.13
[bbf7d656] + CommonSubexpressions v0.3.1
[f70d9fcc] + CommonWorldInvalidations v1.0.0
[ed09eef8] + ComputationalResources v0.3.2
[8f4d0f93] + Conda v1.10.2
[992eb4ea] - CondaPkg v0.2.28
[5218b696] + Configurations v0.17.6
[150eb455] + CoordinateTransformations v0.6.4
[adafc99b] + CpuId v0.3.1
[a8cc5b0e] + Crayons v4.1.1
[dc8bdbbb] + CustomUnitRanges v1.0.2
[a93c6f00] + DataFrames v1.7.0
[8bb1440f] + DelimitedFiles v1.9.1
[163ba53b] + DiffResults v1.1.0
[b552c78f] + DiffRules v1.15.1
[b4f34e82] + Distances v0.10.12
[e2ba6199] + ExprTools v0.1.10
[55351af7] + ExproniconLite v0.10.14
[4f61f5a4] + FFTViews v0.3.2
⌅ [587475ba] + Flux v0.14.25
[f6369f11] + ForwardDiff v1.0.1
⌅ [d9f16b24] + Functors v0.4.12
[0c68f7d7] + GPUArrays v11.2.2
[46192b85] + GPUArraysCore v0.2.0
[61eb1bfa] + GPUCompiler v1.3.2
[096a3bc2] + GPUToolbox v0.2.0
[076d061b] + HashArrayMappedTries v0.2.0
[3e5b6fbb] + HostCPUFeatures v0.1.17
[7869d1d1] + IRTools v0.4.14
[615f187c] + IfElse v0.1.1
[f332f351] + ImageContrastAdjustment v0.3.12
[51556ac3] + ImageDistances v0.2.17
[6a3955dd] + ImageFiltering v0.7.9
[787d08f9] + ImageMorphology v0.4.6
[2996bd0c] + ImageQualityIndexes v0.3.7
[02fcd773] + ImageTransformations v0.10.1
[842dd82b] + InlineStrings v1.4.3
[41ab1584] + InvertedIndices v1.3.1
[b7115f24] + InvertibleNetworks v2.3.0
⌅ [bb331ad6] ↓ JOLI v0.9.0 ⇒ v0.8.5
[0f8b85d8] - JSON3 v1.14.2
[63c18a36] + KernelAbstractions v0.9.34
[929cbde3] + LLVM v9.2.0
[8b046642] + LLVMLoopInfo v1.0.0
[10f19ff3] + LayoutPointers v0.1.17
[bdcacae8] + LoopVectorization v0.12.172
[c2834f40] + MLCore v1.0.0
⌃ [7e8f7934] + MLDataDevices v1.5.3
[f1d291b0] + MLUtils v0.4.8
[d125e4d3] + ManualMemory v0.1.8
[0b3b1443] - MicroMamba v0.1.14
[872c559c] + NNlib v0.9.30
[5da4648a] + NVTX v1.0.0
[bdff3154] + NormalizingFlowFilters v0.0.1 `https://github.com/DataAssimilation/NormalizingFlowFilters.jl#main`
[0b1bfda6] + OneHotArrays v0.2.7
⌅ [3bd65402] + Optimisers v0.3.4
[d96e819e] + Parameters v0.12.3
[fa939f87] - Pidfile v1.3.0
[1d0040c9] + PolyesterWeave v0.2.2
[2dfb63ee] + PooledArrays v1.4.3
[08abe8d2] + PrettyTables v2.4.0
[33c8b6b6] + ProgressLogging v0.1.4
[438e738f] + PyCall v1.96.4
[6099a3de] - PythonCall v0.9.24
[94ee1d12] + Quaternions v0.7.6
[74087812] + Random123 v1.7.0
[e6cf234a] + RandomNumbers v1.6.0
[c1ae055f] + RealDot v0.1.0
[6038ab10] + Rotations v1.7.1
[94e857df] + SIMDTypes v0.1.0
[476501e8] + SLEEFPirates v0.6.43
[7e506255] + ScopedValues v1.3.0
[91c51154] + SentinelArrays v1.4.8
[605ecd9f] + ShowCases v0.1.0
[dc90abb0] + SparseInverseSubset v0.1.2
[aedffcd0] + Static v1.2.0
[0d7ed370] + StaticArrayInterface v1.8.0
[892a3eda] + StringManipulation v0.4.1
[856f2bd8] - StructTypes v1.11.0
[8290d209] + ThreadingUtilities v0.5.3
[06e1c1a7] + TiledIteration v0.5.0
[a759f4b9] + TimerOutputs v0.5.28
[3a884ed6] + UnPack v1.0.2
[013be700] + UnsafeAtomics v0.3.0
[e17b2a0c] - UnsafePointers v1.0.0
[3d5dd08c] + VectorizationBase v0.21.71
[81def892] + VersionParsing v1.3.0
⌅ [e88e6eb3] + Zygote v0.6.76
[700de1a5] + ZygoteRules v0.2.7
[02a925ec] + cuDNN v1.4.2
[4ee394cb] + CUDA_Driver_jll v0.12.1+1
[76a88914] + CUDA_Runtime_jll v0.16.1+0
⌅ [62b44479] + CUDNN_jll v9.4.0+0
[9c1d0b0a] + JuliaNVTXCallbacks_jll v0.2.1+0
[dad2f222] + LLVMExtra_jll v0.0.35+0
[e98f9f5b] + NVTX_jll v3.1.1+0
[1e29f10c] + demumble_jll v1.3.0+0
[f8abcde7] - micromamba_jll v1.5.8+0
[4d7b5844] - pixi_jll v0.41.3+0
Info Packages marked with ⌃ and ⌅ have new versions available. Those with ⌃ may be upgradable, but those with ⌅ are restricted by compatibility constraints from upgrading. To see why use `status --outdated -m`
Precompiling project...
2316.2 ms ✓ EnsembleKalmanFilters
3357.6 ms ✓ Ensembles → EnsembleKalmanFiltersExt
2 dependencies successfully precompiled in 6 seconds. 475 already precompiled.
Define parameters.
params = Dict(
"format" => "v0.1",
"transition" => Dict(
"sigma" => 10,
"rho" => 28,
"beta" => 8 / 3,
"scaling" => 1,
"ministep_nt" => missing,
"ministep_dt" => 0.05,
),
"observation" =>
Dict("noise_scale" => 2, "timestep_size" => 0.1, "num_timesteps" => 300),
"ensemble" => Dict(
"size" => 10,
"seed" => 9347215,
"prior" => "gaussian",
"prior_params" => [0.0, 1.0],
),
"spinup" => Dict(
"num_timesteps" => 300,
"transition_noise_scale" => 1.0,
# EnKF params
"algorithm" => "enkf",
"include_noise_in_y_covariance" => true,
"multiplicative_prior_inflation" => 0.0,
"observation_noise_stddev" => 2.0,
"observation_noise_type" => "diagonal",
),
);Seed for reproducibility.
Random.seed!(1983745);Make operators.
transitioner = Lorenz63Model(; params)
observer = NoisyObserver(get_state_keys(transitioner); params);Set seed for ground-truth simulation.
Random.seed!(0xfee55e45)
xor_seed!(observer, UInt64(0x243ecae5));Define observation times
observation_times = let
step = params["observation"]["timestep_size"]
length = params["observation"]["num_timesteps"]
range(; start=0, length, step)
end0.0:0.1:29.9Generate synthetic ground-truth observations.
if !(@isdefined ground_truth) || isnothing(ground_truth)
ground_truth = @time let
state0 = Dict{Symbol,Any}(:state => randn(3))
# Set seed for ground-truth simulation.
Random.seed!(0xfee55e45)
xor_seed!(observer, UInt64(0x243ecae5))
# Generate states and observations.
t0 = 0.0
states = Vector{Dict{Symbol,Any}}(undef, length(observation_times))
observations = Vector{Dict{Symbol,Any}}(undef, length(observation_times))
let state = state0
for (i, t) in enumerate(observation_times)
state = transitioner(state, t0, t)
obs = observer(state)
states[i] = state
observations[i] = split_clean_noisy(observer, obs)[2]
t0 = t
end
end
(; states, observations)
end
println(" ^ timing for making ground truth observations")
ground_truth_states_vec = get_ensemble_matrix([:state], ground_truth.states)
ground_truth_obs_vec = get_ensemble_matrix([:state], ground_truth.observations)
end; 1.155779 seconds (1.64 M allocations: 82.655 MiB, 3.48% gc time, 99.66% compilation time)
^ timing for making ground truth observations
Plot the ground-truth.
if !(@isdefined plot_ground_truth)
plot_ground_truth = true
end
if plot_ground_truth
figs = let
ts = observation_times
data = reduce(hcat, state[:state] for state in ground_truth.states)
plot_kwargs = (; color="#7fc97f", marker='.', markersize=15, markercolor=:black)
plot_state_over_time(observation_times, data; plot_kwargs...)
end
figs[1]
endEnsembles
Make initial ensemble.
function generate_ensemble(params::Dict)
seed = params["ensemble"]["seed"]
ensemble_size = params["ensemble"]["size"]
prior_type = params["ensemble"]["prior"]
members = Vector{Dict{Symbol,Any}}(undef, ensemble_size)
if prior_type == "gaussian"
rng = Random.MersenneTwister(seed)
prior_mean, prior_std = params["ensemble"]["prior_params"]
for i in 1:ensemble_size
data = prior_mean .+ prior_std .* randn(rng, 3)
state = Dict{Symbol,Any}(:state => data)
members[i] = state
end
else
throw(ArgumentError("Invalid prior type: $prior_type"))
end
ensemble = Ensemble(members)
return ensemble
end
if !(@isdefined ensemble_initial0) || isnothing(ensemble_initial0)
ensemble_initial0 = generate_ensemble(params)
end
ensemble_initial0 = generate_ensemble(params);
ensemble_initial = Ensemble(ensemble_initial0, ensemble_initial0.members, [:state]);
t_index_end = params["spinup"]["num_timesteps"]
observation_times = observation_times[1:t_index_end]
ground_truth_observations = ground_truth.observations[1:t_index_end]
transition_noise = params["spinup"]["transition_noise_scale"];Data assimilation
Choose filtering algorithm.
filter = get_enkf_filter(params["spinup"])EnsembleKalmanFilters.EnKF([4.0 0.0 0.0; 0.0 4.0 0.0; 0.0 0.0 4.0], true, 0.0)Run sequential algorithm.
if !(@isdefined ensembles) || isnothing(ensembles)
ensembles =
let t_index_end = params["spinup"]["num_timesteps"],
observation_times = observation_times[1:t_index_end],
ground_truth_observations = ground_truth.observations[1:t_index_end],
ensemble = ensemble_initial0,
t0 = 0.0,
transition_noise = params["spinup"]["transition_noise_scale"]
Random.seed!(0x3289745)
xor_seed!(observer, UInt64(0x375ef928))
logs = []
ensembles = []
@time begin
push!(ensembles, (; ensemble, t=t0))
for (t, y_obs) in zip(observation_times, ground_truth_observations)
# Advance ensemble to time t.
ensemble = transitioner(ensemble, t0, t; inplace=false)
# Keep ensemble separated.
if transition_noise != 0
for em in ensemble.members
em[:state] .+= transition_noise .* Random.randn(3)
end
end
# Take observation at time t.
ensemble_obs = observer(ensemble)
ensemble_obs_clean, ensemble_obs_noisy = split_clean_noisy(
observer, ensemble_obs
)
# Record.
push!(
ensembles, (; ensemble, ensemble_obs_clean, ensemble_obs_noisy, t)
)
# Assimilate observation
log_data = Dict{Symbol,Any}()
(posterior, timing...) = @timed assimilate_data(
filter,
ensemble,
ensemble_obs_clean,
ensemble_obs_noisy,
y_obs,
log_data,
)
log_data[:timing] = timing
ensemble = posterior
# Record.
push!(ensembles, (; ensemble, t))
push!(logs, log_data)
# Let time pass.
t0 = t
end
end
println(" ^ timing for making initial ensemble")
ensembles
end
end; 9.128559 seconds (13.50 M allocations: 1.562 GiB, 2.30% gc time, 50.16% compilation time)
^ timing for making initial ensemble
Define handy functions.
function get_ground_truth_iterator(ensembles_ts, observation_times)
gt_index = 1
gt_indices = []
post_assim_indices = []
for (i, t) in enumerate(ensembles_ts)
while gt_index <= length(observation_times) && observation_times[gt_index] < t
gt_index += 1
end
if gt_index > length(observation_times)
error(
"Comparing at time $(t) is impossible because final ground-truth observation is at time $(observation_times[end])",
)
end
if observation_times[gt_index] != t
error(
"No observation at time $(t). Closest are $(observation_times[gt_index-1]) and $(observation_times[gt_index])",
)
end
push!(gt_indices, gt_index)
if i == length(ensembles_ts) || t < ensembles_ts[i + 1]
push!(post_assim_indices, i)
end
end
return gt_indices, post_assim_indices
end
function compute_errors(gt_indices, ensembles_means_vec, ground_truth_states_vec)
rmses = Vector{Float64}(undef, length(ensembles_means_vec))
for (i, gt_index) in enumerate(gt_indices)
rmses[i] = rmse(ensembles_means_vec[:, i], ground_truth_states_vec[:, gt_index])
end
return rmses
end
function compute_metrics(ensembles)
means_vec = get_ensemble_matrix(
ensembles[1].ensemble.state_keys, mean(e.ensemble) for e in ensembles
)
vars_vec = get_ensemble_matrix(
ensembles[1].ensemble.state_keys, var(e.ensemble) for e in ensembles
)
ts = [e.t for e in ensembles]
gt_indices, post_assim_indices = get_ground_truth_iterator(ts, observation_times)
rmses = compute_errors(gt_indices, means_vec, ground_truth_states_vec)
spread = sqrt.(mean(vars_vec; dims=1)[1, :])
return (;
ts,
vars_vec,
means_vec,
gt_indices,
post_assim_indices,
rmses,
spread,
post_assim_rmses=(rmses[i] for i in post_assim_indices),
post_assim_spread=(spread[i] for i in post_assim_indices),
)
end;Compute metrics.
metrics_initial = compute_metrics(ensembles)
println("SPINUP")
println(" Average metrics")
println(" RMSE: $(mean(metrics_initial.post_assim_rmses))")
println(" Spread: $(mean(metrics_initial.post_assim_spread))")
println()
println("Observations")
println(" Average metrics")
println(" RMSE: $(mean(rmse.(ground_truth_obs_vec, ground_truth_states_vec)))")
println()SPINUP
Average metrics
RMSE: 0.94082500434391
Spread: 1.049306132209731
Observations
Average metrics
RMSE: 1.6076413581833835
Plot metrics over time
if !(@isdefined plot_initial_metrics)
plot_initial_metrics = true
end
if plot_initial_metrics
figs_state, figs_spread, figs_rmse = let metrics = metrics_initial
cut = Colon()
# Plot variance.
handler = function (fig)
for ax in fig.content
if isa(ax, Axis)
if ax.ylabel[] == L"\text{x}"
ax.ylabel = L"\sigma^2_x"
ax.yscale = log10
elseif ax.ylabel[] == L"\text{y}"
ax.ylabel = L"\sigma^2_y"
ax.yscale = log10
elseif ax.ylabel[] == L"\text{z}"
ax.ylabel = L"\sigma^2_z"
ax.yscale = log10
end
end
end
end
plot_kwargs = (;
handler,
max_dt=50,
make_positive=true,
color="#7fc97f",
marker='.',
markersize=0,
markercolor=:black,
connect=(; linestyle=:dash, color=[1, 2], colormap=:BuGn, markersize=0),
)
figs_state = plot_state_over_time(
metrics.ts[cut], metrics.vars_vec[:, cut]; plot_kwargs...
)
# Plot ensemble spread.
handler = function (fig)
for ax in fig.content
if isa(ax, Axis)
if ax.ylabel[] == L"\text{metric}"
ax.ylabel = L"\text{spread}"
ax.yscale = log10
end
end
end
end
plot_kwargs = (;
handler,
max_dt=50,
color="#041a1c",
marker='.',
markersize=15,
markercolor=:black,
connect=(; linestyle=:dash, color=[1, 2], colormap=:BuGn, markersize=0),
)
figs_spread = plot_error_metric_over_time(
metrics.ts[cut], metrics.spread[cut]; plot_kwargs...
)
# Plot RMSE.
handler = function (fig)
for ax in fig.content
if isa(ax, Axis)
if ax.ylabel[] == L"\text{metric}"
ax.ylabel = L"\text{RMSE}"
ax.yscale = log10
end
end
end
end
plot_kwargs = (;
handler,
max_dt=50,
color="#e41a1c",
marker='.',
markersize=15,
markercolor=:black,
connect=(; linestyle=:dash, color=[1, 2], colormap=:BuGn, markersize=0),
)
figs_rmse = plot_error_metric_over_time(
metrics.ts[cut], metrics.rmses[cut]; plot_kwargs...
)
figs_state, figs_spread, figs_rmse
end
figs_state[1]
endif plot_initial_metrics
figs_spread[1]
endif plot_initial_metrics
figs_rmse[1]
endPlot the ensemble mean.
if !(@isdefined plot_initial_ensemble_mean)
plot_initial_ensemble_mean = true
end
if plot_initial_ensemble_mean
figs = let metrics = metrics_initial
cut = Colon()
ts_gt = observation_times
xs_gt = view(ground_truth_states_vec, 1, :)
ys_gt = view(ground_truth_states_vec, 2, :)
zs_gt = view(ground_truth_states_vec, 3, :)
gt_kwargs = (;
color=("#d95f02", 0.5),
marker='.',
markersize=15,
markercolor=(:yellow, 0.5),
)
handler = function (fig)
for ax in fig.content
if isa(ax, Axis)
t0 = minimum(ax.scene.plots[1].args[1][])
tf = maximum(ax.scene.plots[1].args[1][])
start = searchsortedfirst(ts_gt, t0)
finish = searchsortedfirst(ts_gt, tf)
if ax.ylabel[] == L"\text{x}"
scatterlines!(
ax,
ts_gt[start:finish],
xs_gt[start:finish];
gt_kwargs...,
)
elseif ax.ylabel[] == L"\text{y}"
scatterlines!(
ax,
ts_gt[start:finish],
ys_gt[start:finish];
gt_kwargs...,
)
elseif ax.ylabel[] == L"\text{z}"
scatterlines!(
ax,
ts_gt[start:finish],
zs_gt[start:finish];
gt_kwargs...,
)
end
end
end
end
plot_kwargs = (;
handler,
max_dt=50,
color="#7fc97f",
marker='.',
markersize=0,
markercolor=:black,
connect=(; linestyle=:dash, color=[1, 2], colormap=:BuGn, markersize=0),
)
figs = plot_state_over_time(
metrics.ts[cut], metrics.means_vec[:, cut]; plot_kwargs...
)
end
figs[1]
endAnd so everything is great!
Note that this cleanup only needs to be run in automated contexts. The unregistered packages can cause issues.
try
Pkg.rm("Lorenz63")
Pkg.rm("EnsembleKalmanFilters")
Pkg.rm("NormalizingFlowFilters")
catch e
@warn e
end Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Project.toml`
[72db8b11] - Lorenz63 v0.1.0 `https://github.com/milankl/Lorenz63.jl#15220a7#master`
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Manifest.toml`
[72db8b11] - Lorenz63 v0.1.0 `https://github.com/milankl/Lorenz63.jl#15220a7#master`
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Project.toml`
[489b957c] - EnsembleKalmanFilters v0.0.1 `https://github.com/DataAssimilation/EnsembleKalmanFilters.jl#main`
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Manifest.toml`
[489b957c] - EnsembleKalmanFilters v0.0.1 `https://github.com/DataAssimilation/EnsembleKalmanFilters.jl#main`
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Project.toml`
[bdff3154] - NormalizingFlowFilters v0.0.1 `https://github.com/DataAssimilation/NormalizingFlowFilters.jl#main`
Updating `~/work/Ensembles.jl/Ensembles.jl/examples/lorenz63/Manifest.toml`
[4fba245c] - ArrayInterface v7.18.0
[a9b6321e] - Atomix v1.1.1
[ab4f0b2a] - BFloat16s v0.5.1
[62783981] - BitTwiddlingConvenienceFunctions v0.1.6
[2a0fbf3d] - CPUSummary v0.2.6
[052768ef] - CUDA v5.7.2
[1af6417a] - CUDA_Runtime_Discovery v0.3.5
[aafaddc9] - CatIndices v0.2.2
[082447d4] - ChainRules v1.72.3
[fb6a15b2] - CloseOpenIntervals v0.1.13
[bbf7d656] - CommonSubexpressions v0.3.1
[f70d9fcc] - CommonWorldInvalidations v1.0.0
[ed09eef8] - ComputationalResources v0.3.2
[5218b696] - Configurations v0.17.6
[150eb455] - CoordinateTransformations v0.6.4
[adafc99b] - CpuId v0.3.1
[a8cc5b0e] - Crayons v4.1.1
[dc8bdbbb] - CustomUnitRanges v1.0.2
[a93c6f00] - DataFrames v1.7.0
[8bb1440f] - DelimitedFiles v1.9.1
[163ba53b] - DiffResults v1.1.0
[b552c78f] - DiffRules v1.15.1
[b4f34e82] - Distances v0.10.12
[e2ba6199] - ExprTools v0.1.10
[55351af7] - ExproniconLite v0.10.14
[4f61f5a4] - FFTViews v0.3.2
[587475ba] - Flux v0.14.25
[f6369f11] - ForwardDiff v1.0.1
[d9f16b24] - Functors v0.4.12
[0c68f7d7] - GPUArrays v11.2.2
[46192b85] - GPUArraysCore v0.2.0
[61eb1bfa] - GPUCompiler v1.3.2
[096a3bc2] - GPUToolbox v0.2.0
[076d061b] - HashArrayMappedTries v0.2.0
[3e5b6fbb] - HostCPUFeatures v0.1.17
[7869d1d1] - IRTools v0.4.14
[615f187c] - IfElse v0.1.1
[f332f351] - ImageContrastAdjustment v0.3.12
[51556ac3] - ImageDistances v0.2.17
[6a3955dd] - ImageFiltering v0.7.9
[787d08f9] - ImageMorphology v0.4.6
[2996bd0c] - ImageQualityIndexes v0.3.7
[02fcd773] - ImageTransformations v0.10.1
[842dd82b] - InlineStrings v1.4.3
[41ab1584] - InvertedIndices v1.3.1
[b7115f24] - InvertibleNetworks v2.3.0
[63c18a36] - KernelAbstractions v0.9.34
[929cbde3] - LLVM v9.2.0
[8b046642] - LLVMLoopInfo v1.0.0
[10f19ff3] - LayoutPointers v0.1.17
[bdcacae8] - LoopVectorization v0.12.172
[c2834f40] - MLCore v1.0.0
[7e8f7934] - MLDataDevices v1.5.3
[f1d291b0] - MLUtils v0.4.8
[d125e4d3] - ManualMemory v0.1.8
[872c559c] - NNlib v0.9.30
[5da4648a] - NVTX v1.0.0
[bdff3154] - NormalizingFlowFilters v0.0.1 `https://github.com/DataAssimilation/NormalizingFlowFilters.jl#main`
[0b1bfda6] - OneHotArrays v0.2.7
[3bd65402] - Optimisers v0.3.4
[d96e819e] - Parameters v0.12.3
[1d0040c9] - PolyesterWeave v0.2.2
[2dfb63ee] - PooledArrays v1.4.3
[08abe8d2] - PrettyTables v2.4.0
[33c8b6b6] - ProgressLogging v0.1.4
[94ee1d12] - Quaternions v0.7.6
[74087812] - Random123 v1.7.0
[e6cf234a] - RandomNumbers v1.6.0
[c1ae055f] - RealDot v0.1.0
[6038ab10] - Rotations v1.7.1
[94e857df] - SIMDTypes v0.1.0
[476501e8] - SLEEFPirates v0.6.43
[7e506255] - ScopedValues v1.3.0
[91c51154] - SentinelArrays v1.4.8
[605ecd9f] - ShowCases v0.1.0
[dc90abb0] - SparseInverseSubset v0.1.2
[aedffcd0] - Static v1.2.0
[0d7ed370] - StaticArrayInterface v1.8.0
[892a3eda] - StringManipulation v0.4.1
[8290d209] - ThreadingUtilities v0.5.3
[06e1c1a7] - TiledIteration v0.5.0
[a759f4b9] - TimerOutputs v0.5.28
[3a884ed6] - UnPack v1.0.2
[013be700] - UnsafeAtomics v0.3.0
[3d5dd08c] - VectorizationBase v0.21.71
[e88e6eb3] - Zygote v0.6.76
[700de1a5] - ZygoteRules v0.2.7
[02a925ec] - cuDNN v1.4.2
[4ee394cb] - CUDA_Driver_jll v0.12.1+1
[76a88914] - CUDA_Runtime_jll v0.16.1+0
[62b44479] - CUDNN_jll v9.4.0+0
[9c1d0b0a] - JuliaNVTXCallbacks_jll v0.2.1+0
[dad2f222] - LLVMExtra_jll v0.0.35+0
[e98f9f5b] - NVTX_jll v3.1.1+0
[1e29f10c] - demumble_jll v1.3.0+0
This page was generated using Literate.jl.