text:
mutable struct Mol
    mol::Ref{Cstring}
    mol_size::Ref{Csize_t}
    function Mol(mol::Cstring, mol_size::Ref{Csize_t})
        objref = Ref{Cstring}(mol)
        x = new(objref, mol_size)
        finalizer(x -> ccall((:free_ptr, librdkitcffi), Cvoid, (Cstring,), x.mol[]), x)
    end
end

"""
    get_mol(mol_string::AbstractString, details::Union{Dict{String,Any},Nothing}=nothing)::Union{Mol,Nothing}

Get a mol from a molblock (v2000, v3000), SMILES or SMARTS.

```julia
mol = get_mol("CC(=O)Oc1ccccc1C(=O)O")
```
"""
function get_mol(mol_string::AbstractString, details::Union{Dict{String,Any},Nothing}=nothing)::Union{Mol,Nothing}
    details_json::String = jsonify_details(details)
    mol_size = Ref{Csize_t}(0)
    val = ccall((:get_mol, librdkitcffi), Cstring, (Cstring, Ref{Csize_t}, Cstring), mol_string, mol_size, details_json)
    if val == C_NULL
        mol = nothing
    else
        mol = Mol(val, mol_size)
    end
    return mol
end

"""
    get_qmol(mol_string::AbstractString, details::Union{Dict{String,Any},Nothing}=nothing)::Union{Mol,Nothing}

Get a query mol (for substructure search) for a molblock (v2000, v3000), SMILES or SMARTS.

```julia
mol = get_qmol("c1ccccc1")
```
"""
function get_qmol(mol_string::AbstractString, details::Union{Dict{String,Any},Nothing}=nothing)::Union{Mol,Nothing}
    details_json::String = jsonify_details(details)
    mol_size = Ref{Csize_t}(0)
    val::Cstring = ccall((:get_qmol, librdkitcffi), Cstring, (Cstring, Ref{Csize_t}, Cstring), mol_string, mol_size, details_json)
    if val == C_NULL
        mol = nothing
    else
        mol = Mol(val, mol_size)
    end
    return mol
end

"""
    get_smiles(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String

Get the SMILES for a mol object.

```julia
smiles = get_smiles(mol)
```
"""
function get_smiles(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String
    details_json::String = jsonify_details(details)
    val::Cstring = ccall((:get_smiles, librdkitcffi), Cstring, (Cstring, Csize_t, Cstring), mol.mol[], mol.mol_size[], details_json)
    smiles = unsafe_string_and_free(val)
    return smiles
end

"""
    get_smarts(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String

Get the SMARTS for a mol object.

```julia
smarts = get_smarts(mol)
```
"""
function get_smarts(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String
    details_json::String = jsonify_details(details)
    val::Cstring = ccall((:get_smarts, librdkitcffi), Cstring, (Cstring, Csize_t, Cstring), mol.mol[], mol.mol_size[], details_json)
    smarts = unsafe_string_and_free(val)
    return smarts
end

"""
    get_cxsmiles(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String

Get the CXSMILES for a mol object.

```julia
cxsmiles = get_cxsmiles(mol)
```
"""
function get_cxsmiles(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String
    details_json::String = jsonify_details(details)
    val::Cstring = ccall((:get_cxsmiles, librdkitcffi), Cstring, (Cstring, Csize_t, Cstring), mol.mol[], mol.mol_size[], details_json)
    cxsmiles = unsafe_string_and_free(val)
    return cxsmiles
end

"""
    get_molblock(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String

Get the molblock (V2000) for a mol object.

```julia
molblock = get_molblock(mol)
```
"""
function get_molblock(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String
    details_json::String = jsonify_details(details)
    val::Cstring = ccall((:get_molblock, librdkitcffi), Cstring, (Cstring, Csize_t, Cstring), mol.mol[], mol.mol_size[], details_json)
    molblock = unsafe_string_and_free(val)
    return molblock
end

"""
    get_molblock(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String

Get the molblock (V3000) for a mol object.

```julia
v3kmolblock = get_v3kmolblock(mol)
```
"""
function get_v3kmolblock(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String
    details_json::String = jsonify_details(details)
    val::Cstring = ccall((:get_v3kmolblock, librdkitcffi), Cstring, (Cstring, Csize_t, Cstring), mol.mol[], mol.mol_size[], details_json)
    v3dmolblock = unsafe_string_and_free(val)
    return v3dmolblock
end

"""
    get_json(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String

Get the json (CommonChem format) for a mol object.

```julia
json = get_json(mol)
```
"""
function get_json(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String
    details_json::String = jsonify_details(details)
    val::Cstring = ccall((:get_json, librdkitcffi), Cstring, (Cstring, Csize_t, Cstring), mol.mol[], mol.mol_size[], details_json)
    json = unsafe_string_and_free(val)
    return json
end

"""
    get_inchi(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String

Get the InChI for a mol object.

```julia
inchi = get_inchi(mol)
```
"""
function get_inchi(mol::Mol, details::Union{Dict{String,Any},Nothing}=nothing)::String
    details_json::String = jsonify_details(details)
    val::Cstring = ccall((:get_inchi, librdkitcffi), Cstring, (Cstring, Csize_t, Cstring), mol.mol[], mol.mol_size[], details_json)
    inchi = unsafe_string_and_free(val)
    return inchi
end

"""
    get_inchi_for_molblock(molblock::AbstractString, details::Union{Dict{String,Any},Nothing}=nothing)::String

Get the InChI for a molblock.

```julia
inchi = get_inchi_for_molblock(molblock)
```
"""
function get_inchi_for_molblock(molblock::AbstractString, details::Union{Dict{String,Any},Nothing}=nothing)::String
    details_json::String = jsonify_details(details)
    val::Cstring = ccall((:get_inchi_for_molblock, librdkitcffi), Cstring, (Cstring, Cstring), molblock, details_json)
    inchi = unsafe_string_and_free(val)
    return inchi
end

"""
    get_inchikey_for_inchi(inchi::AbstractString)

Get the InChIKey for a InChI.

```julia
inchikey = get_inchikey_for_inchi("InChI=1S/C9H8O4/c1-6(10)13-8-5-3-2-4-7(8)9(11)12/h2-5H,1H3,(H,11,12)")
```
"""
function get_inchikey_for_inchi(inchi::AbstractString)
    val::Cstring = ccall((:get_inchikey_for_inchi, librdkitcffi), Cstring, (Cstring,), inchi)
    inchikey = unsafe_string_and_free(val)
    return inchikey
end


text:
using TensND, LinearAlgebra, SymPy, Tensors, OMEinsum, Rotations
sympy.init_printing(use_unicode=true)

Spherical = coorsys_spherical()
θ, ϕ, r = getcoords(Spherical)
𝐞ᶿ, 𝐞ᵠ, 𝐞ʳ = unitvec(Spherical)
ℬˢ = get_normalized_basis(Spherical)
𝐱 = getOM(Spherical)
@set_coorsys Spherical
𝐞₁, 𝐞₂, 𝐞₃ = unitvec(coorsys_cartesian())
# 𝟏, 𝟙, 𝕀, 𝕁, 𝕂 = init_isotropic(basis = ℬˢ)
𝕀, 𝕁, 𝕂 = ISO(Val(3),Val(Sym))
𝟏 = tensId2(Val(3),Val(Sym))
k, μ = symbols("k μ", positive = true)
λ = k -2μ/3

u = SymFunction("u", real = true)
𝐮ˢᵖʰ = u(r) * 𝐞ʳ
𝛆ˢᵖʰ = SYMGRAD(𝐮ˢᵖʰ, Spherical)
𝛔ˢᵖʰ = λ * tr(𝛆ˢᵖʰ) * 𝟏 + 2μ * 𝛆ˢᵖʰ
𝐓ˢᵖʰ = 𝛔ˢᵖʰ ⋅ 𝐞ʳ
div𝛔ˢᵖʰ = DIV(𝛔ˢᵖʰ, Spherical) ;
eqˢᵖʰ = factor(simplify(div𝛔ˢᵖʰ ⋅ 𝐞ʳ))
solˢᵖʰ = dsolve(eqˢᵖʰ, u(r))
ûˢᵖʰ = solˢᵖʰ.rhs()
T̂ˢᵖʰ = factor(simplify(subs(𝐓ˢᵖʰ ⋅ 𝐞ʳ, u(r) => ûˢᵖʰ)))

𝐄 = 𝟏 - 3𝐞₃⊗𝐞₃
fᶿ = simplify(𝐞ᶿ ⋅ 𝐄 ⋅ 𝐞ʳ)
fʳ = simplify(𝐞ʳ ⋅ 𝐄 ⋅ 𝐞ʳ)
# fᶿ = SymFunction("fᶿ", real = true)(θ)
# fʳ = SymFunction("fʳ", real = true)(θ)
uᶿ = SymFunction("uᶿ", real = true)
uʳ = SymFunction("uʳ", real = true)
𝐮ᵈᵉᵛ = uᶿ(r) * fᶿ * 𝐞ᶿ + uʳ(r) * fʳ * 𝐞ʳ
𝛆ᵈᵉᵛ = SYMGRAD(𝐮ᵈᵉᵛ, Spherical)
𝛔ᵈᵉᵛ = λ * tr(𝛆ᵈᵉᵛ) * 𝟏 + 2μ * 𝛆ᵈᵉᵛ
𝐓ᵈᵉᵛ = 𝛔ᵈᵉᵛ ⋅ 𝐞ʳ
div𝛔ᵈᵉᵛ = simplify(DIV(𝛔ᵈᵉᵛ, Spherical))
eqᶿᵈᵉᵛ = factor(simplify(div𝛔ᵈᵉᵛ ⋅ 𝐞ᶿ / fᶿ))
eqʳᵈᵉᵛ = factor(simplify(div𝛔ᵈᵉᵛ ⋅ 𝐞ʳ / fʳ))
α, Λ = symbols("α Λ", real = true)
eqᵈᵉᵛ = factor(simplify(subs([eqᶿᵈᵉᵛ,eqʳᵈᵉᵛ], uᶿ(r) => r^α, uʳ(r) => Λ*r^α)))
αΛ = solve([eq.doit() for eq ∈ eqᵈᵉᵛ], [α, Λ])
ûᶿᵈᵉᵛ = sum([Sym("C$(i+2)") * r^αΛ[i][1] for i ∈ 1:length(αΛ)])
ûʳᵈᵉᵛ = sum([Sym("C$(i+2)") * αΛ[i][2] * r^αΛ[i][1] for i ∈ 1:length(αΛ)])
T̂ᶿᵈᵉᵛ = factor(simplify(subs(simplify(𝐓ᵈᵉᵛ ⋅ 𝐞ᶿ / fᶿ), uᶿ(r) => ûᶿᵈᵉᵛ, uʳ(r) => ûʳᵈᵉᵛ)))
T̂ʳᵈᵉᵛ = factor(simplify(subs(simplify(𝐓ᵈᵉᵛ ⋅ 𝐞ʳ / fʳ), uᶿ(r) => ûᶿᵈᵉᵛ, uʳ(r) => ûʳᵈᵉᵛ)))

ext: jl


text:
using GlobalSensitivity, Test

function ishi(X)
    A= 7
    B= 0.1
    sin(X[1]) + A*sin(X[2])^2+ B*X[3]^4 *sin(X[1])
end

lb = -ones(4)*π
ub = ones(4)*π

m = gsa(ishi,DeltaMoment(),fill([lb[1], ub[1]], 3), N=1000)
@test m.deltas ≈ [0.191604, 0.253396, 0.148682] atol=3e-2


text:
@testset "LTI utils tests" begin

    N = 10
    types = [Int32, Int64, Float32, Float64, ComplexF32, ComplexF64]
    atol = 1e-2

    @testset "convolution/deconvolution tests" begin
        zerotol = 5
        for T in types
            if T <: Integer
                g = rand(-10 * one(T):10 * one(T), N)
                h = rand(-10 * one(T):10 * one(T), N)
                if h[1] == 0
                    h[1] = convert(T, rand([-1, 1]))
                end
            else
                g = rand(T, N)
                h = rand(T, N)
                if abs(h[1]) < zerotol
                    if T <: Real
                        h[1] = convert(T, zerotol) * sign(h[1])
                    else
                        h[1] = convert(T, zerotol * exp(angle(h[1]) * im))
                    end
                end
            end
            f = Romeo.LTI.convolve(g, h)
            ga = Romeo.LTI.deconvolve(f, h)
            @test isapprox(g, ga; atol=atol) || "Error for type = $T. max abs.err. = $(max(abs.(g - ga)...))"
        end # for
    end # testset

    @testset "convroot tests / positive first element" begin
        for T in types
            if T <: Integer
                g = rand(-10 * one(T):10 * one(T), N)
                g[1] = rand(1 * one(T):10 * one(T))
                h = Romeo.LTI.convolve(g, g)
            else
                g = rand(T, N)
                g[1] = abs(g[1]) + 0.01
                h = Romeo.LTI.convolve(g, g)
            end # if
            ga = Romeo.LTI.convroot(h)
            @test isapprox(g, ga; atol=atol) || "Error for type = $T. max abs.err. = $(max(abs.(g - ga)...))"
        end # for
    end # testset

    @testset "convroot tests / negative first element" begin
        for T in types
            if T <: Integer
                h = rand(-10 * one(T):10 * one(T), N)
                h[1] = -rand(1 * one(T):10 * one(T))
            else
                h = rand(T, N)
                h[1] = -(abs(h[1]) + 0.01)
            end # if
            g = Romeo.LTI.convroot(h)
            ha = Romeo.LTI.convolve(g, g)
            @test isapprox(h, ha; atol=atol) || "Error for type = $T. max abs.err. = $(max(abs.(h - ha)...))"
        end # for
    end # testset

end # testset


text:
# =========================================================================
#    ENVIRONMENT SETTINGS
# =========================================================================

#OPTIMIZER SETTING
const default_optimizer = Ref{Any}(nothing)
set_optimizer!(O) = default_optimizer[] = O
get_optimizer() = default_optimizer[]
reset_optimizer() = default_optimizer[] = nothing

#SLACK SURP COEFF SETTING
const slack_coeff = Ref{Any}(nothing)
const surp_coeff = Ref{Any}(nothing)
set_slack_coeff!(O) = slack_coeff[] = O
set_surp_coeff!(O) = surp_coeff[] = O
su_C() = surp_coeff[]
sl_C() = slack_coeff[]

#SILENCE SETTING
const verbosity = Ref{Any}(nothing)
silence!(O) = verbosity[] = O
silent() = verbosity[]


text: struct PlutoType <: abstractPlanet end


text:
using Revise
using Plots
using Basins
using DynamicalSystems
using RegionTrees

@inline @inbounds function duffing(u, p, t)
    d = p[1]; F = p[2]; omega = p[3]
    du1 = u[2]
    du2 = -d*u[2] + u[1] - u[1]^3 + F*sin(omega*t)
    return SVector{2}(du1, du2)
end

F=0.3818791946308725; ω= 0.1966442953020134
#F=0.2771812080536913; ω=0.1;
#ω=0.1617;F = 0.395
#ω=0.3;F = 0.1
ds = ContinuousDynamicalSystem(duffing, rand(2), [0.15, F, ω])
integ_df  = integrator(ds; reltol=1e-8, save_everystep=false)
xg = range(-2.2,2.2,length=300)
yg = range(-2.2,2.2,length=300)

@time bsn=Basins.basins_map2D_tree(xg, yg, integ; r_init=0.1, r_max=0.001)

function evaluate(basin,v)
    return findleaf(basin,v).data
end

plt = plot(xlim=(-2.2, 2.2), ylim=(-2.2, 2.2), legend=nothing)
x = range(-2.2, 2.2, length=1000)
y = range(-2.2, 2.2, length=1000)
heatmap!(plt, x, y, (x, y) -> evaluate(bsn.basin, SVector(x, y)), fill=true)

function compute_frac_dim(bsn)
    root_n(x,n) = foldl((y,_) -> parent(y), 1:n; init=x)
    N = zeros(Int, 20)
    wd=1e3
    k_mx = 0
    for lf in allcells(bsn.basin)
        k = 1
        while !isnothing(root_n(lf,k))
            k += 1
        end
        N[k] += 1
        wd = min(wd,lf.boundary.widths[1])
        k_mx = max(k_mx,k)
    end
    @show N
    eps = reverse(wd * 2 .^ range(0,k_mx-1,step=1))
    return eps,N[1:k_mx]
end

eps,N = compute_frac_dim(bsn)

elog = log10.(1 ./ eps)
Nlog = log10.(N)
D = linear_region(elog[4:end],Nlog[4:end])
@show D

# plt = plot(xlim=(-1.5, 1.5), ylim=(-1.5, 1.5), legend=nothing)
# col=Plots.palette(:tab20)
# for leaf in allleaves(bsn.basin)
#     v = hcat(collect(vertices(leaf.boundary))...)
#     #plot!(plt, v[1,[1,2,4,3,1]], v[2,[1,2,4,3,1]])
#     #@show leaf.data
#     plot!(plt, v[1,[1,2,4,3,1]], v[2,[1,2,4,3,1]],fill=(1,col[mod(leaf.data,20)]), linecolor=:black, lw=0)
#
# end
# plt


text:
using Documenter, GLOQ

const ROOT = joinpath(@__DIR__, "..")
makedocs(
    format = Documenter.HTML(
        prettyurls = get(ENV, "CI", nothing) == "true"
    ),
    sitename = "GLOQ.jl",
    modules = [GLOQ],
    authors = "Daniel Appelo <appeloda@msu.edu> and contributors.",
    pages = [
        "Home" => "index.md",
        "Governing models and notation" => Any["Models"=>"model.md",
                       "Protocols"=>"experiment.md"
                      ],
        "Workflow and examples" =>
            Any["Workflow"=>"workflow.md",
                "Example 1" => "example1.md",
                "Example 2" => "example2.md",
                "Example 3" => "example3.md"],
        "Types" => "types.md",
        "Methods" => "methods.md",
        "Index" => "function-index.md",
    ],
)

# Documenter can also automatically deploy documentation to gh-pages.
# See "Hosting Documentation" and deploydocs() in the Documenter manual
# for more information.
 deploydocs(
    repo = "github.com/appelo/GLOQ.jl.git",
    devbranch = "main"
)


text:
using Test
using Flux
using UNet

include("uchain.jl")
include("unet.jl")
include("utils.jl")


text:
"""

Just check if solute and solvent are the same

"""
function isautocorrelation(trajectory::Trajectory)
  if trajectory.solute.index == trajectory.solvent.index
    true
  else
    false
  end
end


text:
const pydatetime111 = pynew()

function init_datetime()
    pycopy!(pydatetime111, pydatetimetype(1, 1, 1))
end

pydate(year, month, day) = pydatetype(year, month, day)
pydate(x::Date) = pydate(year(x), month(x), day(x))
export pydate

pytime(_hour=0, _minute=0, _second=0, _microsecond=0, _tzinfo=nothing; hour=_hour, minute=_minute, second=_second, microsecond=_microsecond, tzinfo=_tzinfo, fold=0) = pytimetype(hour, minute, second, microsecond, tzinfo, fold=fold)
pytime(x::Time) =
    if iszero(nanosecond(x))
        pytime(hour(x), minute(x), second(x), millisecond(x) * 1000 + microsecond(x))
    else
        errset(pybuiltins.ValueError, "cannot create 'datetime.time' with less than microsecond resolution")
        pythrow()
    end
export pytime

pydatetime(year, month, day, _hour=0, _minute=0, _second=0, _microsecond=0, _tzinfo=nothing; hour=_hour, minute=_minute, second=_second, microsecond=_microsecond, tzinfo=_tzinfo, fold=0) = pydatetimetype(year, month, day, hour, minute, second, microsecond, tzinfo, fold=fold)
function pydatetime(x::DateTime)
    # compute time since 1/1/1
    # this accounts for fold
    d = pytimedeltatype(milliseconds = (x - DateTime(1, 1, 1)).value)
    ans = pydatetime111 + d
    pydel!(d)
    return ans
end
pydatetime(x::Date) = pydatetime(year(x), month(x), day(x))
export pydatetime

function pytime_isaware(x)
    tzinfo = pygetattr(x, "tzinfo")
    if pyisnone(tzinfo)
        pydel!(tzinfo)
        return false
    end
    utcoffset = tzinfo.utcoffset
    pydel!(tzinfo)
    o = utcoffset(nothing)
    pydel!(utcoffset)
    ans = !pyisnone(o)
    pydel!(o)
    return ans
end

function pydatetime_isaware(x)
    tzinfo = pygetattr(x, "tzinfo")
    if pyisnone(tzinfo)
        pydel!(tzinfo)
        return false
    end
    utcoffset = tzinfo.utcoffset
    pydel!(tzinfo)
    o = utcoffset(x)
    pydel!(utcoffset)
    ans = !pyisnone(o)
    pydel!(o)
    return ans
end

function pyconvert_rule_date(::Type{Date}, x::Py)
    # datetime is a subtype of date, but we shouldn't convert datetime to Date since it's lossy
    pyisinstance(x, pydatetimetype) && return pyconvert_unconverted()
    year = pyconvert_and_del(Int, x.year)
    month = pyconvert_and_del(Int, x.month)
    day = pyconvert_and_del(Int, x.day)
    pyconvert_return(Date(year, month, day))
end

function pyconvert_rule_time(::Type{Time}, x::Py)
    pytime_isaware(x) && return pyconvert_unconverted()
    hour = pyconvert_and_del(Int, x.hour)
    minute = pyconvert_and_del(Int, x.minute)
    second = pyconvert_and_del(Int, x.second)
    microsecond = pyconvert_and_del(Int, x.microsecond)
    return pyconvert_return(Time(hour, minute, second, div(microsecond, 1000), mod(microsecond, 1000)))
end

function pyconvert_rule_datetime(::Type{DateTime}, x::Py)
    pydatetime_isaware(x) && return pyconvert_unconverted()
    # compute the time since 1/1/1
    # this accounts for fold
    d = x - pydatetime111
    days = pyconvert_and_del(Int, d.days)
    seconds = pyconvert_and_del(Int, d.seconds)
    microseconds = pyconvert_and_del(Int, d.microseconds)
    pydel!(d)
    iszero(mod(microseconds, 1000)) || return pyconvert_unconverted()
    return pyconvert_return(DateTime(1,1,1) + Millisecond(div(microseconds, 1000) + 1000 * (seconds + 60 * 60 * 24 * days)))
end


text:
@recipe function plot(pp::PointPattern; window=true)
    if window && pp.window isa NamedTuple{(:x, :y)}
        @series begin
            seriestype := :path
            primary := false
            linecolor := :black
            markershape := :none
            x0, x1 = pp.window.x
            y0, y1 = pp.window.y
            ([x0, x0, x1, x1, x0], [y0, y1, y1, y0, y0])
        end
    end
    seriestype --> :scatter
    markershape --> :+
    markercolor --> :auto
    (getx.(pp.data), gety.(pp.data))
end


text:
#####
##### Functions for non-rotating models
#####

@inline x_f_cross_U(i, j, k, grid::AbstractGrid{T}, ::Nothing, U) where T = zero(T)
@inline y_f_cross_U(i, j, k, grid::AbstractGrid{T}, ::Nothing, U) where T = zero(T)
@inline z_f_cross_U(i, j, k, grid::AbstractGrid{T}, ::Nothing, U) where T = zero(T)

#####
##### The 'FPlane' approximation. This is equivalent to a model with a constant
##### rotation rate around its vertical axis.
#####

"""
    FPlane{T} <: AbstractRotation

A parameter object for constant rotation around a vertical axis.
"""
struct FPlane{T} <: AbstractRotation
    f :: T
end

"""
    FPlane([T=Float64;] f)

Returns a parameter object for constant rotation at the angular frequency
`2f`, and therefore with background vorticity `f`, around a vertical axis.

Also called `FPlane`, after the "f-plane" approximation for the local effect of
Earth's rotation in a planar coordinate system tangent to the Earth's surface.
"""
function FPlane(T=Float64; f)
    return FPlane{T}(f)
end

@inline fv(i, j, k, grid::RegularCartesianGrid{T}, f, v) where T =
    T(0.5) * f * (avgy_f2c(grid, v, i-1,  j, k) + avgy_f2c(grid, v, i, j, k))

@inline fu(i, j, k, grid::RegularCartesianGrid{T}, f, u) where T =
    T(0.5) * f * (avgx_f2c(grid, u, i,  j-1, k) + avgx_f2c(grid, u, i, j, k))

@inline x_f_cross_U(i, j, k, grid, rotation::FPlane, U) = -fv(i, j, k, grid, rotation.f, U.v)
@inline y_f_cross_U(i, j, k, grid, rotation::FPlane, U) =  fu(i, j, k, grid, rotation.f, U.u)
@inline z_f_cross_U(i, j, k, grid::AbstractGrid{T}, ::FPlane, U) where T = zero(T)


text:
println("pid: $(getpid())"); flush(stdout)

using BSON
using Cytof5
include("../cb/PreProcess.jl")

if length(ARGS) == 0
  SEED = 1
  RESULTS_DIR = "results/test/vb-cb-paper/"
  DATA_PATH="../cb/data/cytof_cb_float32.bson"
  K_VB = 30
  BATCHSIZE = 500
  NITERS = 20000
else
  SEED = parse(Int, ARGS[1])
  RESULTS_DIR = ARGS[2]
  DATA_PATH = ARGS[3]
  K_VB = parse(Int, ARGS[4])
  BATCHSIZE = parse(Int, ARGS[5])
  NITERS = 20000
end
mkpath(RESULTS_DIR)

# For BSON
using Flux, Distributions

# Load cb data
y = Matrix{Float64}.(BSON.load(DATA_PATH)[:y])
goodColumns, J = PreProcess.preprocess!(y, maxNanOrNegProp=.9, maxPosProp=.9,
                                        subsample=0.0, rowThresh=-6.0)
Cytof5.Model.logger("good columns: $goodColumns")

# Generate model constnats
c = Cytof5.VB.Constants(y=y, K=K_VB, L=Dict(false=>5, true=>3),
                        yQuantiles=[.0, .25, .5], pBounds=[.05, .8, .05],
                        use_stickbreak=false, tau=.001)
c.priors.eps = Beta(1, 99)
# c.priors.sig2 = LogNormal(log(.3), .2)
# c.priors.sig2 = Gamma(2, 1/20)
c.priors.sig2 = Gamma(.1, 1)

println("seed: $SEED")
# Fit model
out = Cytof5.VB.fit(y=y, niters=NITERS, batchsize=BATCHSIZE, c=c,
                    nsave=30, seed=SEED, flushOutput=true, scale_logqy=.01)

# Save results
out[:y] = Matrix{Float32}.(y)
BSON.bson("$(RESULTS_DIR)/output.bson", out)

# Post process
include("post_process_defs_pyplot.jl")
out = nothing
post_process("$(RESULTS_DIR)/output.bson")


text:
function searchfor(; kwargs...)
    resultjson = requestjson("place/textsearch"; kwargs...)
    if resultjson["status"] == "OK"
        return resultjson["results"]
    else
        return []
    end
end

"""
Returns information about a set of places based on a string — for example
"pizza in New York" or "shoe stores near Ottawa" or "123 Main Street".

https://developers.google.com/places/web-service/search#TextSearchRequests

## Parameters
* `key`: your google maps API key
* `query`: The text string on which to search, for example: "restaurant" or
    "123 Main Street". The Google Places service will return candidate matches
    based on this string and order the results based on their perceived
    relevance. This parameter becomes optional if the type parameter is also
    used in the search request.

## Keyword Arguments
* `location::String`: The latitude/longitude around which to retrieve place
    information. This must be specified as latitude,longitude. If you specify a
    location parameter, you must also specify a `radius` parameter.
* `radius`: The distance (meters) within which to bias place results. The
    maximum allowed radius is 50,000 meters. Results inside of this region will
    be ranked higher than results outside of the search circle; however,
    prominent results from outside of the search radius may be included.
* `opennow`: Returns only those places that are open for business at the time
    the query is sent. Places that do not specify opening hours in the Google
    Places database will not be returned if you include this parameter.
* `pagetoken`: Returns the next 20 results from a previously run search. Setting
    a pagetoken parameter will execute a search with the same parameters used
    previously — all parameters other than pagetoken will be ignored.
* `type`: Restricts the results to places matching the specified type. Only one
    type may be specified (if more than one type is provided, all types
    following the first entry are ignored).

## Remark
The Google Places search services share the same usage limits. However, the Text
Search service is subject to a 10-times multiplier. That is, each Text Search
request that you make will count as 10 requests against your quota.

So you should consider using the `details()` method (where possible) instead.
"""
searchfor(key::String, query::String; kwargs...) =
    searchfor(key=key, query=query; kwargs...)


text:
using Dates
using Test
using HTTP
using HTTP: Headers, URI
using HTTP.AWS4AuthRequest: sign_aws4!

# Based on https://docs.aws.amazon.com/general/latest/gr/signature-v4-test-suite.html

function test_get!(headers, params; opts...)
    sign_aws4!("GET",
               URI("https://example.amazonaws.com/" * params),
               headers,
               UInt8[];
               timestamp=DateTime(2015, 8, 30, 12, 36),
               aws_service="service",
               aws_region="us-east-1",
               # NOTE: These are the example credentials as specified in the AWS docs,
               # they are not real
               aws_access_key_id="AKIDEXAMPLE",
               aws_secret_access_key="wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY",
               include_md5=false,
               include_sha256=false,
               opts...)
    headers
end

function test_auth_string(headers, sig)
    d = [
        "AWS4-HMAC-SHA256 Credential" => "AKIDEXAMPLE/20150830/us-east-1/service/aws4_request",
        "SignedHeaders" => headers,
        "Signature" => sig,
    ]
    join(map(p->join(p, '='), d), ", ")
end

header_keys(headers) = sort!(map(first, headers))

const required_headers = ["Authorization", "host", "x-amz-date"]

@testset "AWS Signature Version 4" begin
    # The signature for requests with no headers where the path ends up as simply /
    slash_only_sig = "5fa00fa31553b73ebf1942676e86291e8372ff2a2260956d9b8aae1d763fbf31"
    noheaders = [
        ("get-vanilla", "", slash_only_sig),
        ("get-vanilla-empty-query-key", "?Param1=value1", "a67d582fa61cc504c4bae71f336f98b97f1ea3c7a6bfe1b6e45aec72011b9aeb"),
        ("get-utf8", "ሴ", "8318018e0b0f223aa2bbf98705b62bb787dc9c0e678f255a891fd03141be5d85"),
        ("get-relative", "example/..", slash_only_sig),
        ("get-relative-relative", "example1/example2/../..", slash_only_sig),
        ("get-slash", "/", slash_only_sig),
        ("get-slash-dot-slash", "./", slash_only_sig),
        ("get-slashes", "example/", "9a624bd73a37c9a373b5312afbebe7a714a789de108f0bdfe846570885f57e84"),
        ("get-slash-pointless-dot", "./example", "ef75d96142cf21edca26f06005da7988e4f8dc83a165a80865db7089db637ec5"),
        ("get-space", "example space/", "652487583200325589f1fba4c7e578f72c47cb61beeca81406b39ddec1366741"),
    ]
    @testset "$name" for (name, p, sig) in noheaders
        headers = test_get!(Headers([]), p)
        @test header_keys(headers) == required_headers
        d = Dict(headers)
        @test d["x-amz-date"] == "20150830T123600Z"
        @test d["host"] == "example.amazonaws.com"
        @test d["Authorization"] == test_auth_string("host;x-amz-date", sig)
    end

    yesheaders = [
        ("get-header-key-duplicate", "",
         Headers(["My-Header1" => "value2",
                  "My-Header1" => "value2",
                  "My-Header1" => "value1"]),
         "host;my-header1;x-amz-date",
         "c9d5ea9f3f72853aea855b47ea873832890dbdd183b4468f858259531a5138ea"),
        ("get-header-value-multiline", "",
         Headers(["My-Header1" => "value1\n  value2\n    value3"]),
         "host;my-header1;x-amz-date",
         "ba17b383a53190154eb5fa66a1b836cc297cc0a3d70a5d00705980573d8ff790"),
        ("get-header-value-order", "",
         Headers(["My-Header1" => "value4",
                  "My-Header1" => "value1",
                  "My-Header1" => "value3",
                  "My-Header1" => "value2"]),
         "host;my-header1;x-amz-date",
         "08c7e5a9acfcfeb3ab6b2185e75ce8b1deb5e634ec47601a50643f830c755c01"),
        ("get-header-value-trim", "",
         Headers(["My-Header1" => " value1",
                  "My-Header2" => " \"a   b   c\""]),
         "host;my-header1;my-header2;x-amz-date",
         "acc3ed3afb60bb290fc8d2dd0098b9911fcaa05412b367055dee359757a9c736"),
    ]
    @testset "$name" for (name, p, h, sh, sig) in yesheaders
        hh = sort(map(first, h))
        test_get!(h, p)
        @test header_keys(h) == sort(vcat(required_headers, hh))
        d = Dict(h) # collapses duplicates but we don't care here
        @test d["x-amz-date"] == "20150830T123600Z"
        @test d["host"] == "example.amazonaws.com"
        @test d["Authorization"] == test_auth_string(sh, sig)
    end
end


text:
using Test, Random
using Knet.KnetArrays: KnetArray, sumabs, sumabs2, minabs, maxabs, countnz, reduction_ops
using LinearAlgebra: norm
using CUDA: CUDA, functional
using AutoGrad: gradcheck
include("combinatorics.jl")

@testset "reduction" begin

    MIN_DIM  = 3
    MAX_DIM  = 5
    MIN_SIZE = 2
    TOL1 = 0.05

    function rand21(f,t,d...)
        if f==maximum || f==minimum || f==norm || f==sumabs2
            reshape(shuffle(t(0.01)*t[1:prod(d...)...]), d...)
            # elseif f==countnz || f==countnz2
            #     t(0.01)+rand(t,d...)
        elseif f==prod
            exp.(t(0.01)*randn(t,d...))
        else
            randn(t,d...)
        end
    end

    ### countnz is deprecated
    # countnz2(a::AbstractArray{T}; dims=:) where {T}=Array{T}(sum(a.!=0,dims=dims))
    # using AutoGrad
    # @zerograd countnz2(a,d...)

    reduction_fns = []
    for f in reduction_ops
        if isa(f,Tuple); f=f[2]; end
        if f == "countnz"; continue; end # deprecated
        push!(reduction_fns, eval(Meta.parse(f)))
    end

    #Knet.seed!(42)

    for f in reduction_fns
        for t in (Float32, Float64)
            for n in (1,(1,1),2,(2,1),(1,2),(2,2))
                #@show f,t,n
                ax = rand21(f,t,n)
                @test gradcheck(f, ax; rtol=TOL1)
                @test gradcheck(f, ax; kw=(:dims=>1,), rtol=TOL1)
                @test gradcheck(f, ax; kw=(:dims=>2,), rtol=TOL1)
                if CUDA.functional()
                    gx = KnetArray(ax)
                    @test gradcheck(f, gx; rtol=TOL1)
                    @test gradcheck(f, gx; kw=(:dims=>1,), rtol=TOL1)
                    @test gradcheck(f, gx; kw=(:dims=>2,), rtol=TOL1)
                    @test isapprox(f(ax),f(gx))
                    @test isapprox(f(ax,dims=1),Array(f(gx,dims=1)))
                    @test isapprox(f(ax,dims=2),Array(f(gx,dims=2)))
                end
            end
            # test for kernel bug with dims > 64K
            # gradcheck difficult to pass on large arrays due to numerical error
            if CUDA.functional()
                for n in ((10,100000),(100000,10))
                    #@show f,t,n
                    ax = rand21(f,t,n)
                    gx = KnetArray(ax)
                    @test isapprox(f(ax),f(gx))
                    @test isapprox(f(ax,dims=1),Array(f(gx,dims=1)))
                    @test isapprox(f(ax,dims=2),Array(f(gx,dims=2)))
                end
            end
        end
    end

    f = norm
    for t in (Float32, Float64)
        for n in (1,(1,1),2,(2,1),(1,2),(2,2))
            ax = rand21(f,t,n)
            for p in (0,1,2,Inf,-Inf,1/pi,-1/pi,0+pi,-pi)
                #@show f,t,n,p
                @test gradcheck(f, ax, p; rtol=TOL1, args=1)
                if CUDA.functional()
                    gx = KnetArray(ax)
                    @test gradcheck(f, gx, p; rtol=TOL1, args=1)
                    @test isapprox(f(ax,p), f(gx,p); rtol=1e-6)
                end
            end
        end
    end

    # countnz is deprecated

    # # 2-arg countnz is missing in base so we write custom tests for countnz
    # f = countnz
    # f2 = countnz2
    # for t in (Float32, Float64)
    #     for n in (1,(1,1),2,(2,1),(1,2),(2,2))
    #         #@show f,t,n
    #         ax = rand21(f,t,n)
    #         @test gradcheck(f, ax; rtol=TOL1)
    #         @test gradcheck(f2, ax; kw=(:dims=>1,), rtol=TOL1)
    #         @test gradcheck(f2, ax; kw=(:dims=>2,), rtol=TOL1)
    #         if CUDA.functional()
    #             gx = KnetArray(ax)
    #             @test gradcheck(f, gx; rtol=TOL1)
    #             @test gradcheck(f, gx; kw=(:dims=>1,), rtol=TOL1)
    #             @test gradcheck(f, gx; kw=(:dims=>2,), rtol=TOL1)
    #             @test isapprox(f(ax),f(gx))
    #             @test isapprox(f2(ax,dims=1),Array(f(gx,dims=1)))
    #             @test isapprox(f2(ax,dims=2),Array(f(gx,dims=2)))
    #         end
    #     end
    # end

    # all kind of reductions
    for f in (sum,) # reduction_fns takes too much time
        for t in (Float32, Float64)
            for dim = MIN_DIM:MAX_DIM
                # xsize = tuple(dim+MIN_SIZE-1:-1:MIN_SIZE...)
                xsize = ntuple(i->2,dim)
                ax = rand21(f,t,xsize)
                gx = nothing

                #@show f,t,dim,xsize
                @test gradcheck(f,ax; rtol=TOL1)
                if CUDA.functional()
                    gx = KnetArray(ax)
                    @test gradcheck(f, gx; rtol=TOL1)
                    @test isapprox(f(ax),f(gx))
                end

                # test all combinations
                for c in mapreduce(i->collect(combinas(1:dim,i)), vcat, 1:dim)
                    #@show f,t,dim,xsize,c
                    @test gradcheck(f, ax; kw=(:dims=>c,), rtol=TOL1)
                    if CUDA.functional() && gx != nothing
                        @test gradcheck(f,gx; kw=(:dims=>c,), rtol=TOL1)
                        @test isapprox(f(ax,dims=c),Array(f(gx,dims=c)))
                    end
                end
            end
        end
    end
end

nothing

# Time	CUBLS32	CUBLS64	KN32	KN64	CPU32	CPU64	AF32	AF64
# sum	-	-	2.90	3.00	1.91	3.50	3.29	4.41
# prod	-	-	2.89	2.99	25.77	36.54	3.49	4.48
# max	3.77	3.88	2.92	3.01	6.25	8.00	3.53	4.43
# min	3.77	3.72	2.92	3.02	6.24	6.43	3.56	4.41
# asum	3.54	3.62	2.89	2.98	1.18	2.31	-	-
# nrmsq	5.45	9.30	2.88	2.98	3.35	3.13	5.51	7.41

# (*) BLK=128, THR=128 does best for kn.
# (*) what is the secret behind the cpu sum?


text:
# [WEBSITE]

supportedArgs(::GLVisualizeBackend) = [
    # :annotation,
    # :axis,
    # :background_color,
    # :color_palette,
    # :fillrange,
    # :fillcolor,
    # :fillalpha,
    # :foreground_color,
    # :group,
    # :label,
    # :layout,
    # :legend,
    # :linecolor,
    # :linestyle,
     :linetype
    #  :seriescolor, :seriesalpha,
    # :linewidth,
    # :linealpha,
    # :markershape,
    # :markercolor,
    # :markersize,
    # :markeralpha,
    # :markerstrokewidth,
    # :markerstrokecolor,
    # :markerstrokestyle,
    # :n,
    # :bins,
    # :nc,
    # :nr,
    # :pos,
    # :smooth,
    # :show,
    # :size,
    # :title,
    # :windowtitle,
    # :x,
    # :xlabel,
    # :xlims,
    # :xticks,
    # :y,
    # :ylabel,
    # :ylims,
    # :yrightlabel,
    # :yticks,
    # :xscale,
    # :yscale,
    # :xflip,
    # :yflip,
    # :z,
    # :tickfont,
    # :guidefont,
    # :legendfont,
    # :grid,
    # :surface
    # :levels,
  ]
supportedAxes(::GLVisualizeBackend) = [:auto, :left]
supportedTypes(::GLVisualizeBackend) = [:surface] #, :path, :scatter ,:steppre, :steppost, :sticks, :heatmap, :hexbin, :hist, :bar, :hline, :vline, :contour]
supportedStyles(::GLVisualizeBackend) = [:auto, :solid] #, :dash, :dot, :dashdot, :dashdotdot]
supportedMarkers(::GLVisualizeBackend) = [:none, :auto, :ellipse] #, :rect, :diamond, :utriangle, :dtriangle, :cross, :xcross, :star5] #vcat(_allMarkers, Shape)
supportedScales(::GLVisualizeBackend) = [:identity] #, :log, :log2, :log10, :asinh, :sqrt]
subplotSupported(::GLVisualizeBackend) = false

# --------------------------------------------------------------------------------------

function _initialize_backend(::GLVisualizeBackend; kw...)
  @eval begin
    import GLVisualize
    export GLVisualize
  end
end

# ---------------------------------------------------------------------------

immutable GLScreenWrapper
    window
end

function _create_plot(pkg::GLVisualizeBackend, d::KW)
  # TODO: create the window/canvas/context that is the plot within the backend (call it `o`)
  # TODO: initialize the plot... title, xlabel, bgcolor, etc

  # TODO: this should be moved to the display method?
  w=GLVisualize.glscreen()
  @async GLVisualize.renderloop(w)
  Plot(GLScreenWrapper(w), pkg, 0, d, KW[])
end

function _add_series(::GLVisualizeBackend, plt::Plot, d::KW)
  # TODO: add one series to the underlying package
  push!(plt.seriesargs, d)
  # TODO: this should be moved to the display method?
  x,y,z=map(Float32,d[:x]), map(Float32,d[:y]), map(Float32,d[:z].surf)
  GLVisualize.view(GLVisualize.visualize((x*ones(y)', ones(x)*y', z), :surface),plt.o.window)
  plt
end

function _add_annotations{X,Y,V}(plt::Plot{GLVisualizeBackend}, anns::AVec{@compat(Tuple{X,Y,V})})
  for ann in anns
    # TODO: add the annotation to the plot
  end
end

# ----------------------------------------------------------------

function _before_update_plot(plt::Plot{GLVisualizeBackend})
end

# TODO: override this to update plot items (title, xlabel, etc) after creation
function _update_plot(plt::Plot{GLVisualizeBackend}, d::KW)
end

function _update_plot_pos_size(plt::AbstractPlot{GLVisualizeBackend}, d::KW)
end

# ----------------------------------------------------------------

# accessors for x/y data

function getxy(plt::Plot{GLVisualizeBackend}, i::Int)
  # TODO:
  # series = plt.o.lines[i]
  # series.x, series.y
  nothing, nothing
end

function setxy!{X,Y}(plt::Plot{GLVisualizeBackend}, xy::Tuple{X,Y}, i::Integer)
  # TODO:
  # series = plt.o.lines[i]
  # series.x, series.y = xy
  plt
end

# ----------------------------------------------------------------

function _create_subplot(subplt::Subplot{GLVisualizeBackend})
  # TODO: build the underlying Subplot object.  this is where you might layout the panes within a GUI window, for example
end

function _expand_limits(lims, plt::Plot{GLVisualizeBackend}, isx::Bool)
  # TODO: call expand limits for each plot data
end

function _remove_axis(plt::Plot{GLVisualizeBackend}, isx::Bool)
  # TODO: if plot is inner subplot, might need to remove ticks or axis labels
end

# ----------------------------------------------------------------

function Base.writemime(io::IO, ::MIME"image/png", plt::AbstractPlot{GLVisualizeBackend})
  # TODO: write a png to io
end

function Base.display(::PlotsDisplay, plt::Plot{GLVisualizeBackend})
  # TODO: display/show the plot

  # NOTE: I think maybe this should be empty?  We can start with the assumption that creating
  #       and adding to a plot will automatically open a window and draw to it, then the display
  #       wouldn't actually need to do anything
end

function Base.display(::PlotsDisplay, plt::Subplot{GLVisualizeBackend})
  # TODO: display/show the subplot
end


text:
function create_chebyshev_polynomial(::Type{PolynomialsUtils}, arg0::jint)
    return jcall(PolynomialsUtils, "createChebyshevPolynomial", PolynomialFunction, (jint,), arg0)
end

function create_hermite_polynomial(::Type{PolynomialsUtils}, arg0::jint)
    return jcall(PolynomialsUtils, "createHermitePolynomial", PolynomialFunction, (jint,), arg0)
end

function create_jacobi_polynomial(::Type{PolynomialsUtils}, arg0::jint, arg1::jint, arg2::jint)
    return jcall(PolynomialsUtils, "createJacobiPolynomial", PolynomialFunction, (jint, jint, jint), arg0, arg1, arg2)
end

function create_laguerre_polynomial(::Type{PolynomialsUtils}, arg0::jint)
    return jcall(PolynomialsUtils, "createLaguerrePolynomial", PolynomialFunction, (jint,), arg0)
end

function create_legendre_polynomial(::Type{PolynomialsUtils}, arg0::jint)
    return jcall(PolynomialsUtils, "createLegendrePolynomial", PolynomialFunction, (jint,), arg0)
end

function shift(::Type{PolynomialsUtils}, arg0::Vector{jdouble}, arg1::jdouble)
    return jcall(PolynomialsUtils, "shift", Vector{jdouble}, (Vector{jdouble}, jdouble), arg0, arg1)
end


text:
module RLToolkit

# Write your package code here.

# Timer for updating
include("timer.jl")

include("replay.jl")
include("sequence_replay.jl")
include("state_buffer.jl")
include("image_replay.jl")

include("update_state.jl")
include("simple_logger.jl")

include("tile_coder.jl")

end


text:
precompile(Tuple{typeof(Parsers.__init__)})
precompile(Tuple{typeof(Base.deepcopy_internal), Base.MPFR.BigFloat, Base.IdDict{Any, Any}})
precompile(Tuple{typeof(Base.Threads.resize_nthreads!), Array{Base.MPFR.BigFloat, 1}, Base.MPFR.BigFloat})
precompile(Tuple{typeof(Compat.Sys.__init__)})
precompile(Tuple{typeof(Base.active_project), Bool})
precompile(Tuple{typeof(Base.load_path_expand), String})
precompile(Tuple{typeof(Base.load_path)})
precompile(Tuple{getfield(Base, Symbol("#675#676")){String}, Base.IOStream})
precompile(Tuple{getfield(Base, Symbol("##open#270")), Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, typeof(Base.open), getfield(Base, Symbol("#675#676")){String}, String})
precompile(Tuple{typeof(Base.project_deps_get), String, String})
precompile(Tuple{typeof(Base.identify_package), String})
precompile(Tuple{typeof(Base.ht_keyindex), Base.Dict{Any, Int64}, Symbol})
precompile(Tuple{getfield(Base, Symbol("#683#684")){Base.UUID, String}, Base.IOStream})
precompile(Tuple{getfield(Base, Symbol("##open#270")), Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}, typeof(Base.open), getfield(Base, Symbol("#683#684")){Base.UUID, String}, String})
precompile(Tuple{typeof(Base.manifest_deps_get), String, Base.PkgId, String})
precompile(Tuple{typeof(Base.identify_package), Base.PkgId, String})
precompile(Tuple{typeof(Base.manifest_uuid_path), String, Base.PkgId})
precompile(Tuple{typeof(Base.locate_package), Base.PkgId})
precompile(Tuple{typeof(Base.stat), Base.Libc.RawFD})
precompile(Tuple{typeof(Base.isvalid_file_crc), Base.IOStream})
precompile(Tuple{typeof(Base.stale_cachefile), String, String})
precompile(Tuple{typeof(Base.register_root_module), Module})
precompile(Tuple{typeof(Base._include_from_serialized), String, Array{Any, 1}})
precompile(Tuple{typeof(Base._tryrequire_from_serialized), Base.PkgId, UInt64, String})
precompile(Tuple{typeof(Base._require_search_from_serialized), Base.PkgId, String})
precompile(Tuple{typeof(Base.compilecache_path), Base.PkgId})
precompile(Tuple{typeof(Base.load_path_setup_code), Bool})
precompile(Tuple{typeof(Base.create_expr_cache), String, String, Array{Base.Pair{Base.PkgId, UInt64}, 1}, Nothing})
precompile(Tuple{typeof(Base.compilecache), Base.PkgId, String})
precompile(Tuple{typeof(Base._tryrequire_from_serialized), Base.PkgId, UInt64, Nothing})
precompile(Tuple{typeof(Base._require_from_serialized), String})
precompile(Tuple{typeof(Base._require), Base.PkgId})
precompile(Tuple{typeof(Base.require), Base.PkgId})
precompile(Tuple{typeof(Base.require), Module, Symbol})
precompile(Tuple{typeof(Base.setindex!), Base.IdDict{Module, Base.PkgId}, Any, Any})
precompile(Tuple{typeof(Base.isassigned), Core.SimpleVector, Int64})
precompile(Tuple{typeof(Base.Docs.docerror), Any})
precompile(Tuple{typeof(Base.Docs.docm), LineNumberNode, Module, Any, Any, Bool})
precompile(Tuple{typeof(Base.Docs.docm), LineNumberNode, Module, Any, Any})
precompile(Tuple{typeof(Base.Docs.splitexpr), Expr})
precompile(Tuple{typeof(Base.Docs.bindingexpr), Any})
precompile(Tuple{typeof(Base.Docs.objectdoc), Any, Any, Any, Any, Any, Any})
precompile(Tuple{typeof(Base.Docs.docstr), Any, Any})
precompile(Tuple{typeof(Base.Docs._docstr), Core.SimpleVector, Any})
precompile(Tuple{typeof(Base.:(==)), Module, WeakRef})
precompile(Tuple{typeof(Base.Docs.doc!), Module, Base.Docs.Binding, Base.Docs.DocStr, Any})
precompile(Tuple{getfield(Base, Symbol("#@r_str")), LineNumberNode, Module, Any, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base.print_to_string), Expr})
precompile(Tuple{typeof(Base.string), Expr})
precompile(Tuple{typeof(Base.show_unquoted_expr_fallback), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, Expr, Int64, Int64})
precompile(Tuple{typeof(Base.show_list), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, Array{Any, 1}, String, Int64, Int64, Int64, Bool, Bool})
precompile(Tuple{typeof(Base.show_list), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, Array{Any, 1}, Symbol, Int64, Int64, Int64, Bool, Bool})
precompile(Tuple{typeof(Base.show_enclosed_list), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, String, Array{Any, 1}, String, String, Int64, Int64, Int64, Bool, Bool})
precompile(Tuple{typeof(Base.show_generator), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, Expr, Int64, Int64})
precompile(Tuple{typeof(Base.show_list), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, Array{Any, 1}, Char, Int64, Int64, Int64, Bool, Bool})
precompile(Tuple{typeof(Base.show_block), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, String, Array{Any, 1}, Expr, Int64, Int64})
precompile(Tuple{typeof(Base.show_unquoted), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, Expr, Int64, Int64, Int64})
precompile(Tuple{typeof(Base.show_unquoted), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, Expr, Int64, Int64})
precompile(Tuple{typeof(Base.show_call), Base.IOContext{Base.GenericIOBuffer{Array{UInt8, 1}}}, Symbol, Symbol, Array{Any, 1}, Int64, Int64, Bool})
precompile(Tuple{getfield(Dates, Symbol("#@dateformat_str")), LineNumberNode, Module, Any})
precompile(Tuple{Type{Dates.DateFormat{Symbol("m/dd/yy"), Tuple{Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x79000000)}}}}, Tuple{Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x79000000)}}, Dates.DateLocale})
precompile(Tuple{Type{Dates.DatePart{Char(0x49000000)}}, Int64, Bool})
precompile(Tuple{Type{Dates.DatePart{Char(0x70000000)}}, Int64, Bool})
precompile(Tuple{Type{Dates.DateFormat{Symbol("II:MMpp"), Tuple{Dates.DatePart{Char(0x49000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x4d000000)}, Dates.DatePart{Char(0x70000000)}}}}, Tuple{Dates.DatePart{Char(0x49000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x4d000000)}, Dates.DatePart{Char(0x70000000)}}, Dates.DateLocale})
precompile(Tuple{getfield(Base, Symbol("#@ccallable")), LineNumberNode, Module, Any})
precompile(Tuple{typeof(Base.expand_ccallable), Nothing, Expr})
precompile(Tuple{getfield(Base.Cartesian, Symbol("#@nexprs")), LineNumberNode, Module, Int64, Expr})
precompile(Tuple{typeof(Base.Cartesian.exprresolve_arith), Expr})
precompile(Tuple{typeof(Base.Cartesian.exprresolve_conditional), Expr})
precompile(Tuple{typeof(Base.Cartesian.exprresolve), Expr})
precompile(Tuple{typeof(Base.Cartesian.inlineanonymous), Expr, Int64})
precompile(Tuple{typeof(Base.Cartesian.lreplace!), Expr, Base.Cartesian.LReplace{String}})
precompile(Tuple{typeof(Base.Cartesian.lreplace), Expr, Symbol, Int64})
precompile(Tuple{getfield(Base.Cartesian, Symbol("#@ncall")), LineNumberNode, Module, Int64, Any, Vararg{Any, N} where N})
precompile(Tuple{getfield(Base.Cartesian, Symbol("#@nloops")), LineNumberNode, Module, Any, Any, Any, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base.Cartesian._nloops), Int64, Symbol, Expr, Expr})
precompile(Tuple{typeof(Base.map), Function, Array{Any, 1}})
precompile(Tuple{Type{Base.Generator{I, F} where F where I}, getfield(Base, Symbol("#267#268")), Array{Any, 1}})
precompile(Tuple{typeof(Base._collect), Array{Any, 1}, Base.Generator{Array{Any, 1}, getfield(Base, Symbol("#267#268"))}, Base.EltypeUnknown, Base.HasShape{1}})
precompile(Tuple{typeof(Base.collect_similar), Array{Any, 1}, Base.Generator{Array{Any, 1}, getfield(Base, Symbol("#267#268"))}})
precompile(Tuple{typeof(Base.ccallable), Function, Type{T} where T, Type{T} where T, String})
precompile(Tuple{getfield(Base, Symbol("##catch_stack#49")), Bool, typeof(Base.catch_stack), Task})
precompile(Tuple{typeof(SmallParser.julia_main)})
precompile(Tuple{typeof(Dates.character_codes), Core.SimpleVector})
precompile(Tuple{getfield(Dates, Symbol("##s661#35")), Any, Any, Any, Any, Any, Any, Any, Any})
precompile(Tuple{typeof(Dates.character_codes), Type{Dates.DateFormat{Symbol("m/dd/yy"), Tuple{Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x79000000)}}}}})
precompile(Tuple{typeof(Base.first), Core.SimpleVector})
precompile(Tuple{typeof(Dates.genvar), DataType})
precompile(Tuple{Type{Base.IteratorSize}, Tuple{DataType, DataType, DataType}})
precompile(Tuple{typeof(Base._array_for), Type{Symbol}, Tuple{DataType, DataType, DataType}, Base.HasLength})
precompile(Tuple{Type{Base.LinearIndices{N, R} where R<:Tuple{Vararg{Base.AbstractUnitRange{Int64}, N}} where N}, Array{Symbol, 1}})
precompile(Tuple{Type{Base.Generator{I, F} where F where I}, getfield(Dates, Symbol("#36#37")), Tuple{DataType, DataType, DataType}})
precompile(Tuple{typeof(Base.collect), Base.Generator{Tuple{DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}})
precompile(Tuple{Type{Tuple}, Base.Generator{Tuple{DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}})
precompile(Tuple{typeof(Base._array_for), Type{Int64}, Tuple{DataType, DataType, DataType}, Base.HasLength})
precompile(Tuple{typeof(Base.collect_to!), Array{Int64, 1}, Base.Generator{Tuple{DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}, Int64, Int64})
precompile(Tuple{typeof(Base.collect_to_with_first!), Array{Int64, 1}, Int64, Base.Generator{Tuple{DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}, Int64})
precompile(Tuple{typeof(Base.Iterators.zip), Array{Symbol, 1}, Tuple{Int64, Int64, Int64}})
precompile(Tuple{Type{Base.IteratorSize}, Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64}}}})
precompile(Tuple{typeof(Base._array_for), Type{Expr}, Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64}}}, Base.HasLength})
precompile(Tuple{Type{Base.LinearIndices{N, R} where R<:Tuple{Vararg{Base.AbstractUnitRange{Int64}, N}} where N}, Array{Expr, 1}})
precompile(Tuple{typeof(Base.map), getfield(Base.Iterators, Symbol("#3#4")), Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64}}})
precompile(Tuple{typeof(Base.Iterators._zip_iterate_all), Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64}}, Tuple{Tuple{}, Tuple{}}})
precompile(Tuple{typeof(Base.iterate), Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64}}}, Tuple{Int64, Int64}})
precompile(Tuple{typeof(Base.collect), Base.Generator{Array{Type, 1}, getfield(Dates, Symbol("#33#34"))}})
precompile(Tuple{getfield(Dates, Symbol("##s662#32")), Any, Any, Any, Any, Any, Any})
precompile(Tuple{typeof(Dates._directives), Type{Dates.DateFormat{Symbol("m/dd/yy"), Tuple{Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x79000000)}}}}})
precompile(Tuple{typeof(Base._array_for), Type{Int64}, Array{Type, 1}, Base.HasShape{1}})
precompile(Tuple{typeof(Base.collect_to!), Array{Int64, 1}, Base.Generator{Array{Type, 1}, getfield(Dates, Symbol("#33#34"))}, Int64, Int64})
precompile(Tuple{typeof(Base.collect_to_with_first!), Array{Int64, 1}, Int64, Base.Generator{Array{Type, 1}, getfield(Dates, Symbol("#33#34"))}, Int64})
precompile(Tuple{typeof(Dates.character_codes), Type{Dates.DateFormat{Symbol("II:MMpp"), Tuple{Dates.DatePart{Char(0x49000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x4d000000)}, Dates.DatePart{Char(0x70000000)}}}}})
precompile(Tuple{Type{Base.IteratorSize}, Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}})
precompile(Tuple{typeof(Base._array_for), Type{Symbol}, Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}, Base.HasLength})
precompile(Tuple{Type{Base.Generator{I, F} where F where I}, getfield(Dates, Symbol("#36#37")), Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}})
precompile(Tuple{typeof(Base.collect), Base.Generator{Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}})
precompile(Tuple{Type{Tuple}, Base.Generator{Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}})
precompile(Tuple{typeof(Base._array_for), Type{Int64}, Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}, Base.HasLength})
precompile(Tuple{typeof(Base.collect_to!), Array{Int64, 1}, Base.Generator{Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}, Int64, Int64})
precompile(Tuple{typeof(Base.collect_to_with_first!), Array{Int64, 1}, Int64, Base.Generator{Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}, Int64})
precompile(Tuple{typeof(Base.copyto!), Array{Any, 1}, Int64, Array{Int64, 1}, Int64, Int64})
precompile(Tuple{typeof(Base.setindex_widen_up_to), Array{Int64, 1}, Dates.AMPM, Int64})
precompile(Tuple{typeof(Base.collect_to!), Array{Any, 1}, Base.Generator{Tuple{DataType, DataType, DataType, DataType, DataType, DataType, DataType}, getfield(Dates, Symbol("#36#37"))}, Int64, Int64})
precompile(Tuple{typeof(Base.Iterators.zip), Array{Symbol, 1}, Tuple{Int64, Int64, Int64, Int64, Int64, Int64, Dates.AMPM}})
precompile(Tuple{Type{Base.IteratorSize}, Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64, Int64, Int64, Int64, Dates.AMPM}}}})
precompile(Tuple{typeof(Base._array_for), Type{Expr}, Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64, Int64, Int64, Int64, Dates.AMPM}}}, Base.HasLength})
precompile(Tuple{typeof(Base.map), getfield(Base.Iterators, Symbol("#3#4")), Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64, Int64, Int64, Int64, Dates.AMPM}}})
precompile(Tuple{typeof(Base.Iterators._zip_iterate_all), Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64, Int64, Int64, Int64, Dates.AMPM}}, Tuple{Tuple{}, Tuple{}}})
precompile(Tuple{typeof(Base.iterate), Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Int64, Int64, Int64, Int64, Dates.AMPM}}}, Tuple{Int64, Int64}})
precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Symbol, Dates.AMPM}, Int64})
precompile(Tuple{typeof(Base.indexed_iterate), Tuple{Symbol, Dates.AMPM}, Int64, Int64})
precompile(Tuple{typeof(Dates._directives), Type{Dates.DateFormat{Symbol("II:MMpp"), Tuple{Dates.DatePart{Char(0x49000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x4d000000)}, Dates.DatePart{Char(0x70000000)}}}}})
precompile(Tuple{typeof(Base.collect_to!), Array{Any, 1}, Base.Generator{Array{Type, 1}, getfield(Dates, Symbol("#33#34"))}, Int64, Int64})
precompile(Tuple{typeof(Base.Iterators.zip), Array{Symbol, 1}, Tuple{Int64, Int64, Dates.AMPM}})
precompile(Tuple{typeof(Base.map), getfield(Base.Iterators, Symbol("#3#4")), Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Dates.AMPM}}})
precompile(Tuple{typeof(Base.Iterators._zip_iterate_all), Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Dates.AMPM}}, Tuple{Tuple{}, Tuple{}}})
precompile(Tuple{typeof(Base.iterate), Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Tuple{Int64, Int64, Dates.AMPM}}}, Tuple{Int64, Int64}})
precompile(Tuple{typeof(Base.allocatedinline), Type{AbstractArray{T, 1} where T}})
precompile(Tuple{Type{Base.Val{x} where x}, Bool})
precompile(Tuple{Type{Base.Val{true}}})
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{Base.OneTo{Int64}, 1}}})
precompile(Tuple{Type{Core.Compiler.Signature}, Base.BottomRF{typeof(Base.GMP.MPZ.add!)}, Core.Compiler.Const, Array{Any, 1}, Type{T} where T})
precompile(Tuple{typeof(Base.throw_boundserror), Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, typeof(Base.join), Tuple{Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.split), Tuple{Base.Broadcast.Extruded{Array{String, 1}, Tuple{Bool}, Tuple{Int64}}, Base.RefValue{String}}}, Base.RefValue{String}}}, Tuple{Int64}})
precompile(Tuple{getfield(SmallParser, Symbol("#3#4")), String})
precompile(Tuple{typeof(Base.collect_to_with_first!), Array{String, 1}, String, Base.Generator{Array{String, 1}, getfield(SmallParser, Symbol("#3#4"))}, Int64})
precompile(Tuple{typeof(Base._collect), Array{String, 1}, Base.Generator{Array{String, 1}, getfield(SmallParser, Symbol("#3#4"))}, Base.EltypeUnknown, Base.HasShape{1}})
precompile(Tuple{typeof(SmallParser.process_broken_file), Array{String, 1}})
precompile(Tuple{typeof(Base.filter), getfield(SmallParser, Symbol("#1#2")), Array{String, 1}})
precompile(Tuple{typeof(Base.throw_boundserror), Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, typeof(Base.split), Tuple{Base.Broadcast.Extruded{Array{String, 1}, Tuple{Bool}, Tuple{Int64}}}}, Tuple{Int64}})
precompile(Tuple{typeof(SmallParser.process_file), String})
precompile(Tuple{typeof(Base.endswith), String, Base.SubString{String}})
precompile(Tuple{typeof(SmallParser.process_lines), Array{Array{Base.SubString{String}, 1}, 1}})
precompile(Tuple{typeof(Dates.yearmonthday), Int64})
precompile(Tuple{typeof(Base.throw_boundserror), Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, typeof(Base.:(+)), Tuple{Base.RefValue{Dates.Year}, Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, Type{Dates.Date}, Tuple{Base.Broadcast.Extruded{Array{Any, 1}, Tuple{Bool}, Tuple{Int64}}, Base.RefValue{Dates.DateFormat{Symbol("m/dd/yy"), Tuple{Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x79000000)}}}}}}}}, Tuple{Int64}})
precompile(Tuple{typeof(Base.collect_to!), Array{Dates.Time, 1}, Base.Generator{Array{Any, 1}, getfield(SmallParser, Symbol("#7#9"))}, Int64, Int64})
precompile(Tuple{typeof(Base.collect), Base.Generator{Array{Any, 1}, getfield(SmallParser, Symbol("#7#9"))}})
precompile(Tuple{typeof(Base.collect_to!), Array{Dates.Time, 1}, Base.Generator{Array{Any, 1}, getfield(SmallParser, Symbol("#8#10"))}, Int64, Int64})
precompile(Tuple{typeof(Base.collect), Base.Generator{Array{Any, 1}, getfield(SmallParser, Symbol("#8#10"))}})
precompile(Tuple{typeof(Dates.divexact), Int64, Int64})
precompile(Tuple{typeof(Base.throw_boundserror), Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, Type{Dates.Minute}, Tuple{Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Base.:(-)), Tuple{Base.Broadcast.Extruded{Array{Dates.Time, 1}, Tuple{Bool}, Tuple{Int64}}, Base.Broadcast.Extruded{Array{Dates.Time, 1}, Tuple{Bool}, Tuple{Int64}}}}}}, Tuple{Int64}})
precompile(Tuple{typeof(SmallParser.fix_datetimes), Array{Any, 1}, Array{Any, 1}, Array{Any, 1}})
precompile(Tuple{typeof(Base.ht_keyindex), Base.Dict{Symbol, Int64}, Symbol})
precompile(Tuple{typeof(Base.map), typeof(Base.Unicode.uppercase), String})
precompile(Tuple{typeof(Base.collect_to!), Array{Tuple{Int64, Symbol}, 1}, Base.Generator{Base.KeySet{Symbol, Base.Dict{Symbol, Int64}}, getfield(DataFrames, Symbol("#15#20")){String}}, Int64, Int64})
precompile(Tuple{typeof(Base.collect), Base.Generator{Base.KeySet{Symbol, Base.Dict{Symbol, Int64}}, getfield(DataFrames, Symbol("#15#20")){String}}})
precompile(Tuple{typeof(Base.sort!), Array{Tuple{Int64, Symbol}, 1}, Int64, Int64, Base.Sort.InsertionSortAlg, Base.Order.ForwardOrdering})
precompile(Tuple{typeof(Base.sort!), Array{Tuple{Int64, Symbol}, 1}, Int64, Int64, Base.Sort.MergeSortAlg, Base.Order.ForwardOrdering, Array{Tuple{Int64, Symbol}, 1}})
precompile(Tuple{typeof(Base.collect_to!), Array{Int64, 1}, Base.Generator{Base.UnitRange{Int64}, getfield(DataFrames, Symbol("#16#21")){Array{Tuple{Int64, Symbol}, 1}}}, Int64, Int64})
precompile(Tuple{typeof(Base.collect), Base.Generator{Base.UnitRange{Int64}, getfield(DataFrames, Symbol("#16#21")){Array{Tuple{Int64, Symbol}, 1}}}})
precompile(Tuple{typeof(Base.grow_to!), Array{Symbol, 1}, Base.Generator{Base.Iterators.Filter{getfield(DataFrames, Symbol("#19#24")){Int64}, Array{Tuple{Int64, Symbol}, 1}}, getfield(DataFrames, Symbol("#18#23"))}, Int64})
precompile(Tuple{typeof(Base.grow_to!), Array{Symbol, 1}, Base.Generator{Base.Iterators.Filter{getfield(DataFrames, Symbol("#19#24")){Int64}, Array{Tuple{Int64, Symbol}, 1}}, getfield(DataFrames, Symbol("#18#23"))}})
precompile(Tuple{typeof(DataFrames.fuzzymatch), Base.Dict{Symbol, Int64}, Symbol})
precompile(Tuple{typeof(Base.throw_boundserror), Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, typeof(Base.string), Tuple{Base.Broadcast.Extruded{Array{Char, 0}, Tuple{}, Tuple{}}, Base.Broadcast.Extruded{Array{Symbol, 1}, Tuple{Bool}, Tuple{Int64}}}}, Tuple{Int64}})
precompile(Tuple{typeof(Base.getindex), DataFrames.DataFrame, typeof(Base.:(!)), Symbol})
precompile(Tuple{typeof(SmallParser.summary_statistics), DataFrames.DataFrame})
precompile(Tuple{typeof(SmallParser.real_main)})
precompile(Tuple{typeof(Dates.tryparsenext_core), Base.SubString{String}, Int64, Int64, Dates.DateFormat{Symbol("m/dd/yy"), Tuple{Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x79000000)}}}, Bool})
precompile(Tuple{Type{Dates.Date}, Base.SubString{String}, Dates.DateFormat{Symbol("m/dd/yy"), Tuple{Dates.DatePart{Char(0x6d000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x64000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x79000000)}}}})
precompile(Tuple{typeof(Base.endswith), Base.SubString{String}, Base.Regex})
precompile(Tuple{typeof(Base.startswith), Base.SubString{String}, Base.Regex})
precompile(Tuple{typeof(Base._cat), Int64, String, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base.promote_eltypeof), String, Base.SubString{String}})
precompile(Tuple{getfield(Base, Symbol("#cat_t##kw")), NamedTuple{(:dims,), Tuple{Int64}}, typeof(Base.cat_t), Type{AbstractString}, String, Vararg{Any, N} where N})
precompile(Tuple{getfield(Base, Symbol("##cat_t#109")), Int64, typeof(Base.cat_t), Type{AbstractString}, String, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base._cat_t), Int64, Type, String, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base.map), typeof(Base.cat_size), Tuple{String, Base.SubString{String}}})
precompile(Tuple{typeof(Base.cat_similar), String, Type{T} where T, Tuple{Int64}})
precompile(Tuple{Type{Array{AbstractString, N} where N}, UndefInitializer, Tuple{Int64}})
precompile(Tuple{typeof(Base.__cat), Array{AbstractString, 1}, Tuple{Int64}, Tuple{Bool}, String, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base.cat_indices), String, Int64})
precompile(Tuple{typeof(Base.cat_size), String, Int64})
precompile(Tuple{typeof(Base.__subarray_throw_boundserror), Type{Base.SubArray{AbstractString, 1, Array{AbstractString, 1}, Tuple{Base.UnitRange{Int64}}, true}}, Array{AbstractString, 1}, Tuple{Base.UnitRange{Int64}}, Int64, Int64, Tuple{Int64}})
precompile(Tuple{typeof(Base.fill!), Base.SubArray{AbstractString, 1, Array{AbstractString, 1}, Tuple{Base.UnitRange{Int64}}, true}, String})
precompile(Tuple{typeof(Base.cat_indices), Base.SubString{String}, Int64})
precompile(Tuple{typeof(Base.cat_size), Base.SubString{String}, Int64})
precompile(Tuple{typeof(Base.fill!), Base.SubArray{AbstractString, 1, Array{AbstractString, 1}, Tuple{Base.UnitRange{Int64}}, true}, Base.SubString{String}})
precompile(Tuple{typeof(Base.join), Array{AbstractString, 1}, String})
precompile(Tuple{getfield(Base, Symbol("##sprint#338")), Nothing, Int64, typeof(Base.sprint), Function, Array{AbstractString, 1}, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base.join), Base.GenericIOBuffer{Array{UInt8, 1}}, Array{AbstractString, 1}, String})
precompile(Tuple{typeof(Base.split), Base.SubString{String}, String})
precompile(Tuple{getfield(Base, Symbol("#cat##kw")), NamedTuple{(:dims,), Tuple{Int64}}, typeof(Base.cat), Base.SubString{String}, Vararg{Any, N} where N})
precompile(Tuple{getfield(Base, Symbol("##cat#110")), Int64, typeof(Base.cat), Base.SubString{String}, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base._cat), Int64, Base.SubString{String}, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base.promote_eltypeof), Base.SubString{String}, String})
precompile(Tuple{getfield(Base, Symbol("#cat_t##kw")), NamedTuple{(:dims,), Tuple{Int64}}, typeof(Base.cat_t), Type{AbstractString}, Base.SubString{String}, Vararg{Any, N} where N})
precompile(Tuple{getfield(Base, Symbol("##cat_t#109")), Int64, typeof(Base.cat_t), Type{AbstractString}, Base.SubString{String}, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base._cat_t), Int64, Type, Base.SubString{String}, Vararg{Any, N} where N})
precompile(Tuple{typeof(Base.map), typeof(Base.cat_size), Tuple{Base.SubString{String}, String}})
precompile(Tuple{typeof(Base.cat_similar), Base.SubString{String}, Type{T} where T, Tuple{Int64}})
precompile(Tuple{typeof(Base.__cat), Array{AbstractString, 1}, Tuple{Int64}, Tuple{Bool}, Base.SubString{String}, Vararg{Any, N} where N})
precompile(Tuple{typeof(Dates.tryparsenext), Dates.DatePart{Char(0x70000000)}, String, Int64, Int64})
precompile(Tuple{typeof(Dates.tryparsenext_core), String, Int64, Int64, Dates.DateFormat{Symbol("II:MMpp"), Tuple{Dates.DatePart{Char(0x49000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x4d000000)}, Dates.DatePart{Char(0x70000000)}}}, Bool})
precompile(Tuple{typeof(Dates.validargs), Type{Dates.Time}, Int64, Int64, Int64, Int64, Int64, Int64, Dates.AMPM})
precompile(Tuple{Type{Dates.Time}, Int64, Int64, Int64, Int64, Int64, Int64, Dates.AMPM})
precompile(Tuple{getfield(SmallParser, Symbol("#7#9")), String})
precompile(Tuple{typeof(Dates.tryparsenext), Dates.DatePart{Char(0x70000000)}, Base.SubString{String}, Int64, Int64})
precompile(Tuple{typeof(Dates.tryparsenext_core), Base.SubString{String}, Int64, Int64, Dates.DateFormat{Symbol("II:MMpp"), Tuple{Dates.DatePart{Char(0x49000000)}, Dates.Delim{Char, 1}, Dates.DatePart{Char(0x4d000000)}, Dates.DatePart{Char(0x70000000)}}}, Bool})
precompile(Tuple{getfield(SmallParser, Symbol("#7#9")), Base.SubString{String}})
precompile(Tuple{getfield(SmallParser, Symbol("#8#10")), Base.SubString{String}})
precompile(Tuple{getfield(SmallParser, Symbol("#8#10")), String})
precompile(Tuple{Type{Base.Dict{Symbol, Int64}}})
precompile(Tuple{typeof(Base.collect), Base.Generator{Array{Any, 1}, getfield(DataFrames, Symbol("#94#97"))}})
precompile(Tuple{typeof(Base.throw_boundserror), Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, typeof(Base.string), Tuple{Base.Broadcast.Extruded{Array{Symbol, 1}, Tuple{Bool}, Tuple{Int64}}}}, Tuple{Int64}})
precompile(Tuple{Type{Base.DimensionMismatch}, Nothing})
precompile(Tuple{typeof(Base.throw_boundserror), Array{AbstractArray{T, 1} where T, 1}, Tuple{Base.OneTo{Int64}}})
precompile(Tuple{typeof(Base.copyto!), Array{AbstractArray{T, 1} where T, 1}, Array{Any, 1}})
precompile(Tuple{getfield(DataFrames, Symbol("#DataFrame#93#96")), Bool, Type{DataFrames.DataFrame}, Array{Any, 1}, DataFrames.Index})
precompile(Tuple{getfield(DataFrames, Symbol("##DataFrame#100")), Bool, Bool, Type{DataFrames.DataFrame}, Base.Pair{Symbol, Array{Dates.Date, 1}}, Vararg{Base.Pair{Symbol, #s34} where #s34, N} where N})
precompile(Tuple{Type{Base.Generator{I, F} where F where I}, getfield(DataFrames, Symbol("#101#102")), Tuple{Base.Pair{Symbol, Array{Dates.Date, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Minute, 1}}, Base.Pair{Symbol, Array{Any, 1}}}})
precompile(Tuple{typeof(Base.collect), Base.Generator{Tuple{Base.Pair{Symbol, Array{Dates.Date, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Minute, 1}}, Base.Pair{Symbol, Array{Any, 1}}}, getfield(DataFrames, Symbol("#101#102"))}})
precompile(Tuple{getfield(DataFrames, Symbol("#101#102")), Base.Pair{Symbol, Array{Dates.Date, 1}}})
precompile(Tuple{typeof(Base._array_for), Type{Symbol}, Tuple{Base.Pair{Symbol, Array{Dates.Date, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Minute, 1}}, Base.Pair{Symbol, Array{Any, 1}}}, Base.HasLength})
precompile(Tuple{typeof(Base.collect_to!), Array{Symbol, 1}, Base.Generator{Tuple{Base.Pair{Symbol, Array{Dates.Date, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Minute, 1}}, Base.Pair{Symbol, Array{Any, 1}}}, getfield(DataFrames, Symbol("#101#102"))}, Int64, Int64})
precompile(Tuple{typeof(Base.collect_to_with_first!), Array{Symbol, 1}, Symbol, Base.Generator{Tuple{Base.Pair{Symbol, Array{Dates.Date, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Time, 1}}, Base.Pair{Symbol, Array{Dates.Minute, 1}}, Base.Pair{Symbol, Array{Any, 1}}}, getfield(DataFrames, Symbol("#101#102"))}, Int64})
precompile(Tuple{getfield(DataFrames, Symbol("#101#102")), Base.Pair{Symbol, Array{Dates.Time, 1}}})
precompile(Tuple{getfield(DataFrames, Symbol("#101#102")), Base.Pair{Symbol, Array{Dates.Minute, 1}}})
precompile(Tuple{getfield(DataFrames, Symbol("#101#102")), Base.Pair{Symbol, Array{Any, 1}}})
precompile(Tuple{typeof(Base.throw_checksize_error), Array{Symbol, 1}, Tuple{Base.OneTo{Int64}}})
precompile(Tuple{typeof(Base._unsafe_getindex), Base.IndexLinear, Array{Symbol, 1}, Array{Int64, 1}})
precompile(Tuple{typeof(Base.throw_boundserror), Array{Symbol, 1}, Tuple{Array{Int64, 1}}})
precompile(Tuple{getfield(DataFrames, Symbol("##make_unique!#1")), Bool, typeof(DataFrames.make_unique!), Array{Symbol, 1}, Array{Symbol, 1}})
precompile(Tuple{typeof(Base.rehash!), Base.Dict{Symbol, Int64}, Int64})
precompile(Tuple{typeof(Base.ht_keyindex2!), Base.Dict{Symbol, Int64}, Symbol})
precompile(Tuple{typeof(Base.setindex!), Base.Dict{Symbol, Int64}, Int64, Symbol})
precompile(Tuple{Type{Base.Dict{Symbol, Int64}}, Base.Iterators.Zip{Tuple{Array{Symbol, 1}, Base.UnitRange{Int64}}}})
precompile(Tuple{getfield(Core, Symbol("#Type##kw")), NamedTuple{(:makeunique,), Tuple{Bool}}, Type{DataFrames.Index}, Array{Symbol, 1}})
precompile(Tuple{getfield(DataFrames, Symbol("#94#97")), Array{Dates.Date, 1}})
precompile(Tuple{typeof(Base._array_for), Type{Int64}, Array{Any, 1}, Base.HasShape{1}})
precompile(Tuple{typeof(Base.collect_to!), Array{Int64, 1}, Base.Generator{Array{Any, 1}, getfield(DataFrames, Symbol("#94#97"))}, Int64, Int64})
precompile(Tuple{typeof(Base.collect_to_with_first!), Array{Int64, 1}, Int64, Base.Generator{Array{Any, 1}, getfield(DataFrames, Symbol("#94#97"))}, Int64})
precompile(Tuple{getfield(DataFrames, Symbol("#94#97")), Array{Dates.Time, 1}})
precompile(Tuple{getfield(DataFrames, Symbol("#94#97")), Array{Dates.Minute, 1}})
precompile(Tuple{getfield(DataFrames, Symbol("#94#97")), Array{Any, 1}})
precompile(Tuple{typeof(Base.extrema), Array{Int64, 1}})
precompile(Tuple{typeof(Base.copy), Array{Dates.Date, 1}})
precompile(Tuple{typeof(Base.copy), Array{Dates.Time, 1}})
precompile(Tuple{typeof(Base.copy), Array{Dates.Minute, 1}})
precompile(Tuple{typeof(Base.setindex!), Array{AbstractArray{T, 1} where T, 1}, Array{Dates.Date, 1}, Int64})
precompile(Tuple{typeof(Base.setindex!), Array{AbstractArray{T, 1} where T, 1}, Array{Dates.Time, 1}, Int64})
precompile(Tuple{typeof(Base.setindex!), Array{AbstractArray{T, 1} where T, 1}, Array{Dates.Minute, 1}, Int64})
precompile(Tuple{typeof(Base.setindex!), Array{AbstractArray{T, 1} where T, 1}, Array{Any, 1}, Int64})
precompile(Tuple{typeof(Base.mapreduce_impl), typeof(Base.identity), typeof(Base.add_sum), Array{Dates.Minute, 1}, Int64, Int64, Int64})
precompile(Tuple{typeof(Base.sum), Array{Dates.Minute, 1}})
precompile(Tuple{typeof(Base.string), String, Dates.Minute})
precompile(Tuple{typeof(Base.print), Base.GenericIOBuffer{Array{UInt8, 1}}, Dates.Minute})
precompile(Tuple{typeof(Base.println), Base.TTY, String})
precompile(Tuple{typeof(Base._reformat_bt), Array{Ptr{Nothing}, 1}, Array{Any, 1}})
precompile(Tuple{typeof(Base.catch_backtrace)})
precompile(Tuple{typeof(Distributed.flush_gc_msgs)})
precompile(Tuple{getfield(Distributed, Symbol("#131#132"))})
precompile(Tuple{typeof(Base.Broadcast.combine_styles), Array{Dates.Minute, 1}})
precompile(Tuple{typeof(Base.Broadcast.broadcasted), Base.Broadcast.DefaultArrayStyle{1}, Function, Array{Dates.Minute, 1}})
precompile(Tuple{Type{Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Axes, F, Args} where Args<:Tuple where F where Axes}, typeof(Dates.value), Tuple{Array{Dates.Minute, 1}}})
precompile(Tuple{typeof(Base.Broadcast.instantiate), Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(Dates.value), Tuple{Array{Dates.Minute, 1}}}})
precompile(Tuple{typeof(Base.throw_boundserror), Base.Broadcast.Broadcasted{Nothing, Tuple{Base.OneTo{Int64}}, typeof(Dates.value), Tuple{Base.Broadcast.Extruded{Array{Dates.Minute, 1}, Tuple{Bool}, Tuple{Int64}}}}, Tuple{Int64}})
precompile(Tuple{typeof(Base.copy), Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Tuple{Base.OneTo{Int64}}, typeof(Dates.value), Tuple{Array{Dates.Minute, 1}}}})
precompile(Tuple{typeof(Core.Compiler.eltype), Type{Array{Float64, 1}}})
precompile(Tuple{typeof(DataAPI.describe), Array{Int64, 1}})
precompile(Tuple{typeof(Statistics._mean), Array{Int64, 1}, Base.Colon})
precompile(Tuple{typeof(Base._extrema_itr), typeof(Base.identity), Array{Float64, 1}})
precompile(Tuple{typeof(Base.sort!), Array{Int64, 1}, Int64, Int64, Base.Sort.PartialQuickSort{Base.UnitRange{Int64}}, Base.Order.ForwardOrdering})
precompile(Tuple{typeof(Statistics._quantilesort!), Array{Int64, 1}, Bool, Float64, Float64})
precompile(Tuple{getfield(Statistics, Symbol("#50#51")){Array{Int64, 1}}, Float64})
precompile(Tuple{typeof(Base.collect_to_with_first!), Array{Float64, 1}, Float64, Base.Generator{Array{Float64, 1}, getfield(Statistics, Symbol("#50#51")){Array{Int64, 1}}}, Int64})
precompile(Tuple{typeof(Base._collect), Array{Float64, 1}, Base.Generator{Array{Float64, 1}, getfield(Statistics, Symbol("#50#51")){Array{Int64, 1}}}, Base.EltypeUnknown, Base.HasShape{1}})
precompile(Tuple{getfield(Statistics, Symbol("##quantile#54")), Bool, typeof(Statistics.quantile), Array{Int64, 1}, Array{Float64, 1}})
precompile(Tuple{typeof(StatsBase.summarystats), Array{Int64, 1}})
precompile(Tuple{typeof(Printf.decode_dec), Int64, Array{UInt8, 1}})
precompile(Tuple{typeof(Printf.print_fixed), Base.TTY, Int64, Int32, Int32, Bool, Array{UInt8, 1}})
precompile(Tuple{typeof(Base.show), Base.TTY, StatsBase.SummaryStats{Float64}})
precompile(Tuple{typeof(DataAPI.describe), Base.TTY, Array{Int64, 1}})
precompile(Tuple{Type{StatsBase.SummaryStats{Float64}}, Float64, Float64, Float64, Float64, Float64, Float64, Int64, Int64})
precompile(Tuple{typeof(Base.show), Base.GenericIOBuffer{Array{UInt8, 1}}, Type})
precompile(Tuple{typeof(Base._atexit)})
precompile(Tuple{typeof(Base.Filesystem.temp_cleanup_purge), Bool})
precompile(Tuple{typeof(Base.Filesystem.temp_cleanup_purge)})


text:
"""
    abstract type AbstractScalarDiffusivity <: AbstractTurbulenceClosure end

Abstract type for closures with *isotropic* diffusivities.
"""
abstract type AbstractScalarDiffusivity{TD, F} <: AbstractTurbulenceClosure{TD} end

"""
    struct ThreeDimensional end

Specifies a three-dimensionally-isotropic `ScalarDiffusivity`.
"""
struct ThreeDimensionalFormulation end

"""
    struct Horizontal end

Specifies a horizontally-isotropic, `VectorInvariant`, `ScalarDiffusivity`.
"""
struct HorizontalFormulation end

"""
    struct Vertical end

Specifies a `ScalarDiffusivity` acting only in the vertical direction.
"""
struct VerticalFormulation end

"""
    viscosity(closure, diffusivities)

Returns the isotropic viscosity associated with `closure`.
"""
function viscosity end

"""
    diffusivity(closure, diffusivities, tracer_indedx) where tracer_index

Returns the isotropic diffusivity associated with `closure` and tracer index `c_idx`.
"""
function diffusivity end

@inline formulation(::AbstractScalarDiffusivity{TD, F}) where {TD, F} = F()

Base.summary(::VerticalFormulation) = "VerticalFormulation"
Base.summary(::HorizontalFormulation) = "HorizontalFormulation"
Base.summary(::ThreeDimensionalFormulation) = "ThreeDimensionalFormulation"

#####
##### Stress divergences
#####

const AID = AbstractScalarDiffusivity{<:Any, <:ThreeDimensionalFormulation}
const AHD = AbstractScalarDiffusivity{<:Any, <:HorizontalFormulation}
const AVD = AbstractScalarDiffusivity{<:Any, <:VerticalFormulation}

@inline viscous_flux_ux(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶜᶜᶜ(i, j, k, grid, clock, viscosity(closure, args...), Σ₁₁, U.u, U.v, U.w)
@inline viscous_flux_vx(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶠᶠᶜ(i, j, k, grid, clock, viscosity(closure, args...), Σ₂₁, U.u, U.v, U.w)
@inline viscous_flux_wx(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶠᶜᶠ(i, j, k, grid, clock, viscosity(closure, args...), Σ₃₁, U.u, U.v, U.w)
@inline viscous_flux_uy(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶠᶠᶜ(i, j, k, grid, clock, viscosity(closure, args...), Σ₁₂, U.u, U.v, U.w)
@inline viscous_flux_vy(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶜᶜᶜ(i, j, k, grid, clock, viscosity(closure, args...), Σ₂₂, U.u, U.v, U.w)
@inline viscous_flux_wy(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶜᶠᶠ(i, j, k, grid, clock, viscosity(closure, args...), Σ₃₂, U.u, U.v, U.w)

@inline viscous_flux_ux(i, j, k, grid, closure::AHD, clock, U, args...) = - ν_δᶜᶜᶜ(i, j, k, grid, clock, closure.ν, U.u, U.v)
@inline viscous_flux_vx(i, j, k, grid, closure::AHD, clock, U, args...) = - ν_ζᶠᶠᶜ(i, j, k, grid, clock, closure.ν, U.u, U.v)
@inline viscous_flux_uy(i, j, k, grid, closure::AHD, clock, U, args...) = + ν_ζᶠᶠᶜ(i, j, k, grid, clock, closure.ν, U.u, U.v)
@inline viscous_flux_vy(i, j, k, grid, closure::AHD, clock, U, args...) = - ν_δᶜᶜᶜ(i, j, k, grid, clock, closure.ν, U.u, U.v)
# are we sure about this?? This might not be consistent for AHD
@inline viscous_flux_wx(i, j, k, grid, closure::AHD, clock, U, args...) = - ν_σᶠᶜᶠ(i, j, k, grid, clock, viscosity(closure, args...), ∂xᶠᶜᶠ, U.w)
@inline viscous_flux_wy(i, j, k, grid, closure::AHD, clock, U, args...) = - ν_σᶜᶠᶠ(i, j, k, grid, clock, viscosity(closure, args...), ∂yᶜᶠᶠ, U.w)

@inline viscous_flux_uz(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶠᶜᶠ(i, j, k, grid, clock, viscosity(closure, args...), Σ₁₃, U.u, U.v, U.w)
@inline viscous_flux_vz(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶜᶠᶠ(i, j, k, grid, clock, viscosity(closure, args...), Σ₂₃, U.u, U.v, U.w)
@inline viscous_flux_wz(i, j, k, grid, closure::AID, clock, U, args...) = - 2 * ν_σᶜᶜᶜ(i, j, k, grid, clock, viscosity(closure, args...), Σ₃₃, U.u, U.v, U.w)

@inline viscous_flux_uz(i, j, k, grid, closure::AVD, clock, U, args...) = - ν_σᶠᶜᶠ(i, j, k, grid, clock, viscosity(closure, args...), ∂zᶠᶜᶠ, U.u)
@inline viscous_flux_vz(i, j, k, grid, closure::AVD, clock, U, args...) = - ν_σᶜᶠᶠ(i, j, k, grid, clock, viscosity(closure, args...), ∂zᶜᶠᶠ, U.v)
@inline viscous_flux_wz(i, j, k, grid, closure::AVD, clock, U, args...) = - ν_σᶜᶜᶜ(i, j, k, grid, clock, viscosity(closure, args...), ∂zᶜᶜᶜ, U.w)

#####
##### Diffusive fluxes
#####

@inline diffusive_flux_x(i, j, k, grid, closure::Union{AID, AHD}, c, c_idx, clock, args...) = diffusive_flux_x(i, j, k, grid, clock, diffusivity(closure, c_idx, args...), c)
@inline diffusive_flux_y(i, j, k, grid, closure::Union{AID, AHD}, c, c_idx, clock, args...) = diffusive_flux_y(i, j, k, grid, clock, diffusivity(closure, c_idx, args...), c)
@inline diffusive_flux_z(i, j, k, grid, closure::Union{AID, AVD}, c, c_idx, clock, args...) = diffusive_flux_z(i, j, k, grid, clock, diffusivity(closure, c_idx, args...), c)

#####
##### Zero out not used fluxes
#####

for (dir, closure) in zip((:x, :y, :z), (:AVD, :AVD, :AHD))
    diffusive_flux = Symbol(:diffusive_flux_, dir)
    viscous_flux_u = Symbol(:viscous_flux_u, dir)
    viscous_flux_v = Symbol(:viscous_flux_v, dir)
    viscous_flux_w = Symbol(:viscous_flux_w, dir)
    @eval begin
        @inline $diffusive_flux(i, j, k, grid, closure::$closure, c, c_idx, clock, args...) = zero(eltype(grid))
        @inline $viscous_flux_u(i, j, k, grid, closure::$closure, c, clock, U, args...)     = zero(eltype(grid))
        @inline $viscous_flux_v(i, j, k, grid, closure::$closure, c, clock, U, args...)     = zero(eltype(grid))
        @inline $viscous_flux_w(i, j, k, grid, closure::$closure, c, clock, U, args...)     = zero(eltype(grid))
    end
end

#####
##### Support for VerticallyImplicit
#####

const VITD = VerticallyImplicitTimeDiscretization

  @inline z_viscosity(closure::AbstractScalarDiffusivity, args...)        = viscosity(closure, args...)
@inline z_diffusivity(closure::AbstractScalarDiffusivity, c_idx, args...) = diffusivity(closure, c_idx, args...)

@inline ivd_viscous_flux_uz(i, j, k, grid, closure, clock, U, args...) = - ν_σᶠᶜᶠ(i, j, k, grid, clock, closure.ν, ∂xᶠᶜᶠ, U.w)
@inline ivd_viscous_flux_vz(i, j, k, grid, closure, clock, U, args...) = - ν_σᶜᶠᶠ(i, j, k, grid, clock, closure.ν, ∂yᶜᶠᶠ, U.w)

# General functions (eg for vertically periodic)
@inline viscous_flux_uz(i, j, k, grid,  ::VITD, closure::Union{AID, AVD}, args...) = ivd_viscous_flux_uz(i, j, k, grid, closure, args...)
@inline viscous_flux_vz(i, j, k, grid,  ::VITD, closure::Union{AID, AVD}, args...) = ivd_viscous_flux_vz(i, j, k, grid, closure, args...)
@inline viscous_flux_wz(i, j, k, grid,  ::VITD, closure::Union{AID, AVD}, args...) = zero(eltype(grid))
@inline diffusive_flux_z(i, j, k, grid, ::VITD, closure::Union{AID, AVD}, clock, args...) = zero(eltype(grid))

# Vertically bounded grids
#
# For vertically bounded grids, we calculate _explicit_ fluxes on the boundaries,
# and elide the implicit vertical flux component everywhere else. This is consistent
# with the formulation of the tridiagonal solver, which requires explicit treatment
# of boundary contributions (eg boundary contributions must be moved to the right
# hand side of the tridiagonal system).

@inline function viscous_flux_uz(i, j, k, grid::VerticallyBoundedGrid, ::VITD, closure::Union{AID, AVD}, args...)
    return ifelse(k == 1 || k == grid.Nz+1,
                  viscous_flux_uz(i, j, k, grid, ExplicitTimeDiscretization(), closure, args...),
                  ivd_viscous_flux_uz(i, j, k, grid, closure, args...))
end

@inline function viscous_flux_vz(i, j, k, grid::VerticallyBoundedGrid, ::VITD, closure::Union{AID, AVD}, args...)
    return ifelse(k == 1 || k == grid.Nz+1,
                  viscous_flux_vz(i, j, k, grid, ExplicitTimeDiscretization(), closure, args...),
                  ivd_viscous_flux_vz(i, j, k, grid, closure, args...))
end

@inline function viscous_flux_wz(i, j, k, grid::VerticallyBoundedGrid{FT}, ::VITD, closure::Union{AID, AVD}, args...) where FT
    return ifelse(k == 1 || k == grid.Nz+1,
                  viscous_flux_wz(i, j, k, grid, ExplicitTimeDiscretization(), closure, args...),
                  zero(FT))
end

@inline function diffusive_flux_z(i, j, k, grid::VerticallyBoundedGrid{FT}, ::VITD, closure::Union{AID, AVD}, args...) where FT
    return ifelse(k == 1 || k == grid.Nz+1,
                  diffusive_flux_z(i, j, k, grid, ExplicitTimeDiscretization(), closure, args...),
                  zero(FT))
end


text:
using LinearAlgebra
import Flux
import Flux: σ

gate(h, n) = (1:h) .+ h*(n-1)
gate(x::AbstractVector, h, n) = @view x[gate(h,n)]
gate(x::AbstractMatrix, h, n) = @view x[gate(h,n),:]

struct CachedRecur{C, M <: AbstractVecOrMat}
   cell  :: C
   init  :: M
   state :: M
end

Flux.@functor CachedRecur

Flux.trainable(m::CachedRecur) = (m.cell, m.init)

struct CachedLSTMCell{M <: AbstractVecOrMat, V <: AbstractVecOrMat}
   Wi :: M
   Wh :: M
   b  :: V
   cache :: NamedTuple{(:g, :Wix), NTuple{2,M}}
end

Flux.@functor CachedLSTMCell

Flux.trainable(m::CachedLSTMCell) = (m.Wi, m.Wh, m.b)

function CachedLSTMCell(in::Integer, out::Integer; batchsize::Integer,
                        init = Flux.glorot_uniform)
   b = init(4out)
   b[gate(out, 2)] .= 1
   O = Flux.zeros(4out, batchsize)
   cache = (g = O, Wix = copy(O))
   return CachedLSTMCell(init(4out, in), init(4out, out), b, cache)
end

function (m::CachedLSTMCell)((h, c), x)
   Wi, Wh, b, o, batch = m.Wi, m.Wh, m.b, size(h, 1), axes(x, 2)
   @views g, Wix = m.cache.g[:,batch], m.cache.Wix[:,batch]
   g .= mul!(Wix, Wi, x) .+ mul!(g, Wh, h) .+ b
   @views ifo, cell = g[1:(3o),:], g[(3o+1):end,:]
   ifo .= σ.(ifo)
   cell .= tanh.(cell)
   input, forget, output = gate(ifo, o, 1), gate(ifo, o, 2), gate(ifo, o, 3)
   @. c = forget * c + input * cell
   @. h = output * tanh(c)
   return (h, c), h
end

max_stars_repo_name: AzamatB/CachedFluxLayers

max_issues_repo_name: AzamatB/CachedFluxLayers

max_forks_repo_name: AzamatB/CachedFluxLayers