-
Notifications
You must be signed in to change notification settings - Fork 12
Move util docs, install instructions into top level docs #380
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
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
3a0e55e
move util docs to top level, include install instructions in sphinx docs
mcgibbon ece352b
add placeholder content for fv3.rst
mcgibbon 3ba958c
add placeholder content to testing.rst
mcgibbon 5279dfd
unify newline style of sphinx docs
mcgibbon e5129b7
add requirements for doctest, fix existing doctests for transpose
mcgibbon c53aa4b
add documentation on communication
mcgibbon 646ddc9
add doctest to circleci
mcgibbon c7b4071
enable doctest plan
mcgibbon ef0dcf1
update submodules when doctest
mcgibbon b6e578a
remove non-existent doc requirement
mcgibbon 28e10dc
use central mpi env esetup for doctest
mcgibbon 80375f1
install doc requirements for doctest
mcgibbon a2c412b
put linting on small resource
mcgibbon b68a24f
response to review comments
mcgibbon 6429b72
fix mypy errors for gt4py objects
mcgibbon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
.. highlight:: shell | ||
|
||
====== | ||
Docker | ||
====== | ||
|
||
While it is possible to install and build pace bare-metal, we can ensure all system libraries are installed with the correct versions by using a Docker container to test and develop pace. | ||
This requires you have Docker installed (we recommend `Docker Desktop`_ for most users). | ||
You may need to increase memory allocated to Docker in its settings. | ||
|
||
Before building the Docker image, you will need to update the git submodules so that any dependencies are cloned and at the correct version: | ||
|
||
.. code-block:: console | ||
|
||
$ git submodule update --init --recursive | ||
|
||
Then build the `pace` docker image at the top level: | ||
|
||
.. code-block:: console | ||
|
||
$ make build | ||
|
||
.. _`Docker Desktop`: https://www.docker.com/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
=== | ||
FV3 | ||
=== | ||
|
||
This page will include general historical information about FV3, including external links to docs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
.. highlight:: shell | ||
|
||
============ | ||
Installation | ||
============ | ||
|
||
Shell scripts to install Pace on specific machines such as Gaea can be found in `examples/build_scripts/`. | ||
|
||
When cloning Pace you will need to update the repository's submodules as well: | ||
|
||
.. code-block:: console | ||
|
||
$ git clone --recursive https://github.com/ai2cm/pace.git | ||
|
||
or if you have already cloned the repository: | ||
|
||
.. code-block:: console | ||
|
||
$ git submodule update --init --recursive | ||
|
||
|
||
Pace requires GCC > 9.2, MPI, and Python 3.8 on your system, and CUDA is required to run with a GPU backend. | ||
You will also need the headers of the boost libraries in your `$PATH` (boost itself does not need to be installed). | ||
|
||
.. code-block:: console | ||
|
||
$ cd BOOST/ROOT | ||
$ wget https://boostorg.jfrog.io/artifactory/main/release/1.79.0/source/boost_1_79_0.tar.gz | ||
$ tar -xzf boost_1_79_0.tar.gz | ||
$ mkdir -p boost_1_79_0/include | ||
$ mv boost_1_79_0/boost boost_1_79_0/include/ | ||
$ export BOOST_ROOT=BOOST/ROOT/boost_1_79_0 | ||
|
||
|
||
We recommend creating a python `venv` or conda environment specifically for Pace. | ||
|
||
.. code-block:: console | ||
|
||
$ python3 -m venv venv_name | ||
$ source venv_name/bin/activate | ||
|
||
Inside of your pace `venv` or conda environment pip install the Python requirements, GT4Py, and Pace: | ||
|
||
.. code-block:: console | ||
$ pip3 install -r requirements_dev.txt -c constraints.txt | ||
|
||
There are also separate requirements files which can be installed for linting (`requirements_lint.txt`) and building documentation (`requirements_docs.txt`). |
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
======= | ||
Testing | ||
======= | ||
|
||
This page will include instructions on how to run our tests and manage test data. |
File renamed without changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
.. _communication: | ||
|
||
============= | ||
Communication | ||
============= | ||
|
||
As mentioned when discussing :ref:`State`, each process or "rank" on a cubed sphere is responsible for a subset of the cubed sphere grid. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reference to State is not showing up when I build it locally, is something missing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, fixed by adding manual anchors to the missing pages. |
||
In order to operate, the model needs to know how to partition that cubed sphere into parts for each rank, and to be able to communicate data between those ranks. | ||
|
||
Partitioning is managed by so-called "Partitioner" objects. | ||
The :py:class:`pace.util.CubedSpherePartitioner` manages the entire cubed sphere, while the :py:class:`pace.util.TilePartitioner` manages one of the six faces of the cube, or a region on one of those faces. | ||
For communication, we similarly have :py:class:`pace.util.CubedSphereCommunicator` and :py:class:`pace.util.TileCommunicator`. | ||
Please see their API documentation for an up-to-date list of current communications routines. | ||
|
||
Halo Updates | ||
------------ | ||
|
||
Let's walk through a detailed example where we create everything we need to perform halo updates on a cubed sphere, to get a feel for the responsibilities of all involved classes. Here we assume that you already know what halo updates are and how data is partitioned in memory-parallel earth system models. If not, there is a (very brief) explanation in the :ref:`State` section, or we recommend searching for information on the "Ghost Cell Pattern" or "Halo Exchange". | ||
|
||
TilePartitioner | ||
~~~~~~~~~~~~~~~ | ||
|
||
First, we create a :py:class:`pace.util.TilePartitioner` object: | ||
|
||
.. doctest:: | ||
|
||
>>> import pace.util | ||
>>> partitioner = pace.util.TilePartitioner(layout=(1, 1)) | ||
|
||
This partitioner will be responsible for partitioning the data on a single face of the cubed sphere into a single tile. | ||
The :py:attr:`pace.util.TilePartitioner.layout` attribute is a tuple of two integers, which specifies how many ranks (processors) to partition the cubed sphere into in the :math:`x` and :math:`y` directions. | ||
For a (1, 1) layout, only one rank will be responsible for each tile face. | ||
|
||
.. doctest:: | ||
|
||
>>> partitioner.layout | ||
(1, 1) | ||
>>> partitioner.total_ranks | ||
1 | ||
|
||
The :py:class:`pace.util.TilePartitioner` object is a concrete implementation of the :py:class:`pace.util.Partitioner` abstract base class. Partitioners are responsible for telling us how data on a global model domain is partitioned between ranks, given information about the shapes of the global or local domain and staggering of the data. They do not themselves store this information, meaning the same partitioner can be used to partition data at varying resolutions or with different grid staggering. | ||
|
||
Boundary | ||
~~~~~~~~ | ||
|
||
Within the halo update code, a very important feature of the partitioner is the method :py:meth:`pace.util.Partitioner.boundary`, which returns a :py:class:`pace.util.Boundary` object: | ||
|
||
.. doctest:: | ||
|
||
>>> boundary = partitioner.boundary(pace.util.EAST, rank=0) | ||
>>> boundary | ||
SimpleBoundary(from_rank=0, to_rank=0, n_clockwise_rotations=0, boundary_type=1) | ||
|
||
Boundary objects are responsible for describing the boundary between two neighboring ranks, and can tell us what part of a rank's data is on the boundary through its :py:meth:`pace.util.Boundary.send_view` method, and where the neighboring rank's data belongs in the local halo through its :py:meth:`pace.util.Boundary.recv_view` method. As a user you generally will not need to interact with Boundary objects, but they are important to understand if you need to modify or extend the communication code. | ||
|
||
.. note:: | ||
The :py:meth:`pace.util.Partitioner.boundary` method will need to be refactored in the future to support non-square layouts. | ||
The method currently assumes that for a given direction there will be one rank in that direction, but this is not true for tile edges in non-square layouts, and this assumption is not required elsewhere in the code. | ||
Likely the method should be refactored into one that returns an iterable of all boundaries for a given rank. | ||
|
||
Quantity | ||
~~~~~~~~ | ||
|
||
To see how the boundary and other objects operate, we will need some data to operate on. We use a :py:class:`pace.util.Quantity` object to store the data and all required information about its staggering and halo data: | ||
|
||
.. doctest:: | ||
|
||
>>> import numpy as np | ||
>>> quantity = pace.util.Quantity( | ||
... data=np.zeros((6, 6)), | ||
... dims=[pace.util.X_DIM, pace.util.Y_DIM], | ||
... units="m", | ||
... origin=(1, 1), | ||
... extent=(4, 4), | ||
... ) | ||
|
||
This creates a cell-centered Quantity with 8x8x6 data points, and 2 halo points in each direction. | ||
The :py:attr:`pace.util.Quantity.view` attribute provides convenient indexing into the compute domain. | ||
We can see the extent (size) of the compute domain described by the extent of the quantity: | ||
|
||
.. doctest:: | ||
|
||
>>> quantity.view[:].shape | ||
(4, 4) | ||
>>> quantity.extent | ||
(4, 4) | ||
|
||
Given a Quantity, the Boundary object can tell us where the data on the boundary is located: | ||
|
||
.. doctest:: | ||
|
||
>>> quantity.view[:] = np.arange(4)[None, :] + np.arange(0, 40, 10)[:, None] | ||
>>> quantity.data[:] | ||
array([[ 0., 0., 0., 0., 0., 0.], | ||
[ 0., 0., 1., 2., 3., 0.], | ||
[ 0., 10., 11., 12., 13., 0.], | ||
[ 0., 20., 21., 22., 23., 0.], | ||
[ 0., 30., 31., 32., 33., 0.], | ||
[ 0., 0., 0., 0., 0., 0.]]) | ||
>>> boundary.send_slice(quantity.halo_spec(n_halo=1)) | ||
(slice(4, 5, None), slice(1, 5, None)) | ||
>>> quantity.data[boundary.send_slice(quantity.halo_spec(n_halo=1))] | ||
array([[30., 31., 32., 33.]]) | ||
>>> boundary.recv_slice(quantity.halo_spec(n_halo=1)) | ||
(slice(5, 6, None), slice(1, 5, None)) | ||
|
||
.. note:: | ||
Boundary also has some older :py:meth:`pace.util.Boundary.send_view` and :py:meth:`pace.util.Boundary.recv_view` methods which provide similar functionality. | ||
The original halo update code used these, while a newer pathway that involves building a HaloUpdater and pre-compiling some efficient kernels for data packing uses the "slice" methods. | ||
|
||
Comm | ||
~~~~ | ||
|
||
We've established some objects for containing data and how it is partitioned, but we still need to actually perform the communication. | ||
The low-level object responsible for this is the :py:class:`pace.util.Comm` abstract base class. | ||
This mirrors the comm object provided by the `mpi4py`_ package, which is a thin wrapper over MPI. | ||
There are multiple Comm classes available. | ||
Under normal circumstances when running a parallel model you will want to use a :py:class:`pace.util.MPIComm` object, which is a wrapper around an `mpi4py`_ communicator: | ||
|
||
.. doctest:: | ||
|
||
>>> import pace.util | ||
>>> comm = pace.util.MPIComm() | ||
>>> comm | ||
<pace.util.mpi.MPIComm object at 0x...> | ||
>>> comm.Get_rank() | ||
0 | ||
>>> comm.Get_size() | ||
1 | ||
|
||
However this documentation is unit tested, and when it's unit tested it's run on only one rank. | ||
For this reason, many of our tests use the :py:class:`pace.util.NullComm` object, which is a fake communicator that pretends to be an MPI communicator but does not actually perform any communication: | ||
|
||
.. doctest:: | ||
|
||
>>> comm = pace.util.NullComm(rank=0, total_ranks=6) | ||
>>> comm | ||
NullComm(rank=0, total_ranks=6) | ||
>>> comm.Get_rank() | ||
0 | ||
>>> comm.Get_size() | ||
6 | ||
|
||
This is very useful for testing code that relies on multi-rank communication without actually running a parallel model, at the expense of not being able to rely on or test the numerical values being output. | ||
Keep this in mind below, where we will avoid showing output values after halo updates because the NullComm cannot actually update them. | ||
|
||
.. note:: | ||
It is possible to update :py:class:`pace.util.LocalComm` so that it could show a true halo update on one rank, but this is not currently implemented. | ||
The halo update code currently relies on an assumption that only one boundary exists between any pair of ranks, which is not true for a periodic domain with anything less than a 3x3 tile layout. | ||
If this does get implemented, this example should be updated (at least for the tile communication case). | ||
|
||
TileCommunicator | ||
~~~~~~~~~~~~~~~~ | ||
|
||
Halo updates and other communication is performed by the :py:class:`pace.util.Communicator` abstract base class. | ||
Code that relies only on the abstract base class should be able to run on any Communicator, including both the :py:class:`TileCommunicator`` which provides a single doubly-periodic tile, or the :py:class:`pace.util.CubedSphereCommunicator`` which provides a cubed sphere decomposition. | ||
We'll start with the single-tile case. | ||
|
||
.. doctest:: | ||
|
||
>>> comm = pace.util.NullComm(rank=0, total_ranks=9) | ||
>>> partitioner = pace.util.TilePartitioner(layout=(3, 3)) | ||
>>> tile_communicator = pace.util.TileCommunicator(comm, partitioner) | ||
|
||
With all of these objects in place, we can perform an in-place halo update: | ||
|
||
.. doctest:: | ||
|
||
>>> tile_communicator.halo_update(quantity, n_points=1) | ||
|
||
An asynchronous halo update can also be performed: | ||
|
||
.. doctest:: | ||
|
||
>>> request = tile_communicator.start_halo_update(quantity, n_points=1) | ||
>>> request.wait() | ||
|
||
The communicator provides other communication routines, including scatter/gather and a routine to synchronize interface data computed on both ranks neighboring a boundary. | ||
|
||
CubedSphereCommunicator | ||
~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
The :py:class:`pace.util.CubedSphereCommunicator` provides a cubed sphere decomposition of the sphere. | ||
It is used identically to the TileCommunicator, which is by design so that the same code can be used for both decompositions. | ||
|
||
.. doctest:: | ||
|
||
>>> comm = pace.util.NullComm(rank=0, total_ranks=54) | ||
>>> partitioner = pace.util.CubedSpherePartitioner( | ||
... pace.util.TilePartitioner(layout=(3, 3)) | ||
... ) | ||
>>> communicator = pace.util.CubedSphereCommunicator(comm, partitioner) | ||
>>> communicator.halo_update(quantity, n_points=1) | ||
|
||
The :py:class:`pace.util.CubedSpherePartitioner` is a wrapper around a :py:class:`pace.util.TilePartitioner` that provides a cubed sphere decomposition. | ||
Within its implementation, it relies entirely on the TilePartitioner to describe how data is partitioned within any given tile, and only imposes constraints on how tiles are ordered and connected to each other. | ||
|
||
.. _mpi4py: https://mpi4py.readthedocs.io/en/stable/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
========= | ||
Changelog | ||
========= | ||
|
||
.. include:: ../HISTORY.md |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we also mention installing lint and docs with just different requirement name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.