# Firedrake Offloading TODO
## Tests
- [ ] Mixed FS
- Example:
<details>
```python
from firedrake import *
from pyop2.backends.cpu import cpu_backend
import firedrake_configuration
# ~ AVAILABLE_BACKENDS = [cpu_backend]
firedrake_config = firedrake_configuration.get_config()
if firedrake_config["options"].get("cuda"):
from pyop2.backends.cuda import cuda_backend
# ~ AVAILABLE_BACKENDS.append(cuda_backend)
offloading_backend = cuda_backend
elif firedrake_config["options"].get("opencl"):
from pyop2.backends.opencl import opencl_backend
# ~ AVAILABLE_BACKENDS.append(opencl_backend)
offloading_backend = opencl_backend
else:
offloading_backend = cpu_backend
set_offloading_backend(offloading_backend)
baseN = 4
nref = 3
degree = 1
mesh = UnitCubeMesh(baseN, baseN, baseN)
hierarchy = MeshHierarchy(mesh, nref)
mesh = hierarchy[-1]
# LBB stable FEM pair?
Sigma = FunctionSpace(mesh, "RT", degree)
V = FunctionSpace(mesh, "DG", degree - 1)
W = Sigma * V
sigma, u = TrialFunctions(W)
tau, v = TestFunctions(W)
x, y, z = SpatialCoordinate(mesh)
# ~ f = 10*exp(-100*((x - 0.5)**2 + (y - 0.5)**2))
simplerhs = True
if simplerhs:
# Very simple RHS
k = [Constant(1.0), Constant(1.0), Constant(1.0)]
exact = sin(k[0]*pi*x)*sin(k[1]*pi*y)*sin(k[2]*pi*z)
f = ((k[0]**2 + k[1]**2 + k[2]**2)*(pi**2))*exact
else:
# Less simple RHS
a = Constant(1)
b = Constant(2)
exact = sin(pi*x)*tan(pi*x/4)*sin(a*pi*y)*sin(b*pi*z)
f = -pi**2 / 2
f *= 2*cos(pi*x) - cos(pi*x/2) - 2*(a**2 + b**2)*sin(pi*x)*tan(pi*x/4)
f *= sin(a*pi*y)*sin(b*pi*z)
w_h = Function(W)
solver_parameters = {
"pc_type": "none",
"ksp_type": "minres",
"ksp_monitor": None
}
with offloading():
a = assemble(dot(sigma, tau)*dx + div(tau)*u*dx + div(sigma)*v*dx, mat_type="matfree")
L = assemble(-f*v*dx)
solve(a, w_h, L, solver_parameters=solver_parameters)
sigma_h, u_h = w_h.subfunctions
print(f"Norm on GPU: {errornorm(exact, u_h)}")
sigma_h, u_h = w_h.subfunctions
print(f"Norm on CPU: {errornorm(exact, u_h)}")
```
</details>
- [ ] Dirichlet BCs
- Example:
<details>
```python
from firedrake import *
from pyop2.backends.cpu import cpu_backend
import firedrake_configuration
# ~ AVAILABLE_BACKENDS = [cpu_backend]
firedrake_config = firedrake_configuration.get_config()
if firedrake_config["options"].get("cuda"):
from pyop2.backends.cuda import cuda_backend
# ~ AVAILABLE_BACKENDS.append(cuda_backend)
offloading_backend = cuda_backend
elif firedrake_config["options"].get("opencl"):
from pyop2.backends.opencl import opencl_backend
# ~ AVAILABLE_BACKENDS.append(opencl_backend)
offloading_backend = opencl_backend
else:
offloading_backend = cpu_backend
set_offloading_backend(offloading_backend)
baseN = 4
nref = 2
degree = 1
mesh = BoxMesh(baseN, baseN, baseN, 1, 1, 1)
hierarchy = MeshHierarchy(mesh, nref)
mesh = hierarchy[-1]
V = FunctionSpace(mesh, "CG", degree)
dofs = V.dim()
print('DOFs', dofs)
u = TrialFunction(V)
v = TestFunction(V)
bcs = DirichletBC(V, zero(), (1, 2, 3, 4, 5, 6))
x, y, z = SpatialCoordinate(mesh)
simplerhs = True
if simplerhs:
# Very simple RHS
k = [Constant(1.0), Constant(1.0), Constant(1.0)]
exact = sin(k[0]*pi*x)*sin(k[1]*pi*y)*sin(k[2]*pi*z)
f = ((k[0]**2 + k[1]**2 + k[2]**2)*(pi**2))*exact
else:
# Less simple RHS
a = Constant(1)
b = Constant(2)
exact = sin(pi*x)*tan(pi*x/4)*sin(a*pi*y)*sin(b*pi*z)
f = -pi**2 / 2
f *= 2*cos(pi*x) - cos(pi*x/2) - 2*(a**2 + b**2)*sin(pi*x)*tan(pi*x/4)
f *= sin(a*pi*y)*sin(b*pi*z)
u_h = Function(V)
solver_parameters = {
"pc_type": "none",
"ksp_type": "cg",
"ksp_monitor": None
}
a = assemble(dot(grad(u), grad(v))*dx, bcs=bcs, mat_type="matfree")
with offloading():
L = assemble(f*v*dx)
solve(a, u_h, L, solver_parameters=solver_parameters)
print(f"Norm on GPU: {errornorm(exact, u_h)}")
print(f"Norm on CPU: {errornorm(exact, u_h)}")
```
</details>
- [ ] Parallel with multiple GPUs
## Suggestions in PR
- [ ] Use `compile_on_disk` that returns a callable object with the grid sizes baked in.
(Connor: this overlaps a lot with the big `MirroredArray` refactor so I'd like to implement this after that's done)
- [ ] Mirrored Arrays
- [x] petscvec state management
- [x] `MirroredArray.data` SHOULD return backend relevant ndarray.
- Maybe lazy allocation of the (Connor: huh?)
- [ ] Kaushik: get this into the `gpu` branch and passing tests for the different backends
## Backburner
- [ ] Additional copies in `ImplicitMatrix.mult`
- [ ] GMG prolongation
- [ ] Test suite modification for GPUs (Connor)