Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow users to specify the domain when creating a `RegularCartes… #464

Merged
merged 15 commits into from
Oct 23, 2019

Conversation

ali-ramadhan
Copy link
Member

@ali-ramadhan ali-ramadhan commented Oct 12, 2019

So now we can specify the domain using

RegularCartesianGrid(Float64; N=(10, 10, 10), x=(-5, 5), y=(-π, π), z=(0, 1))

but if we only care about the length of each dimension then you can still use

RegularCartesianGrid((32, 32, 32), (1, 1, 1))

This is nice for a lot of problems where the domain isn't x=(0, Lx), y=(0, Ly), z=(-Lz, 0).

I also learned that keyword arguments do not participate in dispatch so you can't have both RegularCartesianGrid(T; N, L) and RegularCartesianGrid(T; x, y, z) :( Apparently it's a pretty old Julia issue: JuliaLang/julia#9498

Resolves #413

@ali-ramadhan ali-ramadhan added the feature 🌟 Something new and shiny label Oct 12, 2019
@glwagner
Copy link
Member

glwagner commented Oct 12, 2019

While we are breaking the API, why not use size instead of N, so its

RegularCartesianGrid(Float64; size=(10, 10, 10), x=(-5, 5), y=(-π, π), z=(0, 1))

It's not only more verbose but also removes the sometimes painful fact that we really want to use N to mean 'buoyancy frequency' in many contexts. It's unfortunate if we remove that potential for clear nomenclature in scripts for geophysical stuff.

I'd also propose adding a constructor of the form

RegularCartesianGrid(FT, nx, ny, nz; length) = RegularCartesianGrid(FT; size=(nx, ny, nz), 
    x=(-length[1]/2, length[1]/2), y=(-length[2]/2, length[2]/2), z=(-length[3], 0))

This has a syntax similar to the Base function zeros, which is nice. Also, we add a small nod to "Oceans" by putting z[nx+1] at the surface. In addition we can add

RegularCartesianGrid(FT, size::Tuple; length) = RegularCartesianGrid(FT, size...; length)

(Along with the corresponding constructors with default float types.)

I'm not too fond of RegularCartesianGrid(size, length), but happy to keep it around if some find it useful, we just don't need to use it in examples and docs.

We've also never discussed this --- but why do we use Nx rather than nx? I find it harder to type; plus julia uses capital letters for types so its a bit of a break in pattern; almost everything else is lowercase.

Edit: if size isn't satisfactory, we could try resolution or number_grid_points (ugly... 😒) instead.

Copy link
Member

@glwagner glwagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this and think its a positive change. Could be good to add a few more small niceties. Major point of discussion is N versus size.

src/grids.jl Outdated Show resolved Hide resolved
@ali-ramadhan
Copy link
Member Author

I think it's a good idea to merge a RegularCartesianGrid we're fully happy with as I'm going to add a VerticallyStretchedCartesianGrid very soon so would be nice to have them both share the same design. Happy to expand the scope of this PR a bit.

why not use size instead of N

Now that L is no longer a keyword argument, we can use size.

We've also never discussed this --- but why do we use Nx rather than nx? I find it harder to type; plus julia uses capital letters for types so its a bit of a break in pattern; almost everything else is lowercase.

I'm on board with a change to lowercase n as it fits the Julia style guide.

I'm not too fond of RegularCartesianGrid(size, length), but happy to keep it around if some find it useful, we just don't need to use it in examples and docs.

Same here, it's a legacy constructor but we can get rid of it in this PR which would also help address #429.

RegularCartesianGrid(FT, nx, ny, nz; length) = RegularCartesianGrid(FT; size=(nx, ny, > nz), 
    x=(-length[1]/2, length[1]/2), y=(-length[2]/2, length[2]/2), z=(-length[3], 0))

This seems like a good default.

@ali-ramadhan
Copy link
Member Author

On that note I feel that RegularCartesianGrid and VerticallyStretchedCartesianGrid are quite wordy.

I wonder if it's better to define abstract types like Uniform or Regular for dimensions with uniform grid spacing and Stretched or NonUniform for non-uniform grid spacing.

Then you can dispatch on e.g. CartesianGrid{Uniform, Uniform, Uniform} and CartesianGrid{Uniform, Uniform, Stretched} but this can get unwieldy so maybe just have one parametric type for the vertical as we're not really planning on having non-uniform grid spacing in the horizontal.

@glwagner
Copy link
Member

glwagner commented Oct 12, 2019

I wonder if it's better to define abstract types like Uniform or Regular for dimensions with uniform grid spacing and Stretched or NonUniform for non-uniform grid spacing.

What information do you need for a stretched grid? Is this just a matter of Δx becoming a Function / Array rather than a number?

In that case we just have CartesianGrid, and dispatch occurs on the type of Δx for each dimension individually.

Edit: may be best to save this change until we have a stretched grid. We haven't really discussed how we'd construct stretched grids, but our design may depend on that.

@ali-ramadhan
Copy link
Member Author

may be best to save this change until we have a stretched grid. We haven't really discussed how we'd construct stretched grids, but our design may depend on that.

True, good idea. My main concern was readability as we dispatch on RegularCartesianGrid and VerticallyStretchedGrid often in the updated operators (PR #283).

@ali-ramadhan
Copy link
Member Author

Unfortunately can't dispatch on keyword arguments

julia> f(x; y, z) = x + y + z
f (generic function with 1 method)

julia> f(x; n) = f(x; y=n, z=2n)
f (generic function with 1 method)

so I don't think we can use this constructor

RegularCartesianGrid(FT, nx, ny, nz; length) = RegularCartesianGrid(FT; size=(nx, ny, nz), 
    x=(-length[1]/2, length[1]/2), y=(-length[2]/2, length[2]/2), z=(-length[3], 0))

but maybe we can define a RegularCartesianGrid(FT, N, L) like before, or a RegularCartesianGrid(FT, nx, ny, nz, lx, ly, lz).

Or we can define an extra keyword argument length so the constructor becomes

RegularCartesianGrid(FT; size, length=nothing, x=nothing, y=nothing, z=nothing)

so you either specify a length or x, y, z bounds.

Also, do we want lowercase Nx -> nz also for halos Hx -> hx and domain size Lx -> lx? While I prefer Lx, if Nx becomes nx then Lx should become lx for consistency. Probably leave areas Ax capitalized?

@glwagner
Copy link
Member

best to avoid lowercase l I think. Why don't we just keep capital N for now. I think we could have some changes coming down the pipe that would greatly facilitate this change (macro that pastes our triple loop, so reduce that massive amount of boilerplate and can change syntax in single place rather than 30 different locations).

I thought RegularCartesianGrid(FT, nx, ny, nz; length) could dispatch on its 4 positional args. What is the conflicting function RegularCartesianGrid that has 4 positional args, and why can't dispatch be used there?

@glwagner
Copy link
Member

Adding length as kwarg with code to validate is fine too.

@ali-ramadhan ali-ramadhan changed the title Allow user to specify domain when creating a RegularCartesianGrid Allow user to specify the domain when creating a RegularCartesianGrid Oct 23, 2019
@ali-ramadhan
Copy link
Member Author

ali-ramadhan commented Oct 23, 2019

I went a bit further and nuked the legacy constructors so that there's only one now:

RegularCartesianGrid(FT=Float64; size, length, x, y, z)

Again, this is a breaking API change although I think we should be nuking legacy constructors now while the code is not being widely used (#429).

I'd like to do something similar for BasicModel.

@ali-ramadhan ali-ramadhan changed the title Allow user to specify the domain when creating a RegularCartesianGrid Allow users to specify the domain when creating a RegularCartesianGrid Oct 23, 2019
Copy link
Member

@glwagner glwagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Examples need to be fixed.

Curious what @suyashbire1 thinks. This is a little late but it is fairly annoying that size and length are the name of base functions and somehow it just doesn't ring right for me (can't put my finger on it). We could use resolution and extent or something like that (in hindsight those are typically the words I'd use in a scientific paper...)

Might be good to put out an informal poll before making this change to see what people find most intuitive.

Bleh.

examples/ocean_wind_mixing_and_convection.jl Outdated Show resolved Hide resolved
examples/two_dimensional_turbulence.jl Outdated Show resolved Hide resolved
src/grids.jl Outdated
Ax::T
Ay::T
Az::T
Ax::FT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need areas and volumes right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true, we currently don't use them.

But thinking about it a bit more, I think we might want to start using them in PR #283. With the more general finite volume operators, we have areas that are computed like

@inline Az(i, j, k, grid) = Δx(i, j, k, grid) * Δy(i, j, k, grid)

although for RegularCartesianGrid and VerticallyStretchedCartesianGrid it might make more sense to use

@inline Az(i, j, k, grid) = grid.Az

to avoid an extra multiplication at the very lowest level.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure you'd see that benefit since I think our costs are dominated by accessing memory. But could be worth benchmarking. If it has no cost I think doing the multiplication is fine; makes the structs simpler which is well worth it. "Store information in functions".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I'll remove them here as they're currently not being used. And I'll benchmark the two options when I work on merging in #283.

Copy link
Member Author

@ali-ramadhan ali-ramadhan Oct 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might make more sense for vertically stretched grids where grid.ΔzF[k] involves an extra memory access but we'll find out when we benchmark the vertically stretched grid.

# Hack that allows us to use `size` and `length` as keyword arguments but then also
# use the `size` and `length` functions.
sz, len = size, length
length = Base.length
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yes, that's annoying.

src/grids.jl Outdated Show resolved Hide resolved
@codecov
Copy link

codecov bot commented Oct 23, 2019

Codecov Report

Merging #464 into master will decrease coverage by 0.03%.
The diff coverage is 85.36%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #464      +/-   ##
==========================================
- Coverage   73.34%   73.31%   -0.04%     
==========================================
  Files          27       27              
  Lines        1508     1525      +17     
==========================================
+ Hits         1106     1118      +12     
- Misses        402      407       +5
Impacted Files Coverage Δ
src/fields.jl 47.67% <ø> (ø) ⬆️
src/models.jl 79.54% <66.66%> (ø) ⬆️
src/grids.jl 83.33% <86.84%> (-10.22%) ⬇️
src/buoyancy.jl 80.64% <0%> (+3.22%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 41a2b55...cab311e. Read the comment docs.

@ali-ramadhan
Copy link
Member Author

Yeah it's not perfect, might be good to discuss a bit so we can merge in a grid we're all happy with (might as well make all breaking changes right now).

Examples need to be fixed.

Fixed them and example tests pass on my laptop. But yeah this might be a problem in the future as we're skipping them...

This is a little late but it is fairly annoying that size and length are the name of base functions and somehow it just doesn't ring right for me (can't put my finger on it). We could use resolution and extent or something like that (in hindsight those are typically the words I'd use in a scientific paper...)

I agree. One bonus point is that size(grid) returns the size you put in, and length(grid) returns the physical length of each dimension, but maybe this is surprising to users who expect size and length to apply to arrays only.

Hmmm, I'm not opposed to resolution and extent although I find them more obscure than size and length which I think make more sense in the code.

@glwagner
Copy link
Member

glwagner commented Oct 23, 2019

@ali-ramadhan:

Both @christophernhill and @suyashbire1 vote for size and length. That's good enough to soothe my concerns.

@ali-ramadhan
Copy link
Member Author

Awesome. Do we want to make any more changes to RegularCartesianGrid or should we just merge?

@ali-ramadhan ali-ramadhan added the cleanup 🧹 Paying off technical debt label Oct 23, 2019
@ali-ramadhan ali-ramadhan changed the title Allow users to specify the domain when creating a RegularCartesianGrid Allow users to specify the domain when creating a `RegularCartes… Oct 23, 2019
@ali-ramadhan ali-ramadhan merged commit 3f3ef52 into master Oct 23, 2019
@ali-ramadhan ali-ramadhan deleted the grid-xyz branch October 23, 2019 14:07
arcavaliere pushed a commit to arcavaliere/Oceananigans.jl that referenced this pull request Nov 6, 2019
…iMA#464)

Allow users to specify the domain when creating a `RegularCartesianGrid`

Former-commit-id: 3f3ef52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cleanup 🧹 Paying off technical debt feature 🌟 Something new and shiny
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Grids should allow us to specify the domain
3 participants