Oceananigans.jl: Elegant unpacking

Created on 28 Mar 2019  ·  8Comments  ·  Source: CliMA/Oceananigans.jl

Right now we have monstrosities like (this one is a bit extreme)

    Nx, Ny, Nz = model.grid.Nx, model.grid.Ny, model.grid.Nz
    Lx, Ly, Lz = model.grid.Lx, model.grid.Ly, model.grid.Lz
    Δx, Δy, Δz = model.grid.Δx, model.grid.Δy, model.grid.Δz

    grid = model.grid
    cfg = model.configuration
    bcs = model.boundary_conditions
    clock = model.clock

    G = model.G
    Gp = model.Gp
    constants = model.constants
    eos =  model.eos
    U = model.velocities
    tr = model.tracers
    pr = model.pressures
    forcing = model.forcing
    poisson_solver = model.poisson_solver

    δρ = model.stepper_tmp.fC1
    RHS = model.stepper_tmp.fCC1
    ϕ = model.stepper_tmp.fCC2

    gΔz = model.constants.g * model.grid.Δz
    fCor = model.constants.f

    uvw = U.u.data, U.v.data, U.w.data
    TS = tr.T.data, tr.S.data
    Guvw = G.Gu.data, G.Gv.data, G.Gw.data

    # Source terms at current (Gⁿ) and previous (G⁻) time steps.
    Gⁿ = G.Gu.data, G.Gv.data, G.Gw.data, G.GT.data, G.GS.data
    G⁻ = Gp.Gu.data, Gp.Gv.data, Gp.Gw.data, Gp.GT.data, Gp.GS.data

Would be nice to prettify or abstract away this unpacking.

@charleskawczynski I noticed you used some @unpack macros in the code you showed on Monday, is it up on GitHub by any chance?

I think Parameters.jl implements an @unpack macro, might be good to look at.

abstractions 🎨 cleanup 🧹

All 8 comments

I think it's as simple as something like

macro unpack_model(model)
    esc(quote
            forcing = $(model).forcing
            # etc
        end # quote
    )
end

@unpack_model model # pastes forcing=model.forcing, etc

I think? Maybe there's a way to make it more automated though.

I've also implemented a similar idea with a function, which is more explicit so maybe better:

function unpack_model(model)
    return model.forcing, model.velocities
end

forcing, U = unpack_model(model)

Although I prefer being explicit I'm a big fan of the macro you suggested as it collapses 20+ lines into a single elegant statement (and buries the ugly unpacking) whereas the unpack_model function still requires a comma separate list of 20+ variables.

I think I'll go with the simple macro. If the unpacking variables have descriptive names, e.g. grid, source_terms, velocities, etc. then I think it'll still be understandable without being explicit.

quite!

with a function you can do some automated stuff, like

function unpack_model(model)
    names = propertynames(model)
    return (getproperty(model, name) for name in names)
end

which will unpack every single field in model.

There's also something like

macro unpack(obj, names...)
    exprs = [ :($name = getproperty($obj, $name)) for name in names ]
    esc(quote
        $(exprs...)
    end
    )
end

which then would have the syntax

@unpack model forcing velocities 

but then you can't rename the fields; they just get spit into the namespace as is.

for this line:

Gⁿ = G.Gu.data, G.Gv.data, G.Gw.data, G.GT.data, G.GS.data

you might want to do something like

data(field) = field.data

function data(fields...)
    (data(field) for field in fields)
end

then you can write Gⁿ = data(G...), provided that typeof(G) <: Collection (I think... should check, but I think its something like that) --- which is true if G is a FieldVector (which I'd advocate).

By the way, I think the fields of G should be u, v, etc. rather than Gu, Gv, etc --- if the names of the fields of these FieldVector like quantities are the same when they refer to the same solution field (u or v or etc) that might enable some generic programming later (because we can relate G.u = ... to solution.u, or whatever).

@charleskawczynski I noticed you used some @unpack macros in the code you showed on Monday, is it up on GitHub by any chance?

It's not, but it is simple (credit @peterahrens ):

macro unpack(stuff, syms...)
  thunk = Expr(:block)
  for sym in syms
    push!(thunk.args, :($(esc(sym)) = $(esc(stuff))[$(QuoteNode(sym))]))
  end
  push!(thunk.args, nothing)
  return thunk
end

I've mostly been using this to unpack light-weight parameters via the input argument params::NamedTuple.

@ali-ramadhan do we need this anymore?

Hmmm, not for the model and the tuples you added help a lot so I'll close this.

I defined an @unpack for the Grid which has been useful, and we can define more in the future if we need them.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ali-ramadhan picture ali-ramadhan  ·  4Comments

truedichotomy picture truedichotomy  ·  8Comments

freemin7 picture freemin7  ·  5Comments

ali-ramadhan picture ali-ramadhan  ·  6Comments

ali-ramadhan picture ali-ramadhan  ·  8Comments