-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updates to documentation: add demo page and update basic usage guide
- Loading branch information
Ashwin Srinath
committed
Jul 7, 2018
1 parent
1a1f36c
commit 3b31f04
Showing
50 changed files
with
3,729 additions
and
171 deletions.
There are no files selected for viewing
This file contains 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
Binary file not shown.
This file contains 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,242 @@ | ||
Basic Usage | ||
=========== | ||
|
||
Initializing and finalizing pyamgx | ||
---------------------------------- | ||
|
||
The :py:func:`~pyamgx.initialize` and :py:func:`~pyamgx.finalize` functions | ||
**must** be called to initialize and finalize the library respectively. | ||
|
||
.. code-block:: python | ||
import pyamgx | ||
pyamgx.initialize() | ||
# use pyamgx | ||
pyamgx.finalize() | ||
Config objects | ||
-------------- | ||
|
||
:py:class:`~pyamgx.Config` objects are used to store configuration settings | ||
for the linear solver used, including | ||
algorithm, preconditioner(s), smoother(s) and associated parameters. | ||
|
||
:py:class:`~pyamgx.Config` objects can be constructed from | ||
JSON files or :py:class:`dict` objects. | ||
|
||
As an example, the :py:class:`~pyamgx.Config` object below | ||
represents the configuration for a BICGSTAB solver | ||
without preconditioning, and is constructed using | ||
the :py:meth:`~pyamgx.Config.create_from_dict` method: | ||
|
||
.. code-block:: python | ||
cfg = pyamgx.Config() | ||
cfg.create_from_dict({ | ||
"config_version": 2, | ||
"determinism_flag": 1, | ||
"exception_handling" : 1, | ||
"solver": { | ||
"monitor_residual": 1, | ||
"solver": "BICGSTAB", | ||
"convergence": "RELATIVE_INI_CORE", | ||
"preconditioner": { | ||
"solver": "NOSOLVER" | ||
} | ||
} | ||
}) | ||
Examples of more complex configurations can be found | ||
`here <https://github.com/NVIDIA/AMGX/tree/master/core/configs>`_, | ||
and a description of all configuration settings can be found in the | ||
AMGX Reference Guide. | ||
|
||
The :py:meth:`~pyamgx.Config.create_from_file` method can be used | ||
to read configuration settings from a JSON file instead: | ||
|
||
.. code-block:: python | ||
cfg = pyamgx.Config() | ||
cfg.create_from_file('/path/to/GMRES.json') | ||
After use, :py:class:`~pyamgx.Config` objects **must** be destroyed using the | ||
:py:meth:`~pyamgx.Config.destroy` method. | ||
|
||
.. code-block:: python | ||
cfg.destroy() | ||
Resources objects | ||
----------------- | ||
|
||
:py:class:`~pyamgx.Resources` objects are used to specify the resources | ||
(GPUs, MPI ranks) used by :py:class:`~pyamgx.Vector`, :py:class:`~pyamgx.Matrix` | ||
and :py:class:`~pyamgx.Solver` objects. | ||
Currently, pyamgx only supports "simple" :py:class:`~pyamgx.Resources` objects for | ||
single threaded, single GPU applications. | ||
created using the :py:meth:`~pyamgx.Resources.create_simple` method: | ||
|
||
.. code-block:: python | ||
resources = pyamgx.Resources() | ||
resources.create_simple(cfg) | ||
After use, :py:class:`~pyamgx.Resources` objects **must** be destroyed using the | ||
:py:meth:`~pyamgx.Resources.destroy` method. | ||
|
||
.. code-block:: python | ||
resources.destroy() | ||
.. important:: | ||
|
||
A :py:class:`~pyamgx.Resources` object should be destroyed only **after** | ||
all :py:class:`~pyamgx.Vector`, :py:class:`~pyamgx.Matrix` and :py:class:`~pyamgx.Solver` | ||
objects constructed from it are destroyed. | ||
|
||
Vectors | ||
------- | ||
|
||
:py:class:`~pyamgx.Vector` objects store vectors on | ||
either the host (CPU memory) or device (GPU memory). | ||
|
||
The value of the optional `mode` argument to the :py:meth:`~pyamgx.Vector.create` method | ||
specifies whether the data resides on the host or device. | ||
If it is ``'dDDI'`` (default), the data resides on the device. | ||
If it is ``'hDDI'``, the data resides on the host. | ||
|
||
.. code-block:: python | ||
vec = pyamgx.Vector() | ||
vec.create(resources, mode='dDDI') | ||
Values of :py:class:`~pyamgx.Vector` objects can be populated | ||
in the following ways: | ||
|
||
1. From an array using the :py:meth:`~pyamgx.Vector.upload` method | ||
|
||
.. code-block:: python | ||
vec.upload(np.array([1, 2, 3], dtype=np.float64)) | ||
2. Using the :py:meth:`~pyamgx.Vector.set_zero` method | ||
|
||
.. code-block:: python | ||
vec.set_zero(5) # implicitly allocates storage for the vector | ||
3. From a raw pointer using the :py:meth:`~pyamgx.Vector.upload_raw` method. | ||
This allows uploading values from arrays already on the GPU, | ||
for instance from :py:class:`numba.cuda.device_array` objects. | ||
|
||
.. code-block:: python | ||
import numba.cuda | ||
a = np.array([1, 2, 3], dtype=np.float64) | ||
d_a = numba.cuda.to_device(a, dtype=np.float64)) | ||
vec.upload_raw(d_a.device_ctypes_pointer.value, 3) # copies directly from GPU | ||
After use, :py:class:`~pyamgx.Vector` objects **must** be destroyed using the | ||
:py:meth:`~pyamgx.Vector.destroy` method. | ||
|
||
Matrices | ||
-------- | ||
|
||
:py:class:`~pyamgx.Matrix` objects store sparse matrices on | ||
either the host (CPU memory) or device (GPU memory). | ||
|
||
The value of the optional `mode` argument to the :py:meth:`~pyamgx.Matrix.create` method | ||
specifies whether the data resides on the host or device. | ||
If it is ``'dDDI'`` (default), the data resides on the device. | ||
If it is ``'hDDI'``, the data resides on the host. | ||
|
||
.. code-block:: python | ||
mat = pyamgx.Matrix() | ||
mat.create(resources, mode='dDDI') | ||
:py:class:`~pyamgx.Matrix` objects store matrices | ||
in the `CSR`_ sparse format. | ||
|
||
Matrix data can be copied into the :py:class:`~pyamgx.Matrix` | ||
object in the following ways: | ||
|
||
1. From the arrays *row_ptrs*, *col_indices* and *data* that define | ||
the CSR matrix, using the :py:meth:`~pyamgx.Matrix.upload` method: | ||
|
||
.. code-block:: python | ||
mat.upload( | ||
row_ptrs=np.array([0, 2, 4], dtype=np.int32), | ||
col_indices=np.array([0, 1, 0, 1], dtype=np.int32), | ||
data=np.array([1., 2., 3., 4.], dtype=np.float64)) | ||
2. From a :py:class:`scipy.sparse.csr_matrix`, | ||
using the :py:meth:`~pyamgx.Matrix.upload_CSR` method: | ||
|
||
.. code-block:: python | ||
import scipy.sparse | ||
M = scipy.sparse.csr_matrix(np.random.rand(5, 5)) | ||
mat.upload_CSR(M) | ||
.. _CSR: https://en.wikipedia.org/wiki/Sparse_matrix#Compressed_sparse_row_(CSR,_CRS_or_Yale_format) | ||
|
||
After use, :py:class:`~pyamgx.Matrix` objects **must** be destroyed using the | ||
:py:meth:`~pyamgx.Matrix.destroy` method. | ||
|
||
Solvers | ||
------- | ||
|
||
A :py:class:`~pyamgx.Solver` encapsulates the linear solver specified | ||
in the :py:class:`~pyamgx.Config` object. | ||
|
||
The :py:meth:`~pyamgx.Solver.setup` method, | ||
must be called prior to solving a linear system; | ||
it sets the coefficient matrix of the linear system: | ||
|
||
.. code-block:: python | ||
solver = pyamgx.Solver() | ||
solver.create(resources, cfg) | ||
solver.setup(mat) | ||
The :py:meth:`~pyamgx.Solver.solve` method solves the linear system. | ||
The two required parameters to :py:meth:`~pyamgx.Solver.solve` | ||
the right hand side :py:class:`~pyamgx.Vector` `b` and | ||
the solution vector :py:class:`~pyamgx.Vector` `x` | ||
respectively. | ||
The optional argument `zero_initial_guess` can be set to ``True`` to specify | ||
that an initial guess of zero is to be used for the solution, | ||
regardless of the values in `x`. | ||
|
||
.. code-block:: python | ||
b = pyamgx.Vector().create(resources) | ||
x = pyamgx.Vector().create(resources) | ||
b.upload(np.random.rand(5)) | ||
solver.solve(b, x, zero_initial_guess=True) | ||
After use, :py:class:`~pyamgx.Solver` objects **must** be destroyed using the | ||
:py:meth:`~pyamgx.Solver.destroy` method. | ||
|
||
Typically, the :py:meth:`pyamgx.Solver.solve` method is called multiple times | ||
(e.g., in a time-stepping simulation loop). | ||
For the case in which the coefficient matrix remains fixed, | ||
the :py:meth:`pyamgx.Solver.setup` method should only be called once | ||
(prior to iteration). | ||
|
||
If the coefficient matrix changes | ||
at each iteration (e.g., in a non-linear solver), | ||
the :py:meth:`pyamgx.Solver.setup` method should be called every iteration. | ||
In this case, the :py:meth:`pyamgx.Matrix.replace_coefficients` method | ||
can be used to update the values of the coefficient matrix, | ||
as long as the location of non-zeros in the matrix remains the same. | ||
|
This file contains 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 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,81 @@ | ||
Demo | ||
==== | ||
|
||
To give you an idea of pyamgx usage, | ||
here is a simple demo program that sets up and solves a linear system | ||
using pyamgx, and compares the result with | ||
:py:func:`scipy.sparse.linalg.spsolve` | ||
|
||
.. code-block:: python | ||
import os | ||
import numpy as np | ||
import scipy.sparse as sparse | ||
import scipy.sparse.linalg as splinalg | ||
import pyamgx | ||
pyamgx.initialize() | ||
# Initialize config and resources: | ||
cfg = pyamgx.Config().create_from_dict({ | ||
"config_version": 2, | ||
"determinism_flag": 1, | ||
"exception_handling" : 1, | ||
"solver": { | ||
"monitor_residual": 1, | ||
"solver": "BICGSTAB", | ||
"convergence": "RELATIVE_INI_CORE", | ||
"preconditioner": { | ||
"solver": "NOSOLVER" | ||
} | ||
} | ||
}) | ||
rsc = pyamgx.Resources().create_simple(cfg) | ||
# Create matrices and vectors: | ||
A = pyamgx.Matrix().create(rsc) | ||
b = pyamgx.Vector().create(rsc) | ||
x = pyamgx.Vector().create(rsc) | ||
# Create solver: | ||
solver = pyamgx.Solver().create(rsc, cfg) | ||
# Upload system: | ||
M = sparse.csr_matrix(np.random.rand(5, 5)) | ||
rhs = np.random.rand(5) | ||
sol = np.zeros(5, dtype=np.float64) | ||
A.upload_CSR(M) | ||
b.upload(rhs) | ||
x.upload(sol) | ||
# Setup and solve system: | ||
solver.setup(A) | ||
solver.solve(b, x) | ||
# Download solution | ||
x.download(sol) | ||
print("pyamgx solution: ", sol) | ||
print("scipy solution: ", splinalg.spsolve(M, rhs)) | ||
# Clean up: | ||
A.destroy() | ||
x.destroy() | ||
b.destroy() | ||
solver.destroy() | ||
rsc.destroy() | ||
cfg.destroy() | ||
pyamgx.finalize() | ||
:: | ||
|
||
AMGX version 2.0.0.130-opensource | ||
Built on Jul 6 2018, 12:08:15 | ||
Compiled with CUDA Runtime 8.0, using CUDA driver 9.2 | ||
pyamgx solution: [-0.90571145 0.85909259 0.54397665 2.02579923 -0.94139638] | ||
scipy solution: [-0.90571145 0.85909259 0.54397665 2.02579923 -0.94139638] |
This file contains 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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Oops, something went wrong.