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

Optionally keep guard cells #30

Merged
merged 12 commits into from
Jul 29, 2019
Merged

Optionally keep guard cells #30

merged 12 commits into from
Jul 29, 2019

Conversation

TomNicholas
Copy link
Collaborator

@TomNicholas TomNicholas commented Mar 20, 2019

This adds options keep_xguards and keep_yguards to open_boutdataset, which will stop the preprocessing function from trimming the cells at the edges of the domain. Addresses #19

It works by inferring the location of the dump file within the whole domain using the number of the dump file and know of the overall processor splitting in each direction.

This isn't finished though - some of the tests need to be rewritten as their use of fixtures is pretty dodgy (I think there was a better way to do them with pytest that I didn't know about when I wrote them, but I'll have a look and push to this branch).

It also assumes there are only boundary cells at the outer edges of the domain, so I think it might not yet work with geometries which have a private flux region? This might break my nice logic in _infer_contains_guards()...

(Note to self: this works with the master branch of xarray rather than with my PR)

@TomNicholas TomNicholas added the enhancement New feature or request label Mar 20, 2019
@TomNicholas TomNicholas requested a review from ZedThree March 20, 2019 17:12
@johnomotani
Copy link
Collaborator

it might not yet work with geometries which have a private flux region?

Should be fine for single-null geometries. Double-null is trickier because the second pair of divertor targets (y-boundries) is in the middle of the grid. I've got a PR coming soon for BOUT-dev to load those y-boundary cells from grid files, which shows the logic needed. It would probably be easier to implement here if we saved global x,y,z indices in the dump files...

@TomNicholas
Copy link
Collaborator Author

Should be fine for single-null geometries. Double-null is trickier

Ah yes I meant double-null geometries.

It would probably be easier to implement here if we saved global x,y,z indices in the dump files...

That would make it easier but would also be a breaking change... Relates to #3
I don't think we have to have global indices to do this, as long as the position of the second pair of targets can be deduced from the variables in a single dump file.

@codecov-io
Copy link

codecov-io commented Mar 20, 2019

Codecov Report

Merging #30 into master will increase coverage by 3.59%.
The diff coverage is 87.09%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #30      +/-   ##
==========================================
+ Coverage   48.03%   51.62%   +3.59%     
==========================================
  Files           6        6              
  Lines         254      277      +23     
  Branches       51       56       +5     
==========================================
+ Hits          122      143      +21     
- Misses        122      123       +1     
- Partials       10       11       +1
Impacted Files Coverage Δ
xbout/boutdataset.py 37.07% <100%> (ø) ⬆️
xbout/load.py 86.91% <86.66%> (+1.2%) ⬆️

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 cc503e7...82ff092. Read the comment docs.

xbout/load.py Outdated
@@ -151,31 +155,82 @@ def _arrange_for_concatenation(filepaths, nxpe=1, nype=1):
return paths_grid, concat_dims


def _trim(ds, ghosts={}, keep_guards=True):
def _trim(ds, ghosts, guards={}, keep_guards={}, nxpe=1, nype=1):
Copy link
Member

Choose a reason for hiding this comment

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

=None rather than ={} as a default argument. This does mean you then need to check if it's None, and if so set a default

xbout/load.py Outdated
lower = None
else:
lower = max(ghosts[dim], guards[dim])
elif ghosts.get(dim, False):
Copy link
Member

Choose a reason for hiding this comment

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

ghosts[dim] is optional here, but required above (max(ghosts[dim], guards[dim])

Might just need documenting?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Technically this is fine because you would never have a dimension which has guard cells but no ghost cells, but it should be made consistent for clarity and ease of testing.

elif ghosts.get(dim, False):
upper = -ghosts[dim]
else:
upper = None
Copy link
Member

Choose a reason for hiding this comment

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

The logic for upper is almost the same as for lower -- is it possible to pull out into a helper function?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Probably - I'll have a go

Copy link
Member

Choose a reason for hiding this comment

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

As they are not completely identical, it might be more trouble that its worth

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I managed to factor this out, so do you think this is ready to merge now @ZedThree ?

@ZedThree
Copy link
Member

ZedThree commented Jul 2, 2019

What are the differences between "ghost" and "guard" cells?

@TomNicholas
Copy link
Collaborator Author

I was using the definitions:

Ghost cells - internal boundary cells around a processor which are not at the edge of the domain, only used for communication, duplicated between processors.

Guard cells - external boundary cells around a processor which are at the edge of the domain. Might be physically-meaningful for certain bcs, for example Debye sheath.

So you might want to keep guard cells in your output but you'll never want to keep ghost cells.

@ZedThree
Copy link
Member

ZedThree commented Jul 2, 2019

Ah, ok. In BOUT++ we usually use "guard cells" to mean what you call "ghost cells", and "boundaries" to mean "guard cells", although not always consistently, unfortunately. We also always have the same number of guard cells as boundary cells.

We may need to be a bit careful here.

@TomNicholas
Copy link
Collaborator Author

Okay, sounds like I should change the names here to match BOUT conventions (even if they're not rigorously adhered to). I'll also add a clear explanation of the difference to the docs somewhere (probably just the docstring of the functions which have keep_xguards etc as arguments).

@bendudson
Copy link
Contributor

Thanks @TomNicholas and @ZedThree . I think if this naming is documented somewhere then we can try to make it consistent across the code and documentation.

_trim was missing a required argument.
Since _trim is a private method, and in the only place it is used all
the arguments are passed, it is clearer not to handle default arguments.
In BOUT++ there are always the same number of guard cells and boundary
cells in a given direction, so do not need to specify the number of
boundary cells separately.
johnomotani and others added 2 commits July 23, 2019 09:17
Merge master into #30 to fix conflicts in making boundary cells optional
@pep8speaks
Copy link

pep8speaks commented Jul 25, 2019

Hello @TomNicholas! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

There are currently no PEP 8 issues detected in this Pull Request. Cheers! 🍻

Comment last updated at 2019-07-26 12:26:59 UTC

guards : dict
Number of guard cells along each dimension, e.g. {'x': 2, 't': 0}
keep_boundaries : dict
Whether or not to preserve the boundary cells along each dimension, e.g.
Copy link
Member

Choose a reason for hiding this comment

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

Just for reference, nxpe, nype aren't documented here

Also, I guess guards and keep_boundaries are optional, although that is somewhat obvious from the signature (if you're familiar with the syntax!)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I've added nxpe and nype to the docstring.

guards and keep_boundaries aren't optional. The foo(*, a, b) syntax means that a and b are required keyword arguments. I found it recently and quite like it because I think long sequences of positional arguments are bug-prone, but it's still nice to use required arguments sometimes - for example here it's an internal-implementation-only function which isn't called with default arguments, so no need to have the handling for default arguments (that would be needed if we had something like guards=None).

@TomNicholas TomNicholas merged commit 3886da9 into master Jul 29, 2019
@johnomotani johnomotani deleted the keep_guard_cells branch August 10, 2019 18:43
johnomotani pushed a commit that referenced this pull request Dec 11, 2019
Merge master into #30 to fix conflicts in making boundary cells optional
johnomotani pushed a commit that referenced this pull request Dec 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants