text:
### A Pluto.jl notebook ###
# v0.17.2

using Markdown
using InteractiveUtils

# ╔═╡ 191b2740-c20f-11eb-1bc3-4554934741e5
using Plots, Swalbe

# ╔═╡ 993b8d98-0f13-4ac5-80d8-3ebd1b64f59b
md"# Droplet coalescence

A fairly simple show case is the dynamics of two coalescing sessile droplets.
The simulation is performed within the quasi two-dimensional (fast prototyping)  system.
Everything, besides the visualization with **Plots.jl**, is contained in the **Swalbe.jl** package.
However for convenience we define two more functions.
The first one contains the simulation, so we can run it with different parameters just by switching input arguments.
The second one is for data analysis.

## Experiment and analysis functions

- The fluid dynamics simulation `run_drop_coal()`
- Computation of the bridge height `brdige_height()`

One minor addition, for convenience we use a `recipe` that works quite similar to *matplotlibs* `markevery` function.

"

# ╔═╡ 645c6e07-c565-4f44-b29a-d9737fde9222
@recipe function f(::Type{Val{:samplemarkers}}, x, y, z; step = 10)
    n = length(y)
    sx, sy = x[1:step:n], y[1:step:n]
    # add an empty series with the correct type for legend markers
    @series begin
        seriestype := :path
        markershape --> :auto
        x := [Inf]
        y := [Inf]
    end
    # add a series for the line
    @series begin
        primary := false # no legend entry
        markershape := :none # ensure no markers
        seriestype := :path
        seriescolor := get(plotattributes, :seriescolor, :auto)
        x := x
        y := y
    end
    # return  a series for the sampled markers
    primary := false
    seriestype := :scatter
    markershape --> :auto
    x := sx
    y := sy
end

# ╔═╡ 301aecbc-a5fc-4cea-8a1e-7ca130377e93
"""
    run_drop_coal()

Simulation for droplet coalesence in quasi two dimensions.
"""
function run_drop_coal(
    sys::Swalbe.SysConst_1D;
    r₁=115,
    r₂=115,
    θ₀=1/9,
    verbos=true,
    dump = 100,
    fluid=zeros(sys.Tmax÷dump, sys.L)
)
    println("Simulating droplet coalecense")
    state = Swalbe.Sys(sys)
    drop_cent = (sys.L/3, 2*sys.L/3)
    state.height .= Swalbe.two_droplets(sys, r₁=r₁, r₂=r₂, θ₁=θ₀, θ₂=θ₀, center=drop_cent)
    Swalbe.equilibrium!(state)
    println("Starting the lattice Boltzmann time loop")
    for t in 1:sys.Tmax
        if t % sys.tdump == 0
            mass = 0.0
            mass = sum(state.height)
            if verbos
                println("Time step $t bridge height is $(round(state.height[Int(sys.L/2)], digits=3))")
            end
        end
        Swalbe.filmpressure!(state, sys)
        Swalbe.h∇p!(state)
        Swalbe.slippage!(state, sys)
        state.F .= -state.h∇p .- state.slip
        Swalbe.equilibrium!(state)
        Swalbe.BGKandStream!(state)
        Swalbe.moments!(state)

        Swalbe.snapshot!(fluid, state.height, t, dumping = dump)
    end

    return fluid

end

# ╔═╡ 518b7204-1301-4a54-8332-ead4f8619cb0
"""
	bridge_height()

Function that tracks the height or thickness at single well defined lattice point.
"""
function bridge_height(data; t1=100, t_dur=size(data)[1], pos=size(data)[2]÷2)
    bridge_h = []
    for i in 1:t_dur
        push!(bridge_h, data[i, pos])
    end
    return bridge_h
end

# ╔═╡ 69f24d80-6181-476c-bd01-a336edf6b8a5
# Need this for plotting purposes
begin
	os = true
	if Sys.iswindows()
		os = false
	elseif Sys.islinux()
		os = true
	end
end

# ╔═╡ b417f463-46e5-421d-8d3b-974532274c3d
md"## Initial condition

The plot below describes the initial condition of our numerical experiment.
Two droplets that are barely touching with an contact angle θ of 20° (or π/9).

Due to surface tension (γ) we expect that these two droplets will coalesce into a single one.
That is because a single droplet does have less surface area than two smaller ones and therefore it is an energetically favorable state."

# ╔═╡ 31fb4367-50e9-46d9-ad41-e0fc309549b4
begin
	# The initial configuration of the numerical experiment
	rad = 500
	h = Swalbe.two_droplets(Swalbe.SysConst_1D(L=1024), r₁=rad, r₂=rad)
	x_ = 1:1024
	p0 = plot(x_ , h, w=3, aspect_ratio=7, label="Initial conf.", xlabel="x [Δx]", ylabel="h(x)")
	ylims!(0,40)
end

# ╔═╡ 684e5cd8-aeae-411b-81e1-342df09d1bd8
md"## Experiment

We start the numerical experiment or simulation by simply calling the function that we defined before: `run_drop_coal()`.

The data will be saved to an array the contains n-time steps and the whole height field.
Something that is only possible with numerical simulations is to change parameters at will.
We do this by changing the surface tension γ of our test liquid.
Of course changing the contact angle θ or the kinematic viscosity ν would as well be possible."

# ╔═╡ 5f2202d7-f217-4fec-8669-b34bfcbf5008
begin
	# Sphere radius
	sphere_rad = 500
	# Different surface tension values
	γs = [0.00008, 0.0003, 0.0006, 0.0008]
	# Array that contains the simulation data
	data_merge = zeros(20000, 1024, length(γs))
	# Loop different surface tension values
	for γ in enumerate(γs)
		# System parameter, δ=50 can still considered small to medium slippage
		sys = Swalbe.SysConst_1D(L=1024, Tmax=2000000, δ=50.0, γ=γ[2])
		# The experiment
		data_merge[:,:,γ[1]] = run_drop_coal(sys, r₁=sphere_rad, r₂=sphere_rad)
	end
end

# ╔═╡ 03a2f622-202a-4847-bf20-2a072eb9f592
md"### Data

Below is an example of the data that was generated during the simulation.
We saved all `Tmax` time steps of all `L` lattice points in `data_merge[:,:,γ]` where we can specifying the desired `γ` value in the last column of the array.
Displayed is the data of the run with γ=0.00008, or simply the first run.

Here a short word of caution.
[The lattice Boltzmann method](https://link.springer.com/book/10.1007/978-3-319-44649-3) is not perfect, it is easy to programm and scales well.
One of the downsides however is the fact that this method is derived from the [Boltzmann equation](https://en.wikipedia.org/wiki/Boltzmann_equation).
Therefore trying to make sense of these surface tension values is not too helpful.
Interpreting results in terms of **SI** units is often not the best way.
Personally I like to work with dimensionless numbers and relevant length and time scales.

Instead of adding **SI** units to the plots we normalize with characteristic quantities of the experiment."

# ╔═╡ 056f47ed-2be2-4937-aa0c-6a9e353cfa92
# Data containing the γ=0.00008 simulation
data_merge[:,:,1]

# ╔═╡ b35ee645-1220-4132-a9da-3097ade07dcd
md"Since a plot says more than several columns of the dataset here a plot of three different time steps.
The initial kink between the two droplets is quickly smoothed out and the bridge height h₀ is growing."

# ╔═╡ f5112422-d08a-4566-9ba7-ee3eed12cc9c
begin
	# Time evolution for a single surface tension
	lf = 8
	p01 = plot(p0)
	plot!(x_ ,data_merge[1000,:,1], w=3, alpha=0.6, label="t=1000Δt")
	plot!(x_ ,data_merge[5000,:,1], w=3, alpha=0.6, label="t=5000Δt")
	plot!(x_ ,data_merge[15000,:,1], w=3, alpha=0.6, label="t=15000Δt",
		  xlims=(150,1024),
		  # legend=:bottomright,
		  legendfontsize = lf,			# legend font size
          tickfont = (14),				# tick font and size
          guidefont = (15),				# label font and size
		  grid=:none)
end

# ╔═╡ 5cbbb115-47d8-4cb6-9d68-77c391425e86
md"### Under the bridge

The next point on the list is to measure the evolution of the bridge height h₀.
We expect that the height will grow according to some power law, in fact $h_0(t) = t^{\alpha}$ with $\alpha = 2/3$.

Luckily this is a fairly easy task, since by definition the touching point of the droplets is at the center of the substrate."

# ╔═╡ ddcf4747-a3d5-4eaf-8614-c620f37724fc
begin
	bridges = zeros(20000, length(γs))
	for i in 1:length(γs)
		bridges[:, i] = bridge_height(data_merge[:,:,i])
	end
end

# ╔═╡ f7db6fb5-eaa0-4954-8730-89647cc73629
md"Now there are two data sets
- Film thicknesses: $h(t,x)$
- bridge heights: $h_0(t,γ)$

Especially the bridge heights should likely collapse to a single curve upon rescaling with a characteristic time scale $\tau$ which we define as

$$\tau = \frac{\mu R}{\gamma},$$

where $R$ is the radius of the sphere from which the spherical cap has been cut, $\gamma$ is the surface tension and $\mu$ is the liquids viscosity.
This time scale can be understood as a capillary time scale, see [Zitz et al.](https://journals.aps.org/pre/abstract/10.1103/PhysRevE.100.033313)."

# ╔═╡ b32505e2-5fc8-48d1-8381-8050a8d292b5
"""
	τ(γ, R, μ)

Computes a characteristic time scale.
"""
function τ(γ; R=500, μ=1/6)
	time_c = 0.0
	time_c = R*μ/γ
	return time_c
end

# ╔═╡ e4cc9ddc-cf63-47ba-8b13-ddf9265c8338
md"## Results
In the following we show the results collected.
First being the evolution of the bridge height h₀(t).
This information may not be too insightful, because the data is given in terms of lattice Boltzmann units (l.b.u.).
To overcome this issue we have two natural scales.
On the one hand a time scale defined by **τ** and on the other hand a length scale given by the spheres radii **R**.

- τ ... time
- R ... length

In the plot below we see that *pure* data spans four different curves, based on their respective surface tensions.
"

# ╔═╡ 842006de-fb79-41be-8af1-459cb7bdde2e
begin
	labels_gamma = ["γ=0.00008" "γ=0.0003" "γ=0.0006" "γ=0.0008"]
	γ_h = [0.00008, 0.0003, 0.0006, 0.0008]
	time_lbm = 100:100:2000000
	p1 = plot(time_lbm,
		      bridges,
		      xlabel="t [Δt]",
		      ylabel="h₀",
		      label=labels_gamma,
			  xticks=([0:1000000:2000000;], ["0", "1×10⁶", "2×10⁶"]),
		      xlims=(0,2100000),
			  ylims=(0, 40),
		      w = 3, 							# line width
		      st = :samplemarkers, 				# some recipy stuff
		      step = 1800, 						# density of markers
		      marker = (8, :auto, 0.6),			# marker size
		      legend=:bottomright,
			  legendfontsize = lf,			# legend font size
              tickfont = (14),	# tick font and size
              guidefont = (15),	# label font and size
			  grid=:none
	         )
end

# ╔═╡ 96b773b7-e158-47c4-b25c-75e4fef655b8
md"In the box below the lattice Boltzmann time steps are normalized and nondimensionalized with τ."

# ╔═╡ 0db816bf-9dc2-43f3-a315-887c9ca68ff4
begin
	# Normalize the simulation time step with the viscous time
	time_norm = zeros(length(time_lbm), length(γs))
	for i in enumerate(γs)
		time_norm[:, i[1]] .= time_lbm ./ τ(i[2])
	end
end

# ╔═╡ 6451c7dd-344f-41d1-a869-7a733ad5b2b1
md"With the normalized time we can plot the data of the bridge height h₀ again.
Interestingly now the data *collapses* to a single master curve, independent of our parameters.

Another interesting obeservation is that the curve has a straight part in the **loglog** scale, which means that the data follows a powerlaw.
Luckily for us the exponent of the powerlaw α is exactly the one that we want to observe for a partially wetting substrate with small contact angle (θ < π/2).

$$\alpha = 2/3.$$

The black dashed line in the plot below.
"

# ╔═╡ 23fd2d46-22c8-4dae-8437-d3fd4628f6c3
begin
	p2 = plot(time_norm,
	      bridges ./ sphere_rad,
	      xlabel="t/τ",
	      ylabel="h₀/R₀",
	      label=labels_gamma,
	      w = 3, 							# line width
		  alpha=0.6,
	      ylims=(2e-4, 2e-1),
		  xticks=([0.00001,0.001, 0.1, 10], ["10⁻⁵", "10⁻³", "10⁻¹", "10"]),
		  st = :samplemarkers, 				# some recipy stuff
		  step = 1000, 						# density of markers
		  marker = (8, :auto, 0.6),			# marker size
		  legendfontsize = lf,			# legend font size
          tickfont = (14),	# tick font and size
          guidefont = (15),	# label font and size
	      axis=:log,
		  grid=:none,
	      legend=:topleft)
	exponent = 2/3
	there = collect(1e-5:1e-5:10)
	plot!(there, 0.023 .* there.^(exponent), c=:black, w=4, l=:dash, label="t^(2/3)")
end

# ╔═╡ b1de636a-81c7-410c-8767-153a1b9a3079
md"## Conclusion

Two sessile droplets placed next to each other on a partially wetting substrate are coalescing into a single one.
The dynamics of this process, the growth of the bridge height h₀, can be explained with a powerlaw.
Interestingly the data of the different surface tensions γ can be collapsed to a single master curve upon rescaling."

# ╔═╡ 88f037e3-1ec3-4360-84d3-a6c496731c6c
begin
	# Collecting results in a single plot
	l = @layout[a{0.6h}; b c]
	all_p = plot(p01, p1, p2, layout = l)
end

# ╔═╡ 85104c76-b2fc-4813-8205-34de12792e0c
#savefig(all_p, "..\\paper\\drop_coal.png")

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Swalbe = "1073fb09-a5e2-4e80-8bde-f3562efda53f"

[compat]
Plots = "~1.22.6"
Swalbe = "~1.0.0"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

[[AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.0.1"

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[BFloat16s]]
deps = ["LinearAlgebra", "Printf", "Random", "Test"]
git-tree-sha1 = "a598ecb0d717092b5539dbbe890c98bac842b072"
uuid = "ab4f0b2a-ad5b-11e8-123f-65d77653426b"
version = "0.2.0"

[[BSON]]
git-tree-sha1 = "ebcd6e22d69f21249b7b8668351ebf42d6dc87a1"
uuid = "fbb218c0-5317-5bc6-957e-2ee96dd4b1f0"
version = "0.3.4"

[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"]
git-tree-sha1 = "61adeb0823084487000600ef8b1c00cc2474cd47"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "1.2.0"

[[BinaryProvider]]
deps = ["Libdl", "Logging", "SHA"]
git-tree-sha1 = "ecdec412a9abc8db54c0efc5548c64dfce072058"
uuid = "b99e7846-7c00-51b0-8f62-c81ae34c0232"
version = "0.5.10"

[[Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"

[[CEnum]]
git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.1"

[[CRlibm]]
deps = ["Libdl"]
git-tree-sha1 = "9d1c22cff9c04207f336b8e64840d0bd40d86e0e"
uuid = "96374032-68de-5a5b-8d9e-752f78720389"
version = "0.8.0"

[[CUDA]]
deps = ["AbstractFFTs", "Adapt", "BFloat16s", "CEnum", "CompilerSupportLibraries_jll", "ExprTools", "GPUArrays", "GPUCompiler", "LLVM", "LazyArtifacts", "Libdl", "LinearAlgebra", "Logging", "Printf", "Random", "Random123", "RandomNumbers", "Reexport", "Requires", "SparseArrays", "SpecialFunctions", "TimerOutputs"]
git-tree-sha1 = "2c8329f16addffd09e6ca84c556e2185a4933c64"
uuid = "052768ef-5323-5732-b1bb-66c8b64840ba"
version = "3.5.0"

[[Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "f2202b55d816427cd385a9a4f3ffb226bee80f99"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+0"

[[Calculus]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad"
uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9"
version = "0.5.1"

[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "d9e40e3e370ee56c5b57e0db651d8f92bce98fea"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.10.1"

[[CodeTracking]]
deps = ["InteractiveUtils", "UUIDs"]
git-tree-sha1 = "9aa8a5ebb6b5bf469a7e0e2b5202cf6f8c291104"
uuid = "da1fd8a2-8d9e-5ec2-8556-3022fb5608a2"
version = "1.0.6"

[[CodecBzip2]]
deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"]
git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7"
uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd"
version = "0.7.2"

[[CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.0"

[[ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "a851fec56cb73cfdf43762999ec72eff5b86882a"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.15.0"

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[CommonSubexpressions]]
deps = ["MacroTools", "Test"]
git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7"
uuid = "bbf7d656-a473-5ed7-a52c-81e309532950"
version = "0.3.0"

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "31d0151f5716b655421d9d75b7fa74cc4e744df2"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.39.0"

[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[Contour]]
deps = ["StaticArrays"]
git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.5.7"

[[Crayons]]
git-tree-sha1 = "3f71217b538d7aaee0b69ab47d9b7724ca8afa0d"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.0.4"

[[DataAPI]]
git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.9.0"

[[DataFrames]]
deps = ["Compat", "DataAPI", "Future", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrettyTables", "Printf", "REPL", "Reexport", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"]
git-tree-sha1 = "d785f42445b63fc86caa08bb9a9351008be9b765"
uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
version = "1.2.2"

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.10"

[[DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[DiffResults]]
deps = ["StaticArrays"]
git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805"
uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5"
version = "1.0.3"

[[DiffRules]]
deps = ["NaNMath", "Random", "SpecialFunctions"]
git-tree-sha1 = "7220bc21c33e990c14f4a9a319b1d242ebc5b269"
uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
version = "1.3.1"

[[Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.5"

[[Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.2.3+0"

[[ErrorfreeArithmetic]]
git-tree-sha1 = "d6863c556f1142a061532e79f611aa46be201686"
uuid = "90fa49ef-747e-5e6f-a989-263ba693cf1a"
version = "0.5.2"

[[Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

[[ExprTools]]
git-tree-sha1 = "b7e3d17636b348f005f11040025ae8c6f645fe92"
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
version = "0.1.6"

[[FFMPEG]]
deps = ["FFMPEG_jll"]
git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
version = "0.4.1"

[[FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.4.0+0"

[[FastRounding]]
deps = ["ErrorfreeArithmetic", "Test"]
git-tree-sha1 = "224175e213fd4fe112db3eea05d66b308dc2bf6b"
uuid = "fa42c844-2597-5d31-933b-ebd51ab2693f"
version = "0.2.0"

[[FileIO]]
deps = ["Pkg", "Requires", "UUIDs"]
git-tree-sha1 = "3c041d2ac0a52a12a27af2782b34900d9c3ee68c"
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
version = "1.11.1"

[[FileWatching]]
uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee"

[[FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[Fontconfig_jll]]
deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03"
uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
version = "2.13.93+0"

[[Formatting]]
deps = ["Printf"]
git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
version = "0.4.2"

[[ForwardDiff]]
deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"]
git-tree-sha1 = "63777916efbcb0ab6173d09a658fb7f2783de485"
uuid = "f6369f11-7733-5829-9624-2563aa707210"
version = "0.10.21"

[[FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.4+0"

[[FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
uuid = "559328eb-81f9-559d-9380-de523a88c83c"
version = "1.0.10+0"

[[Future]]
deps = ["Random"]
uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820"

[[GLFW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"]
git-tree-sha1 = "0c603255764a1fa0b61752d2bec14cfbd18f7fe8"
uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
version = "3.3.5+1"

[[GLPK]]
deps = ["BinaryProvider", "GLPK_jll", "Libdl", "MathOptInterface", "SparseArrays"]
git-tree-sha1 = "86573ecb852e303b209212046af44871f1c0e49c"
uuid = "60bf3e95-4087-53dc-ae20-288a0d20c6a6"
version = "0.13.0"

[[GLPKMathProgInterface]]
deps = ["GLPK", "LinearAlgebra", "MathProgBase", "SparseArrays"]
git-tree-sha1 = "dcca815a687d8f398c8fc701c3796a36ef6b73a5"
uuid = "3c7084bd-78ad-589a-b5bb-dbd673274bea"
version = "0.5.0"

[[GLPK_jll]]
deps = ["GMP_jll", "Libdl", "Pkg"]
git-tree-sha1 = "ccc855de74292e478d4278e3a6fdd8212f75e81e"
uuid = "e8aa6df9-e6ca-548a-97ff-1f85fc5b8b98"
version = "4.64.0+0"

[[GMP_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "781609d7-10c4-51f6-84f2-b8444358ff6d"

[[GPUArrays]]
deps = ["Adapt", "LinearAlgebra", "Printf", "Random", "Serialization", "Statistics"]
git-tree-sha1 = "7772508f17f1d482fe0df72cabc5b55bec06bbe0"
uuid = "0c68f7d7-f131-5f86-a1c3-88cf8149b2d7"
version = "8.1.2"

[[GPUCompiler]]
deps = ["ExprTools", "InteractiveUtils", "LLVM", "Libdl", "Logging", "TimerOutputs", "UUIDs"]
git-tree-sha1 = "ba475ea91facd7bde9f0f113f60e975882b4f5ca"
uuid = "61eb1bfa-7361-4325-ad38-22787b887f55"
version = "0.13.6"

[[GR]]
deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"]
git-tree-sha1 = "d189c6d2004f63fd3c91748c458b09f26de0efaa"
uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
version = "0.61.0"

[[GR_jll]]
deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "cafe0823979a5c9bff86224b3b8de29ea5a44b2e"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.61.0+0"

[[GeometryBasics]]
deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c"
uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
version = "0.4.1"

[[Gettext_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
version = "0.21.0+0"

[[Glib_jll]]
deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "7bf67e9a481712b3dbe9cb3dac852dc4b1162e02"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.3+0"

[[Graphite2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
version = "1.3.14+0"

[[Grisu]]
git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
version = "1.0.2"

[[HTTP]]
deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "14eece7a3308b4d8be910e265c724a6ba51a9798"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.16"

[[HarfBuzz_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
git-tree-sha1 = "8a954fed8ac097d5be04921d595f741115c1b2ad"
uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
version = "2.8.1+0"

[[IniFile]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[IntervalArithmetic]]
deps = ["CRlibm", "FastRounding", "LinearAlgebra", "Markdown", "Random", "RecipesBase", "RoundingEmulator", "SetRounding", "StaticArrays"]
git-tree-sha1 = "5f6387acf62a633bfe21a28999eef5c6a39b638a"
uuid = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"
version = "0.20.0"

[[InverseFunctions]]
deps = ["Test"]
git-tree-sha1 = "f0c6489b12d28fb4c2103073ec7452f3423bd308"
uuid = "3587e190-3f89-42d0-90ee-14403ec27112"
version = "0.1.1"

[[InvertedIndices]]
git-tree-sha1 = "bee5f1ef5bf65df56bdd2e40447590b272a5471f"
uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f"
version = "1.1.0"

[[IrrationalConstants]]
git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.1"

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

[[IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"

[[JLD2]]
deps = ["DataStructures", "FileIO", "MacroTools", "Mmap", "Pkg", "Printf", "Reexport", "TranscodingStreams", "UUIDs"]
git-tree-sha1 = "46b7834ec8165c541b0b5d1c8ba63ec940723ffb"
uuid = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
version = "0.4.15"

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

[[JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.2"

[[JSONSchema]]
deps = ["HTTP", "JSON", "URIs"]
git-tree-sha1 = "2f49f7f86762a0fbbeef84912265a1ae61c4ef80"
uuid = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
version = "0.3.4"

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

[[JuMP]]
deps = ["Calculus", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MathOptInterface", "MutableArithmetics", "NaNMath", "Printf", "Random", "SparseArrays", "SpecialFunctions", "Statistics"]
git-tree-sha1 = "4358b7cbf2db36596bdbbe3becc6b9d87e4eb8f5"
uuid = "4076af6c-e467-56ae-b986-b466b2749572"
version = "0.21.10"

[[JuliaInterpreter]]
deps = ["CodeTracking", "InteractiveUtils", "Random", "UUIDs"]
git-tree-sha1 = "e273807f38074f033d94207a201e6e827d8417db"
uuid = "aa1ae85d-cabe-5617-a682-6adf51b2e16a"
version = "0.8.21"

[[LAME_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
version = "3.100.1+0"

[[LLVM]]
deps = ["CEnum", "LLVMExtra_jll", "Libdl", "Printf", "Unicode"]
git-tree-sha1 = "46092047ca4edc10720ecab437c42283cd7c44f3"
uuid = "929cbde3-209d-540e-8aea-75f648917ca0"
version = "4.6.0"

[[LLVMExtra_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6a2af408fe809c4f1a54d2b3f188fdd3698549d6"
uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab"
version = "0.0.11+0"

[[LZO_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
version = "2.10.1+0"

[[LaTeXStrings]]
git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.2.1"

[[Latexify]]
deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"]
git-tree-sha1 = "669315d963863322302137c4591ffce3cb5b8e68"
uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
version = "0.15.8"

[[LazyArtifacts]]
deps = ["Artifacts", "Pkg"]
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"

[[LazySets]]
deps = ["Distributed", "ExprTools", "GLPK", "GLPKMathProgInterface", "InteractiveUtils", "IntervalArithmetic", "JuMP", "LinearAlgebra", "MathProgBase", "Random", "RecipesBase", "Reexport", "Requires", "SharedArrays", "SparseArrays"]
git-tree-sha1 = "89d025d6f264bda82ccfa5ef634dbf2637c85eba"
uuid = "b4f0291d-fe17-52bc-9479-3d1a343d9043"
version = "1.53.2"

[[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[Libffi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+1"

[[Libgcrypt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
version = "1.8.7+0"

[[Libglvnd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"]
git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf"
uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29"
version = "1.3.0+3"

[[Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.42.0+0"

[[Libiconv_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778"
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
version = "1.16.1+1"

[[Libmount_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
version = "2.35.0+0"

[[Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

[[Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
version = "2.36.0+0"

[[LinearAlgebra]]
deps = ["Libdl"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[LogExpFunctions]]
deps = ["ChainRulesCore", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "6193c3815f13ba1b78a51ce391db8be016ae9214"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.4"

[[Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[LoweredCodeUtils]]
deps = ["JuliaInterpreter"]
git-tree-sha1 = "491a883c4fef1103077a7f648961adbf9c8dd933"
uuid = "6f1432cf-f94c-5a45-995e-cdbf5db27b0b"
version = "2.1.2"

[[MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "5a5bc6bf062f0f95e62d0fe0a2d99699fed82dd9"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.8"

[[Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[MathOptInterface]]
deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "JSON", "JSONSchema", "LinearAlgebra", "MutableArithmetics", "OrderedCollections", "SparseArrays", "Test", "Unicode"]
git-tree-sha1 = "575644e3c05b258250bb599e57cf73bbf1062901"
uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
version = "0.9.22"

[[MathProgBase]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "9abbe463a1e9fc507f12a69e7f29346c2cdc472c"
uuid = "fdba3010-5040-5b88-9595-932c9decdf73"
version = "0.7.8"

[[MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.0.3"

[[MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[Measures]]
git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f"
uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
version = "0.3.1"

[[Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.2"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[MutableArithmetics]]
deps = ["LinearAlgebra", "SparseArrays", "Test"]
git-tree-sha1 = "8d9496b2339095901106961f44718920732616bb"
uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
version = "0.2.22"

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

[[NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[Ogg_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f"
uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
version = "1.3.5+0"

[[OpenLibm_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "05823500-19ac-5b8b-9628-191a04bc5112"

[[OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.10+0"

[[OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[Opus_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
uuid = "91d4177d-7536-5919-b921-800302f37372"
version = "1.3.2+0"

[[OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[PCRE_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488"
uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc"
version = "8.44.0+0"

[[Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.3"

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "98f59ff3639b3d9485a03a72f3ab35bab9465720"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.0.6"

[[Pixman_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29"
uuid = "30392449-352a-5448-841d-b1acce4e97dc"
version = "0.40.1+0"

[[Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[PlotThemes]]
deps = ["PlotUtils", "Requires", "Statistics"]
git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d"
uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
version = "2.0.1"

[[PlotUtils]]
deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"]
git-tree-sha1 = "b084324b4af5a438cd63619fd006614b3b20b87b"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.0.15"

[[Plots]]
deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs"]
git-tree-sha1 = "ba43b248a1f04a9667ca4a9f782321d9211aa68e"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.22.6"

[[PooledArrays]]
deps = ["DataAPI", "Future"]
git-tree-sha1 = "a193d6ad9c45ada72c14b731a318bedd3c2f00cf"
uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720"
version = "1.3.0"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

[[PrettyTables]]
deps = ["Crayons", "Formatting", "Markdown", "Reexport", "Tables"]
git-tree-sha1 = "d940010be611ee9d67064fe559edbb305f8cc0eb"
uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
version = "1.2.3"

[[Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[Profile]]
deps = ["Printf"]
uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"

[[Qt5Base_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"]
git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8"
uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1"
version = "5.15.3+0"

[[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[Random]]
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[Random123]]
deps = ["Libdl", "Random", "RandomNumbers"]
git-tree-sha1 = "0e8b146557ad1c6deb1367655e052276690e71a3"
uuid = "74087812-796a-5b5d-8853-05524746bad3"
version = "1.4.2"

[[RandomNumbers]]
deps = ["Random", "Requires"]
git-tree-sha1 = "043da614cc7e95c703498a491e2c21f58a2b8111"
uuid = "e6cf234a-135c-5ec9-84dd-332b85af5143"
version = "1.5.3"

[[RecipesBase]]
git-tree-sha1 = "44a75aa7a527910ee3d1751d1f0e4148698add9e"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.1.2"

[[RecipesPipeline]]
deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"]
git-tree-sha1 = "7ad0dfa8d03b7bcf8c597f59f5292801730c55b8"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.4.1"

[[Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[Revise]]
deps = ["CodeTracking", "Distributed", "FileWatching", "JuliaInterpreter", "LibGit2", "LoweredCodeUtils", "OrderedCollections", "Pkg", "REPL", "Requires", "UUIDs", "Unicode"]
git-tree-sha1 = "41deb3df28ecf75307b6e492a738821b031f8425"
uuid = "295af30f-e4ad-537b-8983-00126c2a3abe"
version = "3.1.20"

[[RoundingEmulator]]
git-tree-sha1 = "40b9edad2e5287e05bd413a38f61a8ff55b9557b"
uuid = "5eaf0fd0-dfba-4ccb-bf02-d820a40db705"
version = "0.2.1"

[[SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[Scratch]]
deps = ["Dates"]
git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.1.0"

[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[SetRounding]]
git-tree-sha1 = "d7a25e439d07a17b7cdf97eecee504c50fedf5f6"
uuid = "3cc68bcd-71a2-5612-b932-767ffbe40ab0"
version = "0.2.1"

[[SharedArrays]]
deps = ["Distributed", "Mmap", "Random", "Serialization"]
uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"

[[Showoff]]
deps = ["Dates", "Grisu"]
git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
version = "1.0.3"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.0.1"

[[SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[SpecialFunctions]]
deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
git-tree-sha1 = "2d57e14cd614083f132b6224874296287bfa3979"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.8.0"

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3c76dde64d03699e074ac02eb2e8ba8254d428da"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.13"

[[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

[[StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "eb35dcc66558b2dda84079b9a1be17557d32091a"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.12"

[[StructArrays]]
deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"]
git-tree-sha1 = "2ce41e0d042c60ecd131e9fb7154a3bfadbf50d3"
uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
version = "0.6.3"

[[Swalbe]]
deps = ["BSON", "CUDA", "DataFrames", "FileIO", "JLD2", "LazySets", "Parameters", "Random", "Revise", "Statistics"]
git-tree-sha1 = "b7cc26d63f598239153e748091d524f55b5ab574"
uuid = "1073fb09-a5e2-4e80-8bde-f3562efda53f"
version = "1.0.0"

[[TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"

[[Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"]
git-tree-sha1 = "fed34d0e71b91734bf0a7e10eb1bb05296ddbcd0"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.6.0"

[[Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[TimerOutputs]]
deps = ["ExprTools", "Printf"]
git-tree-sha1 = "7cb456f358e8f9d102a8b25e8dfedf58fa5689bc"
uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
version = "0.5.13"

[[TranscodingStreams]]
deps = ["Random", "Test"]
git-tree-sha1 = "216b95ea110b5972db65aa90f88d8d89dcb8851c"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.9.6"

[[URIs]]
git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.3.0"

[[UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

[[Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[Wayland_jll]]
deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23"
uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89"
version = "1.19.0+0"

[[Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"]
git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.18.0+4"

[[XML2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.12+0"

[[XSLT_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
version = "1.1.34+0"

[[Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527"
uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
version = "1.6.9+4"

[[Xorg_libXau_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e"
uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
version = "1.0.9+4"

[[Xorg_libXcursor_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd"
uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724"
version = "1.2.0+4"

[[Xorg_libXdmcp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4"
uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
version = "1.1.3+4"

[[Xorg_libXext_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
version = "1.3.4+4"

[[Xorg_libXfixes_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4"
uuid = "d091e8ba-531a-589c-9de9-94069b037ed8"
version = "5.0.3+4"

[[Xorg_libXi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"]
git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246"
uuid = "a51aa0fd-4e3c-5386-b890-e753decda492"
version = "1.7.10+4"

[[Xorg_libXinerama_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"]
git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123"
uuid = "d1454406-59df-5ea1-beac-c340f2130bc3"
version = "1.1.4+4"

[[Xorg_libXrandr_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631"
uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484"
version = "1.5.2+4"

[[Xorg_libXrender_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
version = "0.9.10+4"

[[Xorg_libpthread_stubs_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb"
uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
version = "0.1.0+3"

[[Xorg_libxcb_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6"
uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
version = "1.13.0+3"

[[Xorg_libxkbfile_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2"
uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a"
version = "1.1.0+4"

[[Xorg_xcb_util_image_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97"
uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b"
version = "0.4.0+1"

[[Xorg_xcb_util_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"]
git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1"
uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5"
version = "0.4.0+1"

[[Xorg_xcb_util_keysyms_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00"
uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7"
version = "0.4.0+1"

[[Xorg_xcb_util_renderutil_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e"
uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e"
version = "0.3.9+1"

[[Xorg_xcb_util_wm_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67"
uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361"
version = "0.4.1+1"

[[Xorg_xkbcomp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"]
git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b"
uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4"
version = "1.4.2+4"

[[Xorg_xkeyboard_config_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"]
git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d"
uuid = "33bec58e-1273-512f-9401-5d533626f822"
version = "2.27.0+4"

[[Xorg_xtrans_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845"
uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
version = "1.4.0+3"

[[Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.15.1+0"

[[libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "2.0.2+0"

[[libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[libvorbis_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+0"

[[nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

[[x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2021.5.5+0"

[[x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.5.0+0"

[[xkbcommon_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"]
git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6"
uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd"
version = "0.9.1+5"
"""

# ╔═╡ Cell order:
# ╠═191b2740-c20f-11eb-1bc3-4554934741e5
# ╟─993b8d98-0f13-4ac5-80d8-3ebd1b64f59b
# ╟─645c6e07-c565-4f44-b29a-d9737fde9222
# ╠═301aecbc-a5fc-4cea-8a1e-7ca130377e93
# ╠═518b7204-1301-4a54-8332-ead4f8619cb0
# ╟─69f24d80-6181-476c-bd01-a336edf6b8a5
# ╟─b417f463-46e5-421d-8d3b-974532274c3d
# ╠═31fb4367-50e9-46d9-ad41-e0fc309549b4
# ╟─684e5cd8-aeae-411b-81e1-342df09d1bd8
# ╠═5f2202d7-f217-4fec-8669-b34bfcbf5008
# ╟─03a2f622-202a-4847-bf20-2a072eb9f592
# ╠═056f47ed-2be2-4937-aa0c-6a9e353cfa92
# ╟─b35ee645-1220-4132-a9da-3097ade07dcd
# ╠═f5112422-d08a-4566-9ba7-ee3eed12cc9c
# ╟─5cbbb115-47d8-4cb6-9d68-77c391425e86
# ╠═ddcf4747-a3d5-4eaf-8614-c620f37724fc
# ╟─f7db6fb5-eaa0-4954-8730-89647cc73629
# ╠═b32505e2-5fc8-48d1-8381-8050a8d292b5
# ╟─e4cc9ddc-cf63-47ba-8b13-ddf9265c8338
# ╠═842006de-fb79-41be-8af1-459cb7bdde2e
# ╟─96b773b7-e158-47c4-b25c-75e4fef655b8
# ╠═0db816bf-9dc2-43f3-a315-887c9ca68ff4
# ╟─6451c7dd-344f-41d1-a869-7a733ad5b2b1
# ╠═23fd2d46-22c8-4dae-8437-d3fd4628f6c3
# ╟─b1de636a-81c7-410c-8767-153a1b9a3079
# ╠═88f037e3-1ec3-4360-84d3-a6c496731c6c
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
export NormalWeightedMeanPrecision

import StatsFuns: log2π, invsqrt2π

struct NormalWeightedMeanPrecision{T <: Real} <: ContinuousUnivariateDistribution
    xi :: T # Weighted mean: xi = w * μ
    w  :: T
end

NormalWeightedMeanPrecision(xi::Real, w::Real)       = NormalWeightedMeanPrecision(promote(xi, w)...)
NormalWeightedMeanPrecision(xi::Integer, w::Integer) = NormalWeightedMeanPrecision(float(xi), float(w))
NormalWeightedMeanPrecision(xi::Real)                = NormalWeightedMeanPrecision(xi, one(xi))
NormalWeightedMeanPrecision()                        = NormalWeightedMeanPrecision(0.0, 1.0)

Distributions.@distr_support NormalWeightedMeanPrecision -Inf Inf

Distributions.support(dist::NormalWeightedMeanPrecision) = Distributions.RealInterval(minimum(dist), maximum(dist))

weightedmean(dist::NormalWeightedMeanPrecision) = dist.xi

function mean_cov(dist::NormalWeightedMeanPrecision)
    v = cov(dist)
    μ = v * weightedmean(dist)
    return (μ, v)
end

Distributions.mean(dist::NormalWeightedMeanPrecision)    = var(dist) * weightedmean(dist)
Distributions.median(dist::NormalWeightedMeanPrecision)  = mean(dist)
Distributions.mode(dist::NormalWeightedMeanPrecision)    = mean(dist)
Distributions.var(dist::NormalWeightedMeanPrecision)     = inv(dist.w)
Distributions.std(dist::NormalWeightedMeanPrecision)     = sqrt(var(dist))
Distributions.cov(dist::NormalWeightedMeanPrecision)     = var(dist)
Distributions.invcov(dist::NormalWeightedMeanPrecision)  = dist.w
Distributions.entropy(dist::NormalWeightedMeanPrecision) = (1 + log2π - log(precision(dist))) / 2

Distributions.pdf(dist::NormalWeightedMeanPrecision, x::Real)    = (invsqrt2π * exp(-abs2(x - mean(dist)) * precision(dist) / 2)) * sqrt(precision(dist))
Distributions.logpdf(dist::NormalWeightedMeanPrecision, x::Real) = -(log2π - log(precision(dist)) + abs2(x - mean(dist)) * precision(dist)) / 2

Base.precision(dist::NormalWeightedMeanPrecision)     = invcov(dist)
Base.eltype(::NormalWeightedMeanPrecision{T}) where T = T

Base.convert(::Type{ NormalWeightedMeanPrecision }, xi::Real, w::Real) = NormalWeightedMeanPrecision(xi, w)
Base.convert(::Type{ NormalWeightedMeanPrecision{T} }, xi::Real, w::Real) where { T <: Real } = NormalWeightedMeanPrecision(convert(T, xi), convert(T, w))

vague(::Type{ <: NormalWeightedMeanPrecision }) = NormalWeightedMeanPrecision(0.0, tiny)

prod_analytical_rule(::Type{ <: NormalWeightedMeanPrecision }, ::Type{ <: NormalWeightedMeanPrecision }) = ProdAnalyticalRuleAvailable()

function Base.prod(::ProdPreserveType, left::NormalWeightedMeanPrecision, right::NormalWeightedMeanPrecision)
    xi = weightedmean(left) + weightedmean(right)
    w  = precision(left) + precision(right)
    return NormalWeightedMeanPrecision(xi, w)
end

function Base.prod(::ProdAnalytical, left::NormalWeightedMeanPrecision, right::NormalWeightedMeanPrecision)
    xi = weightedmean(left) + weightedmean(right)
    w  = precision(left) + precision(right)
    return NormalWeightedMeanPrecision(xi, w)
end

ext: jl


text:
# # Modelling the establishment potential of _Drosophila suzukii_
#
# In this example we will calculate the expected population growth rates of
# Spotted Wing Drosophila (SWD) _D. suzukii_, for each month of the year on a 9km grid
# accross North America.
#
# We'll experiment with running the model with a number of different datasets.
# GrowthMaps.jl, via GeoData.jl, faciliates using a wide range of input sources.

# First we will use aggregated data in tiff files, then aggregate them to in-memory
# files to run the inferface. Finally if you can download it, we'll use the
# (huge) SMAP dataset, which is in a custom HDF5 format.
#
# Load some required packages
using GeoData, Plots, Dates
using Unitful, UnitfulRecipes
using GrowthMaps
# Set the path for docs materials from GrowthMaps.jl
basedir = realpath(joinpath(dirname(pathof(GrowthMaps)), "../docs"))

# ## Define model components

# First we'll define the growth model using `SchoolfieldIntrinsicGrowth`,
# based on Schoolfield (1981).

# ### Growth Model
#
# These are parameters with units.
# To use them in `fit!` and in the interface, we
# use ModelParameters.jl `Param` wrappers
p = Param(3e-1)
ΔH_A = Param(3e4; units=u"cal/mol")
ΔH_L = Param(-1e5; units=u"cal/mol")
ΔH_H = Param(3e5; units=u"cal/mol")
Thalf_L = Param(2e2; units=u"K")
Thalf_H = Param(3e2; units=u"K")
T_ref = u"K"(25.0u"°C")

# Use the parameters in the SchoolfieldIntrinsicGrowth model
growthmodel = SchoolfieldIntrinsicGrowth(p, ΔH_A, ΔH_L, Thalf_L, ΔH_H, Thalf_H, T_ref)

# Now connect the model with a layer from the dataset, and give the layer units
growth = Layer(:surface_temp, u"K", growthmodel)

# Load lab observations
#
# If these are only estimated parameters, we can also fit the model to a a dataset
# of growth rate and temperature.
#
# First extract our independent and dependent variables from the example CSV:
using DataFrames, CSV
obscsv = CSV.File(joinpath(basedir, "swd_ecophys_data.csv"); select=[:x_value, :y_value, :y_key])
obsdata = DataFrame(obscsv) |> df -> filter(d -> d.y_key == "r_m", df) |> dropmissing

# Then extract the required data colummns, and convert temperature values from
# unitless Celcius to explit Kelvins, using Unitful.jl:
obsrate = obsdata.y_value
obstemp = obsdata.x_value .* u"°C" .|> u"K"
obs = collect(zip(obstemp, obsrate))

# Now we can fit the model. The `fitrate` function provides an easy way to fit the
# models in GrowthMaps or your own custom `RateModel`s, using the LsqFit.jl
# package:
model = Model(growth)
GrowthMaps.fit!(model, obs)

# Plot the fit against the data
#
# Define a custom temperature range
temprange = (270.0:0.1:310.0)u"K"
# Plot the rate
temp_plot = plot(temprange; label="fitted") do x
    GrowthMaps.rate(stripparams(model), x)
end
scatter!(temp_plot, obs; label="observed")

# Manual tweaking
#
# We can also try tweaking the fitting the model manually in a user interface.
# Model components are immutable (for performance reasons), so we wrap the model
# in a mutable wraper so we can use the results.
# We parametrise the model over the same temperature range that we are plotting,
# using the :surface_temp key that the model requires:
tempdata = (surface_temp=temprange,)
fit_interface = manualfit!(model, tempdata; observations=obs)

# To use the it in a desktop app, use Blink.jl:
# using Blink
# w = Blink.Window()
# body!(w, fit_interface)

# Note that `manualfit!` will also work with multiple model components
# that use the same source data, like `Model(growth, heatstress, coldstress)`.

# ## Load spatial data
#
# Later we can use real SMAP datasets using GeoData.jl SMAPseries loader.
# But downloading the dataset takes too long for an example.
# Instead we will download and unzip some lower resolution monthly
# data to use in the model:
using Downloads
dataurl = "https://media.githubusercontent.com/media/cesaraustralia/GrowthMaps.jl/data/SMAP_aggregated27km.zip"
zipfilepath = joinpath(basedir, "SMAP_aggregated27km.zip")
unzippedfolder = joinpath(basedir, "SMAP_aggregated27km")
isfile(zipfilepath) || Downloads.download(dataurl, zipfilepath)
run(`unzip -o $zipfilepath -d $basedir`);

# Get the paths for to all the wilting and surface-temp files
filenames = readdir(unzippedfolder)
wilting_filenames = filter(fn -> occursin(r"land_fraction_wilting", fn), filenames)
surface_temp_filenames = filter(fn -> occursin(r"surface_temp", fn), filenames)
wilting_paths = joinpath.(Ref(unzippedfolder), wilting_filenames)
surface_temp_paths = map(p -> joinpath(unzippedfolder, p), surface_temp_filenames)
# Get the dates the `surface_temp` files using regex.
# Then use them to create the time dimension
date_format = DateFormat("yyyymmddTHHMMSS");
dates = DateTime.(replace.(surface_temp_paths, Ref(r".*_(\d+T\d+).tif" => s"\1")), Ref(date_format))

# Make a new time dimension
timedim = Ti(dates; mode=Sampled(span=Regular(Hour(3))))

# We know the `land_fraction_wilting` files are for the same dates.
#
# Now we have the files and date seies, we can put together a series of
# GeoData.jl stacks to load lazily from disk while running `mapgrowth`.
#
# Make a NamedTuple of Vectors of String paths to the files
layers = (land_fraction_wilting=wilting_paths, surface_temp=surface_temp_paths)

# Create the series
tiffseries = GeoSeries(layers, (timedim,); mappedcrs=EPSG(4326))
tiffseries = map(x -> view(x, Band(1)), tiffseries)

# We can plot a layer from a file at some date in the series:
tiffseries[Ti(Near(DateTime(2016, Feb)))] |> plot

# Set the time period to a month, and set the length of the subsample period to
# the available times over one day:
#
# ## Run a model over the spatial data
#
# Define a timespan range to run the model over:
tspan = DateTime(2016, Jan):Month(1):DateTime(2016, Dec)

# Then to start, we'll run a simple model that only calculates growth rate.
growth_output = mapgrowth(model;
    series=tiffseries, tspan=tspan,
)

# Then plot the results:
growth_output[Ti(1)] |> plot

# It doesn't really capture realistic population growth: there are no growth rates
# below zero. We need to add some stress models. Stress models model processes
# that produce negative deathrates in the population, as oposed to rate models,
# where the minimum growth rate is zero.
#
# Stress models have a threshold in K and mortality
# rate per degree K. `LowerStress` models stress below the given threshold, while
# `UpperStress` models stress induced above a threshold.
#
# We will define stress models for cold, heat and wilt stress.
# As SWD live on and around plants, we use the proportion of plants
# wilting as an indicater of stress induced by lack of moisture.
coldthresh = Param(ustrip(u"K", -10.0f0u"°C"); units=u"K", bounds=(240, 290))  # Stephens2015
coldmort = Param(-log(1.23f0); units=u"K"^-1, bounds=(0, 0.4)) # Stephens2015
coldstress = Layer(:surface_temp, u"K", LowerStress(coldthresh, coldmort))

heatthresh = Param(ustrip(u"K"(30.0u"°C")); units=u"K", bounds=(280, 330)) # Kimura2004
heatmort = Param(-log(1.15); units= u"K"^-1, bounds=(0, 0.4))
heatstress = Layer(:surface_temp, u"K", UpperStress(heatthresh, heatmort))

wiltthresh = Param(0.5; bounds=(0, 1)) # default?
wiltmort = Param(-log(1.1); bounds=(0, 0.4));
wiltstress = Layer(:land_fraction_wilting, UpperStress(wiltthresh, wiltmort));

# Missing the aggregated data for this!
# wetthresh = 0.8f0
# wetmort = -10.0f0
# wetstress = Layer(:sm_surface_wetness, WetStress(wetthresh, wetmort));

# ## Analyse the stressors
#
# ## Heat stress
heat_output = mapgrowth(heatstress;
    series=tiffseries, tspan=tspan,
)
plot(heat_output[Ti(1)])

# ## Cold stress
cold_output = mapgrowth(coldstress;
    series=tiffseries, tspan=tspan,
)
plot(cold_output[Ti(1)])

# ## Wilting stress
wilt_output = mapgrowth(wiltstress;
    series=tiffseries, tspan=tspan,
)
plot(wilt_output[Ti(1)])

# ## Combine the stressors
stress_output = mapgrowth(coldstress, heatstress, wiltstress;
    series=tiffseries, tspan=tspan,
)
plot(stress_output[Ti(1)])

plot(stress_output[Ti(1)]; clims=(-1, 0))

# To build a more complex model, we can chain components together
# in a tuple, and again, run and plot them:
model_output = mapgrowth(growth, coldstress, heatstress, wiltstress;
    series=tiffseries, tspan=tspan,
)

# ## Show just rates above zero
#
# For January:
plot(model_output[Ti(Jan)]; color=:oleron, clims=(-0.3, 0.3))

# For July:
plot(model_output[Ti(July)]; color=:oleron, clims=(-0.3, 0.3))

# ## Take the mean growth rate
using Statistics
mean_growth = mean(model_output; dims=Ti)
plot(mean_growth; color=:oleron, clims=(-0.3, 0.3))

# ## Compare with observation data
#
# To compare out simulation with observations data,
# we'll first load them from a CSV file:
csvurl = "https://raw.githubusercontent.com/cesaraustralia/GrowthMaps.jl/data/Oersted_occurrence.csv"
csvfilename = joinpath(basedir, "Oersted_occurrence.csv")
isfile(csvfilename) || download(csvurl, csvfilename)

obs = CSV.File(csvfilename)
occurrence = collect(zip(obs.Longitude, obs.Latitude))

# This means positive and negative growth-rates are clear
growth_plot = plot(mean_growth; color=:oleron, clims=(-0.3, 0.3))
# Then scatter them on a map:
scatter!(growth_plot, occurrence;
     label="obs", legend=:none, fillalpha=0,
     markeralpha=0.4,
     markersize=2.0, markercolor=:red, markershape=:cross,
)

# ## Save the results
#
# Write the output as a NetCDF file
write("growthrates.nc", model_output)
# And check it
GeoArray("growthrates.nc")

# ## Parametrising models using interactive maps

# If you need to adjust the model based on the distribution, this
# can be done live in the interface, as with the manual fit.
#
# But parametrising maps on large datasets is processor intensive, which inhibits
# interactive fedback. To reduce processing, we can aggregate the spatial data to
# a more manageable size.
#
# You can experiment with the `agg` size to compromise between quality and render time.
# Large values will look pixelated but will run fast.
#
# `Center()` simply takes the central cell. `Statistics.mean` would take the mean value.
agg = 8
aggseries = GeoData.aggregate(Center(), read(tiffseries), (X(agg), Y(agg)))

# Then fit the other components. `throttle` will dictate how fast the interface
# updates. Make it larger on a slow machine, smaller on a faster one.
# The `window` argument lets us select a window of the output to view, using
# DimensionalData.jl/GeoData.jl `Dimension`s and `Selector`s. Here we only plot
# the first time: but you can select any/multiple, and select them with
# `Near(DateTime(2016,2))` or similar.
whole_year = DateTime(2016, 1):Year(1):DateTime(2016, 12)
stress_model = Model((coldstress, heatstress, wiltstress))
mapfit_interface = mapfit!(model, (series=aggseries, tspan=whole_year);
    occurrence=occurrence,
    throttle=0.1,
    colorbar=true,
    clims=(-2, 0),
    markershape=:cross,
    markercolor=:red,
    markeropacity=0.4,
    window=(Ti(1),),
)

# In atom, this will show the interface in the plot pane:
display(mapfit_interface)

# To use the it in a desktop app, use Blink.jl:
## using Blink
## w = Blink.Window()
## body!(w, mapfit_interface)

# And get the updated model components from the model:
# wiltstress, coldstress, heatstress = parent(stress_model)

# Now we will put together decent population growth maps
# using the higher resolutions data, and a monthly tiestep:
final_output = mapgrowth(growth, wiltstress, coldstress, heatstress;
    series=tiffseries,
    tspan=tspan,
);
plot(final_output[Ti(1:3:12)]; axis=false)

# ## Save the results
#
# Write the output as a NetCDF file
write("growthrates.nc", final_output)

# We can load it again with:
A = GeoArray("growthrates.nc")
plot(A[Ti(1)])

# Use the real SMAP dataset

# Using aggregated data loses some of the impact of the stress
# models, which respond to extremes, not averages. If you need to use
# the model for a serious application, run it on the real SMAP dataset.
#
# Unfortunately we can't just download the data for you with a script,
# as you need to log in to an account to have access.
#
# But GeoData.jl has a `SMAPseries()` constructor that will automate the
# whole process of loading SMAP HDF5 files from a folder once you have
# the data.
#
# We can also reduce the numer of days processed to 8 each month (or whatever)
# using the `Where` selector from DimensionalData.jl.

## using HDF5

# Set this to your own SMAP data folder
## smappath = "/home/raf/Storage/Data/SMAP/SMAP_L4_SM_gph_v4"

# Choose the dayes of month to use
## days = (1, 4, 8, 12, 16, 20, 23, 27) # 8 days per month

#days = 1:31 # all days
# Use the `Where` selector to choose dates in the time index by day of month
## smapseries = SMAPseries(smappath)[Ti(Where(d -> dayofmonth(d) in days))]

# Run the model:
## @time output = mapgrowth(model, wiltstress, coldstress, heatstress;
##    series=smapseries, tspan=tspan,
## )
## plot(output[Ti(1:3:12)]; axis=false)

# And save a netcdf:
## write(joinpath(basedir, "growthrates.nc"), output)

max_stars_repo_name: EcoJulia/Julia-PhD-course-Copenhagen

max_issues_repo_name: EcoJulia/Julia-PhD-course-Copenhagen

max_forks_repo_name: EcoJulia/Julia-PhD-course-Copenhagen


text:
using CoordinateTransformations, Rotations, TestImages, ImageCore, StaticArrays, OffsetArrays, Interpolations, LinearAlgebra
using EndpointRanges
using Tau
using Test, ReferenceTests

include("twoints.jl")

img_camera = testimage("camera")
@testset "Interface tests" begin
    tfm = recenter(RotMatrix(pi/8), center(img_camera))
    ref_inds = (-78:591, -78:591)
    ref_size = map(length,ref_inds)

    @testset "warp" begin
        imgr = @inferred(warp(img_camera, tfm))
        @test typeof(imgr) <: OffsetArray
        @test axes(imgr) == ref_inds
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg.txt" imgr

        imgr2 = imgr[axes(img_camera)...]
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop.txt" imgr2

        imgr = @inferred(warp(img_camera, tfm, axes(img_camera)))
        @test typeof(imgr) <: Array
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop.txt" imgr

        imgr = @inferred(warp(img_camera, tfm, axes(img_camera); fillvalue=1))
        @test typeof(imgr) <: Array
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop_white.txt" imgr

        imgr = @inferred(warp(img_camera, tfm, axes(img_camera); method=Linear(), fillvalue=1))
        @test typeof(imgr) <: Array
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop_white.txt" imgr

        imgr = @inferred(warp(img_camera, tfm; fillvalue=1))
        @test typeof(imgr) <: OffsetArray
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_white.txt" imgr
        imgr2 = @inferred warp(imgr, inv(tfm))
        @test eltype(imgr2) == eltype(img_camera)
        @test_reference "reference/warp_cameraman.txt" imgr2[axes(img_camera)...]
        # look the same but are not similar enough to pass test
        # @test imgr2[axes(img_camera)...] ≈ img_camera

        imgr = @inferred(warp(img_camera, tfm; fillvalue=Flat()))
        @test typeof(imgr) <: OffsetArray
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_flat.txt" imgr
        imgr = @inferred(warp(img_camera, tfm, ref_inds; fillvalue=Flat()))
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_flat.txt" imgr

        imgr = @inferred(warp(img_camera, tfm; method=Constant(), fillvalue=Periodic()))
        @test typeof(imgr) <: OffsetArray
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_periodic.txt" imgr
        imgr = @inferred(warp(img_camera, tfm, ref_inds; method=Constant(), fillvalue=Periodic()))
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_periodic.txt" imgr

        # Ensure that dynamic arrays work as transformations
        tfmd = AffineMap(Matrix(tfm.linear), Vector(tfm.translation))
        imgrd = @inferred(warp(img_camera, tfmd))
        imgrd = warp(img_camera, tfmd)
        @test imgrd == warp(img_camera, tfm)
        tfmd = LinearMap(Matrix(tfm.linear))
        @test @inferred(warp(img_camera, tfmd)) == warp(img_camera, LinearMap(tfm.linear))
        tfmd = Translation([-2, 2])
        @test @inferred(warp(img_camera, tfmd)) == warp(img_camera, Translation(-2, 2))
        @test_throws DimensionMismatch warp(img_camera, Translation([1,2,3]))

        # Since Translation can be constructed from any iterable, check that we support this too.
        # (This ensures the fallback for `_getindex` gets called even if we fix the issue by other means)
        tfmt = Translation(TwoInts(1, 2))
        @test tfmt isa Translation{TwoInts}
        imgt = warp(img_camera, tfmt)  # not necessarily inferrable, that's OK
        @test imgt == warp(img_camera, Translation(1,2))
    end

    @testset "WarpedView" begin
        imgr = @inferred(WarpedView(img_camera, tfm))
        @test_nowarn summary(imgr)
        @test @inferred(getindex(imgr,2,2)) == imgr[2,2]
        @test typeof(imgr[2,2]) == eltype(imgr)
        @test size(imgr) == ref_size
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: WarpedView
        @test axes(imgr) == ref_inds
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg.txt" imgr

        imgr2 = imgr[axes(img_camera)...]
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop.txt" imgr2

        imgr = @inferred(WarpedView(img_camera, tfm, axes(img_camera)))
        @test_nowarn summary(imgr)
        @test @inferred(size(imgr)) == size(img_camera)
        @test @inferred(size(imgr,3)) == 1
        @test parent(imgr) === img_camera
        @test axes(imgr) === axes(img_camera)
        @test typeof(imgr) <: WarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop.txt" imgr

        imgr = @inferred(WarpedView(img_camera, tfm, axes(img_camera); fillvalue=1))
        @test_nowarn summary(imgr)
        @test @inferred(size(imgr)) == size(img_camera)
        @test @inferred(size(imgr,3)) == 1
        @test parent(imgr) === img_camera
        @test axes(imgr) === axes(img_camera)
        @test typeof(imgr) <: WarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop_white.txt" imgr

        imgr = @inferred(WarpedView(img_camera, tfm, axes(img_camera); method=Linear(), fillvalue=1))
        @test_nowarn summary(imgr)
        @test @inferred(size(imgr)) == size(img_camera)
        @test @inferred(size(imgr,3)) == 1
        @test parent(imgr) === img_camera
        @test axes(imgr) === axes(img_camera)
        @test typeof(imgr) <: WarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop_white.txt" imgr

        imgr = @inferred(WarpedView(img_camera, tfm; fillvalue=1))
        @test_nowarn summary(imgr)
        @test size(imgr) == ref_size
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: WarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_white.txt" imgr
        imgr2 = @inferred WarpedView(imgr, inv(tfm))
        @test eltype(imgr2) == eltype(img_camera)
        @test_reference "reference/warp_cameraman.txt" imgr2[axes(img_camera)...]
        # look the same but are not similar enough to pass test
        # @test imgr2[axes(img_camera)...] ≈ img_camera

        imgr = @inferred(WarpedView(img_camera, tfm; fillvalue=Flat()))
        @test_nowarn summary(imgr)
        @test size(imgr) == ref_size
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: WarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_flat.txt" imgr
        imgr = @inferred(WarpedView(img_camera, tfm, ref_inds; fillvalue=Flat()))
        @test eltype(imgr) == eltype(img_camera)
        @test axes(imgr) === ref_inds
        @test_reference "reference/warp_cameraman_rotate_r22deg_flat.txt" imgr

        imgr = @inferred(WarpedView(img_camera, tfm; method=Constant(), fillvalue=Periodic()))
        @test_nowarn summary(imgr)
        @test size(imgr) == ref_size
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: WarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_periodic.txt" imgr

        imgr = @inferred(WarpedView(img_camera, tfm, ref_inds; method=Constant(), fillvalue=Periodic()))
        @test_nowarn summary(imgr)
        @test size(imgr) == ref_size
        @test parent(imgr) === img_camera
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_periodic.txt" imgr
    end

    tfm = recenter(RotMatrix(-pi/8), center(img_camera))
    @testset "invwarpedview" begin
        wv = @inferred(InvWarpedView(img_camera, tfm))
        @test wv ≈ @inferred(InvWarpedView(WarpedView(img_camera, inv(tfm))))
        @test_reference "reference/invwarpedview_cameraman_rotate_r22deg.txt" wv
        @test size(wv) == ref_size
        @test axes(wv) == ref_inds
        @test eltype(wv) === eltype(img_camera)
        @test parent(wv) === img_camera

        # check nested transformation using the inverse
        wv2 = @inferred(InvWarpedView(wv, inv(tfm)))
        @test axes(wv2) == axes(img_camera)
        @test eltype(wv2) === eltype(img_camera)
        @test parent(wv2) === img_camera
        @test_skip wv2 ≈ img_camera      # see discussion in #143
        @test wv2[ibegin+1:iend-1,ibegin+1:iend-1] ≈ img_camera[ibegin+1:iend-1,ibegin+1:iend-1]  # TODO: change to begin/end, drop EndpointRanges

        imgr = @inferred(InvWarpedView(img_camera, tfm))
        @test_nowarn summary(imgr)
        @test size(imgr) == ref_size
        @test typeof(imgr) <: InvWarpedView
        @test parent(imgr) === img_camera
        @test axes(imgr) == ref_inds
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg.txt" imgr

        imgr2 = imgr[axes(img_camera)...]
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop.txt" imgr2

        imgr = @inferred(InvWarpedView(img_camera, tfm, axes(img_camera)))
        @test imgr2 == imgr
        @test_nowarn summary(imgr)
        @test @inferred(size(imgr)) == size(img_camera)
        @test axes(imgr) === axes(img_camera)
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: InvWarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop.txt" imgr

        imgr = @inferred(InvWarpedView(img_camera, tfm, axes(img_camera); fillvalue=1))
        @test_nowarn summary(imgr)
        @test @inferred(size(imgr)) == size(img_camera)
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: InvWarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop_white.txt" imgr

        imgr = @inferred(InvWarpedView(img_camera, tfm, axes(img_camera); method=Linear(), fillvalue=1))
        @test_nowarn summary(imgr)
        @test @inferred(size(imgr)) == size(img_camera)
        @test parent(imgr) === img_camera
        @test axes(imgr) === axes(img_camera)
        @test typeof(imgr) <: InvWarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_crop_white.txt" imgr

        imgr = @inferred(InvWarpedView(img_camera, tfm; fillvalue=1))
        @test_nowarn summary(imgr)
        @test size(imgr) == ref_size
        @test axes(imgr) === ref_inds
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: InvWarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_white.txt" imgr

        imgr = @inferred(InvWarpedView(img_camera, tfm; fillvalue=Flat()))
        @test_nowarn summary(imgr)
        @test size(imgr) == ref_size
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: InvWarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_flat.txt" imgr
        imgr = @inferred(InvWarpedView(img_camera, tfm, ref_inds; fillvalue=Flat()))
        @test parent(imgr) === img_camera
        @test eltype(imgr) == eltype(img_camera)
        @test axes(imgr) === ref_inds
        @test_reference "reference/warp_cameraman_rotate_r22deg_flat.txt" imgr

        imgr = @inferred(InvWarpedView(img_camera, tfm; method=Constant(), fillvalue=Periodic()))
        @test_nowarn summary(imgr)
        @test size(imgr) == ref_size
        @test axes(imgr) == ref_inds
        @test parent(imgr) === img_camera
        @test typeof(imgr) <: InvWarpedView
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_periodic.txt" imgr

        imgr = @inferred(InvWarpedView(img_camera, tfm, ref_inds; method=Constant(), fillvalue=Periodic()))
        @test_nowarn summary(imgr)
        @test parent(imgr) === img_camera
        @test size(imgr) == ref_size
        @test axes(imgr) == ref_inds
        @test eltype(imgr) == eltype(img_camera)
        @test_reference "reference/warp_cameraman_rotate_r22deg_periodic.txt" imgr
    end

    @testset "InvWarpedView on SubArray" begin
        tfm = recenter(RotMatrix(-pi/8), center(img_camera))
        img = similar(img_camera)
        v = view(img, 75:195, 245:370)
        v .= view(img_camera, v.indices...)

        wv = InvWarpedView(v, tfm)
        @test wv isa InvWarpedView
        @test parent(wv) == v
        @test axes(wv) == (-78:82, 72:234)
        # boundaries are filled with 0 values
        @test all(wv[first(axes(wv, 1)), :] .== 0)
        @test all(wv[last(axes(wv, 1)), :] .== 0)
        @test all(wv[:, first(axes(wv, 2))] .== 0)
        @test all(wv[:, last(axes(wv, 2))] .== 0)

        # Out-of-domain values are not used to generate the warp view
        v = view(img_camera, 75:195, 245:370)
        wv2 = InvWarpedView(v, tfm)
        @test wv2 == wv == warp(v, inv(tfm))
    end

    @testset "3d warps" begin
        img = testimage("mri")
        θ = π/8
        tfm = AffineMap(RotZ(θ), (I - RotZ(θ))*center(img))
        imgr = WarpedView(img, tfm, axes(img))
        @test axes(imgr) == axes(img)
    end
end

img_pyramid = Gray{Float64}[
    0.0 0.0 0.0 0.0 0.0;
    0.0 0.5 0.5 0.5 0.0;
    0.0 0.5 1.0 0.5 0.0;
    0.0 0.5 0.5 0.5 0.0;
    0.0 0.0 0.0 0.0 0.0;
]
img_pyramid_cntr = OffsetArray(img_pyramid, -2:2, -2:2)
ref_img_pyramid = Float64[
    NaN   NaN   NaN   NaN   NaN   NaN   NaN;
    NaN   NaN   NaN  0.172  NaN   NaN   NaN;
    NaN   NaN  0.293 0.543 0.293  NaN   NaN;
    NaN  0.172 0.543 1.000 0.543 0.172  NaN;
    NaN   NaN  0.293 0.543 0.293  NaN   NaN;
    NaN   NaN   NaN  0.172  NaN   NaN   NaN;
    NaN   NaN   NaN   NaN   NaN   NaN   NaN;
]
ref_img_pyramid_quad = Float64[
    NaN      NaN      NaN      0.003    NaN      NaN      NaN;
    NaN      NaN     -0.038    0.205   -0.038    NaN      NaN;
    NaN     -0.038    0.255    0.635    0.255   -0.038    NaN;
    0.003    0.205    0.635    1.0      0.635    0.205    0.003;
    NaN     -0.038    0.255    0.635    0.255   -0.038    NaN;
    NaN      NaN     -0.038    0.205   -0.038    NaN      NaN;
    NaN      NaN      NaN      0.003    NaN      NaN      NaN;
]
ref_img_pyramid_grid = Float64[
    NaN  NaN         NaN         NaN         NaN         NaN         NaN;
    NaN  NaN         NaN           0.157977  NaN         NaN         NaN;
    NaN  NaN           0.223858    0.654962    0.223858  NaN         NaN;
    NaN    0.157977    0.654962    1.0         0.654962    0.157977  NaN;
    NaN  NaN           0.223858    0.654962    0.223858  NaN         NaN;
    NaN  NaN         NaN           0.157977  NaN         NaN         NaN;
    NaN  NaN         NaN         NaN         NaN         NaN         NaN;
]
ref_img_pyramid_lanczos = Float64[
NaN  NaN      NaN      NaN      NaN      NaN      NaN
NaN  NaN      NaN        0.204  NaN      NaN      NaN
NaN  NaN        0.22     0.649    0.22   NaN      NaN
NaN    0.204    0.649    1.0      0.649    0.204  NaN
NaN  NaN        0.22     0.649    0.22   NaN      NaN
NaN  NaN      NaN        0.204  NaN      NaN      NaN
NaN  NaN      NaN      NaN      NaN      NaN      NaN
]
@testset "Result against reference" begin

    tfm1 = recenter(RotMatrix(pi/4), center(img_pyramid))
    tfm2 = LinearMap(RotMatrix(pi/4))

    @testset "warp" begin
        imgr = warp(img_pyramid, tfm1)
        @test axes(imgr) == (0:6, 0:6)
        @test eltype(imgr) == eltype(img_pyramid)
        # Use map and === because of the NaNs
        @test nearlysame(round.(Float64.(parent(imgr)), digits=3), round.(ref_img_pyramid,digits=3))

        # https://discourse.julialang.org/t/translate-images-by-subpixel-amounts/30248/4
        a = [1 2 3; 4 5 6]
        t = Translation(.9, .9)
        b = warp(a, t, indices_spatial(a); fillvalue=0)
        @test b[1,1] ≈ 0.9^2*5 + 0.1*0.9*(4+2) + 0.1^2*1

        @testset "OffsetArray" begin
            imgr_cntr = warp(img_pyramid_cntr, tfm2)
            @test axes(imgr_cntr) == (-3:3, -3:3)
            @test nearlysame(parent(imgr_cntr), parent(imgr))

            imgr_cntr = warp(img_pyramid_cntr, tfm2, (-1:1,-1:1))
            @test axes(imgr_cntr) == (-1:1, -1:1)
            @test nearlysame(parent(imgr_cntr), imgr[2:4,2:4])
        end

        @testset "Method kwarg" begin
            imgr_cntr = warp(img_pyramid_cntr, tfm2, method=Linear())
            @test axes(imgr_cntr) == (-3:3, -3:3)
            @test nearlysame(parent(warp(img_pyramid_cntr, tfm2)), parent(warp(img_pyramid_cntr, tfm2, method=Linear())))

            imgr_cntr = warp(img_pyramid_cntr, tfm2, (-1:1,-1:1), method=Linear())
            @test axes(imgr_cntr) == (-1:1, -1:1)
            @test nearlysame(parent(imgr_cntr), imgr[2:4,2:4])

            imgr_cntr = warp(img_pyramid_cntr, tfm2, method=BSpline(Linear()))
            @test axes(imgr_cntr) == (-3:3, -3:3)
            @test nearlysame(parent(imgr_cntr), parent(imgr))

            imgr_cntr = warp(img_pyramid_cntr, tfm2, (-1:1, -1:1), method=BSpline(Linear()))
            @test axes(imgr_cntr) == (-1:1, -1:1)
            @test nearlysame(parent(imgr_cntr), imgr[2:4,2:4])

            imgr_cntr = warp(img_pyramid_cntr, tfm2, method=Lanczos4OpenCV())
            @test axes(imgr_cntr) == (-3:3, -3:3)
            @test nearlysame(round.(Float64.(parent(imgr_cntr)), digits=3), round.(ref_img_pyramid_lanczos, digits=3))
        end

        @testset "Quadratic Interpolation" begin
            itp = interpolate(img_pyramid_cntr, BSpline(Quadratic(Flat(OnCell()))))
            imgrq_cntr = warp(itp, tfm2)
            @test axes(imgrq_cntr) == (-3:3, -3:3)
            @test nearlysame(round.(Float64.(parent(imgrq_cntr)), digits=3), round.(ref_img_pyramid_quad, digits=3))

            imgrq_cntr = warp(img_pyramid_cntr, tfm2, method=Quadratic(Flat(OnGrid())))
            @test axes(imgrq_cntr) == (-3:3, -3:3)
            @test nearlysame(round.(Float64.(parent(imgrq_cntr)), digits=3), round.(ref_img_pyramid_grid, digits=3))
        end
    end

    @testset "InvWarpedView" begin
        imgr = InvWarpedView(img_pyramid, inv(tfm1))
        @test axes(imgr) == (0:6, 0:6)
        # Use map and === because of the NaNs
        @test nearlysame(round.(Float64.(imgr[0:6, 0:6]), digits=3), round.(ref_img_pyramid, digits=3))

        @testset "OffsetArray" begin
            imgr_cntr = InvWarpedView(img_pyramid_cntr, inv(tfm2))
            @test axes(imgr_cntr) == (-3:3, -3:3)
            @test nearlysame(imgr_cntr[axes(imgr_cntr)...], imgr[axes(imgr)...])
        end

        @testset "Quadratic Interpolation" begin
            itp = interpolate(img_pyramid_cntr, BSpline(Quadratic(Flat(OnCell()))))
            imgrq_cntr = InvWarpedView(itp, inv(tfm2))
            @test parent(imgrq_cntr) === itp
            @test_nowarn summary(imgrq_cntr)
            @test axes(imgrq_cntr) == (-3:3, -3:3)
            @test eltype(imgrq_cntr) == eltype(img_pyramid_cntr)

            @test nearlysame(round.(Float64.(imgrq_cntr[axes(imgrq_cntr)...]), digits=3), round.(ref_img_pyramid_quad, digits=3))
        end
    end

    @testset "imrotate" begin
    # imrotate is a wrapper, hence only need to guarantee the interface works as expected

        test_types = (Float32, Float64, N0f8, N0f16)
        graybar = repeat(range(0,stop=1,length=100),1,100)
        @testset "interface" begin
            for T in test_types
                img = Gray{T}.(graybar)
                @test_nowarn imrotate(img, π/4)
                @test_nowarn imrotate(img, π/4, method=Linear())
                @test_nowarn imrotate(img, π/4, method=Lanczos4OpenCV())

                @test_nowarn imrotate(img, π/4, axes(img))
                @test_nowarn imrotate(img, π/4, axes(img), method=Constant())
                @test_nowarn imrotate(img, π/4, axes(img), method=Constant(), fillvalue=1)

                @test nearlysame(imrotate(img, π/4, method=Linear()), imrotate(img, π/4, method=BSpline(Linear())))
                @test nearlysame(imrotate(img, π/4), imrotate(img, π/4; method=Linear(), fillvalue= ImageTransformations._default_fillvalue(eltype(T))))
            end
        end

        @testset "numerical" begin
            for T in test_types
                img = Gray{T}.(graybar)
                for θ in range(0,stop=2π,length = 100)
                    @test nearlysame(imrotate(img,θ), imrotate(img,θ+2π))
                end
            end
        end

        @testset "issue #147" begin
            img = Float64[1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16]
            trfm = recenter(RotMatrix(pi/2), center(img))
            @test imrotate(img, π/2) ≈ warp(img, trfm) ≈ rotr90(img)
            @test  any(isnan, imrotate(img, π/3))
            @test !any(isnan, imrotate(img, π/3; fillvalue=0.0))
            @test !any(isnan, imrotate(img, π/3, fillvalue=0.0))
            @test  any(isnan, imrotate(img, π/3, axes(img)))
            @test !any(isnan, imrotate(img, π/3, axes(img); fillvalue=0.0))
            @test !any(isnan, imrotate(img, π/3, axes(img), fillvalue=0.0))
        end

        @testset "Examples from #79" begin
            @test axes(imrotate(img_camera, pi/2)) == axes(img_camera)
            @test imrotate(imrotate(imrotate(imrotate(img_camera, pi/2), pi/2), pi/2), pi/2) ≈ img_camera
            @test imrotate(imrotate(img_camera, pi), pi) == img_camera
            # Also check a "generic" irrational (one that happens to be quite special)
            ## First, check that this hits the generic code path (if we change that, pick a different irrational)
            @test ImageTransformations._mod2pi(τ) isa Float64
            ## Now check that it gives the expected result
            @test imrotate(img_camera, τ) ≈ img_camera

            # check special rotation degrees
            img = rand(Gray{N0f8}, 100, 50)
            @test size(imrotate(img, pi/2)) == (50, 100)
            @test size(imrotate(img, pi)) == (100, 50)
            @test size(imrotate(img, 3pi/2)) == (50, 100)
            @test size(imrotate(img, 2pi)) == (100, 50)
        end
    end
end


text:
import DataFrames: DataFrame
using Tables

include("exports.jl")
include("readORG.jl")
include("writeOGR.jl")


text:
function real_eigvectors(A)
    n = size(A, 1)

    vals, vecs = eigen(A)
    ix = imag.(vals) .>= 0

    real.(vals[ix]), real.(vecs[:, ix]), isreal.(vals[ix])
end

function rosenbrok(A, B, C)
    if length(B) == 0
        [
            A
            C
        ]
    elseif length(C) == 0
        [
            A B
        ]
    else
        [
            A B
            C zeros(size(C, 1), size(B, 2))
        ]
    end
end

function fixed_modes(A, B, C)
    ra = eigvals(A)
    rn = length(ra)
    n = size(A, 1)
    N = length(B)

    minsvd = Inf .* ones(rn)

    for i in 1:rn
        for j in 1:2^N
            mask = digits(Bool, j - 1, base=2, pad=N)
            BB = reduce(hcat, B[mask], init=zeros(n, 0))
            CC = reduce(vcat, C[.! mask], init=zeros(0, n))
            s = svdvals(DistributedControl.rosenbrok(A - ra[i] * I, BB, CC))
            if minsvd[i] > s[n]
                minsvd[i] = s[n]
            end
        end
    end
    minsvd
end