Skip to content

Commit 42e0e70

Browse files
authored
Add some examples (#76)
1 parent f1d7f0f commit 42e0e70

7 files changed

Lines changed: 817 additions & 13 deletions

File tree

.github/workflows/pytest-petsc.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ jobs:
8080
8181
- name: Test examples
8282
run: |
83-
${{ env.RUN_CMD }} mpiexec -n 1 python3 --cov --cov-config=.coveragerc --cov-report=xml examples/petsc/seismic/staggered_acoustic.py
83+
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/seismic/01_staggered_acoustic.py
84+
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/cfd/01_navierstokes.py
85+
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/Poisson/01_poisson.py
86+
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/Poisson/02_laplace.py
87+
${{ env.RUN_CMD }} mpiexec -n 1 python3 examples/petsc/random/01_helmholtz.py
8488
8589
- name: Upload coverage to Codecov
8690
if: "!contains(matrix.name, 'docker')"

devito/petsc/types/array.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from devito.types.array import ArrayBasic
66
from devito.finite_differences import Differentiable
77
from devito.types.basic import AbstractFunction
8-
from devito.finite_differences.tools import fd_weights_registry
98
from devito.tools import dtype_to_ctype, as_tuple
109
from devito.symbolics import FieldFromComposite
1110

@@ -27,9 +26,6 @@ class PETScArray(ArrayBasic, Differentiable):
2726

2827
_data_alignment = False
2928

30-
# Default method for the finite difference approximation weights computation.
31-
_default_fd = 'taylor'
32-
3329
__rkwargs__ = (AbstractFunction.__rkwargs__ +
3430
('target', 'liveness', 'coefficients', 'localinfo'))
3531

@@ -38,15 +34,8 @@ def __init_finalize__(self, *args, **kwargs):
3834
self._target = kwargs.get('target')
3935
self._ndim = kwargs['ndim'] = len(self._target.space_dimensions)
4036
self._dimensions = kwargs['dimensions'] = self._target.space_dimensions
41-
4237
super().__init_finalize__(*args, **kwargs)
43-
44-
# Symbolic (finite difference) coefficients
45-
self._coefficients = kwargs.get('coefficients', self._default_fd)
46-
if self._coefficients not in fd_weights_registry:
47-
raise ValueError("coefficients must be one of %s"
48-
" not %s" % (str(fd_weights_registry), self._coefficients))
49-
38+
self._coefficients = self._target.coefficients
5039
self._localinfo = kwargs.get('localinfo', None)
5140

5241
@property
@@ -93,6 +82,10 @@ def shape(self):
9382
def space_order(self):
9483
return self.target.space_order
9584

85+
@property
86+
def staggered(self):
87+
return self.target.staggered
88+
9689
@property
9790
def is_Staggered(self):
9891
return self.target.staggered is not None
@@ -113,6 +106,10 @@ def shape_allocated(self):
113106
def _C_ctype(self):
114107
return POINTER(dtype_to_ctype(self.dtype))
115108

109+
@cached_property
110+
def _fd_priority(self):
111+
return self.target._fd_priority
112+
116113
@property
117114
def symbolic_shape(self):
118115
field_from_composites = [
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
import os
2+
import numpy as np
3+
4+
from devito import (Grid, Function, Eq, Operator, switchconfig,
5+
configuration, SubDomain)
6+
7+
from devito.petsc import PETScSolve, EssentialBC
8+
from devito.petsc.initialize import PetscInitialize
9+
configuration['compiler'] = 'custom'
10+
os.environ['CC'] = 'mpicc'
11+
12+
# Solving pn.laplace = 2x(y - 1)(y - 2x + xy + 2)e^(x-y)
13+
# Constant zero Dirichlet BCs.
14+
15+
PetscInitialize()
16+
17+
18+
# Subdomains to implement BCs
19+
class SubTop(SubDomain):
20+
name = 'subtop'
21+
22+
def define(self, dimensions):
23+
x, y = dimensions
24+
return {x: x, y: ('right', 1)}
25+
26+
27+
class SubBottom(SubDomain):
28+
name = 'subbottom'
29+
30+
def define(self, dimensions):
31+
x, y = dimensions
32+
return {x: x, y: ('left', 1)}
33+
34+
35+
class SubLeft(SubDomain):
36+
name = 'subleft'
37+
38+
def define(self, dimensions):
39+
x, y = dimensions
40+
return {x: ('left', 1), y: y}
41+
42+
43+
class SubRight(SubDomain):
44+
name = 'subright'
45+
46+
def define(self, dimensions):
47+
x, y = dimensions
48+
return {x: ('right', 1), y: y}
49+
50+
51+
sub1 = SubTop()
52+
sub2 = SubBottom()
53+
sub3 = SubLeft()
54+
sub4 = SubRight()
55+
56+
subdomains = (sub1, sub2, sub3, sub4)
57+
58+
59+
def analytical(x, y):
60+
return np.float64(np.exp(x-y) * x * (1-x) * y * (1-y))
61+
62+
63+
Lx = np.float64(1.)
64+
Ly = np.float64(1.)
65+
66+
n_values = list(range(13, 174, 10))
67+
dx = np.array([Lx/(n-1) for n in n_values])
68+
errors = []
69+
70+
71+
for n in n_values:
72+
73+
grid = Grid(
74+
shape=(n, n), extent=(Lx, Ly), subdomains=subdomains, dtype=np.float64
75+
)
76+
77+
phi = Function(name='phi', grid=grid, space_order=2, dtype=np.float64)
78+
rhs = Function(name='rhs', grid=grid, space_order=2, dtype=np.float64)
79+
80+
eqn = Eq(rhs, phi.laplace, subdomain=grid.interior)
81+
82+
tmpx = np.linspace(0, Lx, n).astype(np.float64)
83+
tmpy = np.linspace(0, Ly, n).astype(np.float64)
84+
Y, X = np.meshgrid(tmpx, tmpy)
85+
86+
rhs.data[:] = np.float64(
87+
2.0*X*(Y-1.0)*(Y - 2.0*X + X*Y + 2.0)
88+
) * np.float64(np.exp(X-Y))
89+
90+
# # Create boundary condition expressions using subdomains
91+
bcs = [EssentialBC(phi, np.float64(0.), subdomain=sub1)]
92+
bcs += [EssentialBC(phi, np.float64(0.), subdomain=sub2)]
93+
bcs += [EssentialBC(phi, np.float64(0.), subdomain=sub3)]
94+
bcs += [EssentialBC(phi, np.float64(0.), subdomain=sub4)]
95+
96+
exprs = [eqn] + bcs
97+
petsc = PETScSolve(exprs, target=phi, solver_parameters={'ksp_rtol': 1e-8})
98+
99+
with switchconfig(language='petsc'):
100+
op = Operator(petsc)
101+
op.apply()
102+
103+
phi_analytical = analytical(X, Y)
104+
105+
diff = phi_analytical[1:-1, 1:-1] - phi.data[1:-1, 1:-1]
106+
error = np.linalg.norm(diff) / np.linalg.norm(phi_analytical[1:-1, 1:-1])
107+
errors.append(error)
108+
109+
slope, _ = np.polyfit(np.log(dx), np.log(errors), 1)
110+
111+
assert slope > 1.9
112+
assert slope < 2.1
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import os
2+
import numpy as np
3+
4+
from devito import (Grid, Function, Eq, Operator, SubDomain,
5+
configuration, switchconfig)
6+
from devito.petsc import PETScSolve, EssentialBC
7+
from devito.petsc.initialize import PetscInitialize
8+
configuration['compiler'] = 'custom'
9+
os.environ['CC'] = 'mpicc'
10+
11+
PetscInitialize()
12+
13+
# Laplace equation, solving phi.laplace = 0
14+
15+
# Constant Dirichlet BCs:
16+
# phi(x, 0) = 0
17+
# phi(0, y) = 0
18+
# phi(1, y) = 0
19+
# phi(x, 1) = f(x) = sin(pi*x)
20+
21+
# The analytical solution is:
22+
# phi(x, y) = sinh(pi*y)*sin(pi*x)/sinh(pi)
23+
24+
25+
# Subdomains to implement BCs
26+
class SubTop(SubDomain):
27+
name = 'subtop'
28+
29+
def define(self, dimensions):
30+
x, y = dimensions
31+
return {x: x, y: ('right', 1)}
32+
33+
34+
class SubBottom(SubDomain):
35+
name = 'subbottom'
36+
37+
def define(self, dimensions):
38+
x, y = dimensions
39+
return {x: x, y: ('left', 1)}
40+
41+
42+
class SubLeft(SubDomain):
43+
name = 'subleft'
44+
45+
def define(self, dimensions):
46+
x, y = dimensions
47+
return {x: ('left', 1), y: y}
48+
49+
50+
class SubRight(SubDomain):
51+
name = 'subright'
52+
53+
def define(self, dimensions):
54+
x, y = dimensions
55+
return {x: ('right', 1), y: y}
56+
57+
58+
sub1 = SubTop()
59+
sub2 = SubBottom()
60+
sub3 = SubLeft()
61+
sub4 = SubRight()
62+
63+
subdomains = (sub1, sub2, sub3, sub4)
64+
65+
66+
Lx = np.float64(1.)
67+
Ly = np.float64(1.)
68+
69+
70+
def analytical(x, y, Lx, Ly):
71+
tmp = np.float64(np.pi)/Lx
72+
numerator = np.float64(np.sinh(tmp*y)) * np.float64(np.sin(tmp*x))
73+
return numerator / np.float64(np.sinh(tmp*Ly))
74+
75+
76+
n_values = list(range(13, 174, 10))
77+
dx = np.array([Lx/(n-1) for n in n_values])
78+
errors = []
79+
80+
81+
for n in n_values:
82+
83+
grid = Grid(
84+
shape=(n, n), extent=(Lx, Ly), subdomains=subdomains, dtype=np.float64
85+
)
86+
87+
phi = Function(name='phi', grid=grid, space_order=2, dtype=np.float64)
88+
rhs = Function(name='rhs', grid=grid, space_order=2, dtype=np.float64)
89+
90+
phi.data[:] = np.float64(0.0)
91+
rhs.data[:] = np.float64(0.0)
92+
93+
eqn = Eq(rhs, phi.laplace, subdomain=grid.interior)
94+
95+
tmpx = np.linspace(0, Lx, n).astype(np.float64)
96+
tmpy = np.linspace(0, Ly, n).astype(np.float64)
97+
Y, X = np.meshgrid(tmpx, tmpy)
98+
99+
# Create boundary condition expressions using subdomains
100+
bc_func = Function(name='bcs', grid=grid, space_order=2, dtype=np.float64)
101+
bc_func.data[:] = np.float64(0.0)
102+
bc_func.data[:, -1] = np.float64(np.sin(tmpx*np.pi))
103+
104+
bcs = [EssentialBC(phi, bc_func, subdomain=sub1)] # top
105+
bcs += [EssentialBC(phi, bc_func, subdomain=sub2)] # bottom
106+
bcs += [EssentialBC(phi, bc_func, subdomain=sub3)] # left
107+
bcs += [EssentialBC(phi, bc_func, subdomain=sub4)] # right
108+
109+
exprs = [eqn] + bcs
110+
petsc = PETScSolve(exprs, target=phi, solver_parameters={'ksp_rtol': 1e-8})
111+
112+
with switchconfig(language='petsc'):
113+
op = Operator(petsc)
114+
op.apply()
115+
116+
phi_analytical = analytical(X, Y, Lx, Ly)
117+
118+
diff = phi_analytical[1:-1, 1:-1] - phi.data[1:-1, 1:-1]
119+
error = np.linalg.norm(diff) / np.linalg.norm(phi_analytical[1:-1, 1:-1])
120+
errors.append(error)
121+
122+
slope, _ = np.polyfit(np.log(dx), np.log(errors), 1)
123+
124+
assert slope > 1.9
125+
assert slope < 2.1

0 commit comments

Comments
 (0)