Skip to content

Require Mesh::addCoordinates(location) to initialize Coordinates at location - #1392

Closed
johnomotani wants to merge 27 commits into
nextfrom
getCoordinates_fix-next
Closed

Require Mesh::addCoordinates(location) to initialize Coordinates at location#1392
johnomotani wants to merge 27 commits into
nextfrom
getCoordinates_fix-next

Conversation

@johnomotani

Copy link
Copy Markdown
Contributor

This is the 'final' version of changes started in #1372. Now only CELL_CENTRE coordinates are created by default, and the user must call REQUEST_LOCATION(location) or mesh->addCoordinates(location) to initialize Coordinates for staggered locations.

Includes updates to the manual, unit tests for addCoordinates() as part of BoutMeshTest and support for getCoordinates/addCoordinates in boutcore.

This does add a couple of methods to Mesh, hasCoordinates(location) and countCoordinates(). I think they're justified, but alternatives could be to make Coordinates a friend of Mesh, or to make coords_map a public member; I don't favour either of those alternatives, but maybe there are others?

Previously the localmesh was not passed through to the constructor of
d2x and d2y in Coordinates::geometry(), so they used the global 'mesh'.

Also, when d2x/d2y are read from the mesh, they are at CELL_CENTRE, so
we need to interpolate them to the location of the Coordinates.
Could cause bugs, for example in unit tests of BoutMesh where
mesh==nullptr.
Comment thread src/mesh/mesh.cxx
Get the Coordinates object of this mesh
Deprecated version of getCoordinates
"""
print("Warning Mesh.coordinates is deprecated, and does not handle "

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe use warnings.warn?

Comment thread include/bout/mesh.hxx Outdated
}

/// switch to pass to Coordinates objects
bool allow_geometry_without_recalculate_staggered;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please could the doxygen comment be a bit more descriptive?

Also should this be a member of mesh/does it need to be stored at all? It looks like it should maybe just be an argument to Coordinates::geometry?

@ZedThree

Copy link
Copy Markdown
Member

I'm afraid I'm not 100% sure about the utility of the macro. It's not much shorter than mesh->addCoordinates.

Would an alternative to requiring users to call this in their physics models be to put the call to Mesh::addCoordinates in Field3D::applyBoundary?

@johnomotani

Copy link
Copy Markdown
Contributor Author

I'd be fine with getting rid of the macro if you think it's not useful.

Why in Field3D::applyBoundary? I'd thought about trying to put the call to Mesh::addCoordinates in Field*::setLocation but that gets called frequently (it's inside a whole bunch of other methods). I'm in favour of requiring the user to make an explicit call to something because the order of calling for example Mesh::addCoordinates and Coordinates::geometry matters; making the user call Mesh::addCoordinates seems like the only way to have addCoordinates be called once and only once for each location, which I think is attractive because it avoids recalculating stuff and minimizes the amount of checking needed.

@johnomotani
johnomotani force-pushed the getCoordinates_fix-next branch from 6dec2de to bbfb58d Compare November 21, 2018 12:55
@johnomotani

Copy link
Copy Markdown
Contributor Author

Fabio just made a good point: the way this PR has gone, we're now initializing settings for staggered grids in two ways - with the mesh:staggergrids option in the input file and with Mesh::addCoordinates c++-code in the physics model init() [even before, some 'settings' are in c++-code since the user has to call setLocation or use outloc arguments to derivatives, etc.].

This might be a good time to simplify the initialization. We could either:

  1. Have input file settings specifying which locations should be available, e.g. mesh:staggered locations = xlow, ylow, zlow. Coordinates objects get created for all locations selected, and updated whenever geometry() is called on the CELL_CENTRE Coordinates. Remove Mesh::addCoordinates, or make it protected.
  2. Remove 'staggering' settings from the input file and just require a call to Mesh::addCoordinates during init for each location that will be used. addCoordinates should be called after geometry() on the CELL_CENTRE Coordinates and before any setLocation. Since models like STORM that use staggering probably hard-code the CELL_LOCs anyway, removing run-time options for staggering could be sensible.

In either case I think the mesh:staggergrids option and bool Mesh::StaggerGrids could be removed/deprecated now. Mesh::StaggerGrids is actually not used much any more except in checks where we wouldn't lose anything by leaving the check as something like inloc==outloc or rhs.getLocation()==lhs.getLocation(). I think the only place it makes any real difference is in derivs_initialise() where staggered derivative tables aren't created, but #1384 replaces that anyway.

Thoughts? I'm inclined to option 2, a compile-time 'setting' in init().

@dschwoerer

dschwoerer commented Nov 21, 2018 via email

Copy link
Copy Markdown
Contributor

@johnomotani
johnomotani force-pushed the getCoordinates_fix-next branch from bbfb58d to 7e7fa88 Compare November 25, 2018 13:18
@johnomotani johnomotani changed the title Require REQUEST_LOCATION(location) to initialize Coordinates at location Require Mesh::addCoordinates(location) to initialize Coordinates at location Nov 25, 2018
Instead of creating Coordinates objects when Mesh::getCoordinates is
called, create them during initialization. As a temporary workaround to
maintain backward compatibility, initialize all locations in
BoutMesh::load() so that they are always available.

Allow the user to explicitly request a location to be available, by
calling Mesh::addCoordinates(location) for each location required. This
is optional in v4.2 but will be required from v4.3.

When Coordinates::geometry() is called, assume that staggered location
Coordinates objects need to be recalculated because the user has changed
the CELL_CENTRE version.

As a temporary workaround, replace geometry() with
geometryNoRecalculate() and geometry() now calls geometryNoRecalculate
and then recalculates the staggered versions. This means geometry() can
be reset back to not recalculating in next (which is OK because we will
add the requirement to call addCoordinates() after calling geometry())
without changing the function signature.
Allows Coordinates pointers to be retrieved where necessary in the unit
tests.
Instead of creating Coordinates objects when Mesh::getCoordinates is
called, create them during initialization. As a temporary workaround to
maintain backward compatibility, initialize all locations in
BoutMesh::load() so that they are always available.

Allow the user to explicitly request a location to be available, by
calling Mesh::addCoordinates(location) for each location required. This
is optional in v4.2 but will be required from v4.3.

When Coordinates::geometry() is called, assume that staggered location
Coordinates objects need to be recalculated because the user has changed
the CELL_CENTRE version.

As a temporary workaround, replace geometry() with
geometryNoRecalculate() and geometry() now calls geometryNoRecalculate
and then recalculates the staggered versions. This means geometry() can
be reset back to not recalculating in next (which is OK because we will
add the requirement to call addCoordinates() after calling geometry())
without changing the function signature.
Remove initialization of Coordinates for all staggered locations in
BoutMesh::load(). User is now required to initialize the Coordinates for
any needed locations using Mesh::addCoordinates(location).

Removes recalculation of staggered Coordinates in
Coordinates::geometry(). The user should instead call
addCoordinates(location) after the CELL_CENTRE Coordinates object is
updated and its geometry() method is called. geometry() checks that
either it has been called at CELL_CENTRE and CELL_CENTRE is the only
entry in coords_map, or that the location of the current Coordinates
object that called geometry() has not yet been added to coords_map; this
check can be overridden by setting the option
mesh:allow_geometry_without_recalculate_staggered=true so that the
staggered Coordinates objects can be explicitly updated if necessary.

If Mesh::addCoordinates(location) is called without explicitly asking
for the Coordinates at location to be replaced (using the replace_coords
argument) then throw an exception if location is already in coords_map.
tests/integrated/test-drift-instability, tests/MMS/wave-1d and
tests/MMS/wave-1d-y use staggered grids and so need to call
Mesh::addCoordinates(location).
Move StaggerGrids option into [mesh] section of input files.

Call mesh->addCoordinates(CELL_YLOW).

Only use CELL_YLOW if mesh->StaggerGrids=true to avoid exceptions.
Need to call Mesh.addCoordinates(location) to initialize staggered
grids in tests/MMS/derivatives3 and tests/MMS/upwinding3.
Unit tests for addCoordinates() methods.
Call to addCoordinates('YLOW') is now needed to allow 'YLOW' location to
be used.
Make the allow_geometry_without_recalculate_staggered flag an argument
to Coordinates::geometry() rather than an option that has to be read by
Mesh and passed to Coordinates.
If Field3D was created in global scope, its fieldmesh pointer is null.
getMesh() returns the global mesh in that case, so use getMesh() instead
of fieldmesh to avoid segfaults.
@johnomotani
johnomotani force-pushed the getCoordinates_fix-next branch from 7e7fa88 to 53f780a Compare November 25, 2018 13:44
Comment thread include/bout/mesh.hxx
GridDataSource *source; ///< Source for grid data

std::map<CELL_LOC, std::shared_ptr<Coordinates> > coords_map; ///< Coordinate systems at different CELL_LOCs
std::map<CELL_LOC, std::unique_ptr<Coordinates> > coords_map; ///< Coordinate systems at different CELL_LOCs

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure about changing this to unique_ptr. I know we currently hand out a raw pointer, but that should change, and returning a unique_ptr says "I'm giving ownership over to you", whereas a shared_ptr says "You can have a look at this, but I will keep hold of it too"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My thought in changing to unique_ptr it was that the Mesh object should keep ownership of the Coordinates objects, and not share ownership (since there is no point keeping the Coordinates after the Mesh has been deleted anyway). I'm having trouble finding much discussion, but see e.g. https://www.reddit.com/r/cpp/comments/6dyq6l/is_it_alright_to_return_raw_pointer_from_unique/. Maybe raw pointer is OK, or we could return reference?

@bendudson

Copy link
Copy Markdown
Contributor

I think if the result can't be null, and we're not transferring or sharing ownership, then a reference would be the right way to go. I may have got that wrong though.

@johnomotani

Copy link
Copy Markdown
Contributor Author

If in the long term we want to return a reference, what should we do now? Changing getCoordinates() to return a reference would break backward compatibilty. Do we want a new method that returns a reference (what would be a sensible name for it?) and to deprecate Coordinates* getCoordinates()? Or to leave as-is (returning a pointer) for now, and change to returning a reference in the next major release? Or something else?

@bendudson

Copy link
Copy Markdown
Contributor

Since coordinates only recently changed to getCoordinates, perhaps getCoordinates could return a reference, and coordinates return a pointer?

@johnomotani

Copy link
Copy Markdown
Contributor Author

Since coordinates only recently changed to getCoordinates, perhaps getCoordinates could return a reference, and coordinates return a pointer?

I'd be happy with that, but technically it changes the v4.2 interface... Any thoughts @ZedThree?

@johnomotani

Copy link
Copy Markdown
Contributor Author

Interface question: Rather than requiring users to call Mesh::addCoordinates(location) for each location they want to use, would it be better to have a separate method like Mesh::enableLocation(location)? For now enableLocation(location) could just call addCoordinates(location) but it would be more future-proof in case we need to do other things for different locations, for example create different ParallelTransforms, at some point.

Using std::unique_ptr for Mesh::coords map requires a few changes to
FakeMesh.
@ZedThree

Copy link
Copy Markdown
Member

I think we're passing this up in favour of setLocation automagically doing the right thing (reopen this if I'm wrong!)

@ZedThree ZedThree closed this Jan 25, 2019
@johnomotani
johnomotani deleted the getCoordinates_fix-next branch March 11, 2019 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants