Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
G
grudge
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Alexandru Fikl
grudge
Commits
f5433100
Commit
f5433100
authored
4 years ago
by
Andreas Klöckner
Browse files
Options
Downloads
Patches
Plain Diff
Eager interface: implement MPI communication, add example
parent
58b8d1d3
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
examples/wave/wave-eager-mpi.py
+206
-0
206 additions, 0 deletions
examples/wave/wave-eager-mpi.py
grudge/eager.py
+89
-8
89 additions, 8 deletions
grudge/eager.py
with
295 additions
and
8 deletions
examples/wave/wave-eager-mpi.py
0 → 100644
+
206
−
0
View file @
f5433100
from
__future__
import
division
,
print_function
__copyright__
=
"
Copyright (C) 2020 Andreas Kloeckner
"
__license__
=
"""
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the
"
Software
"
), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED
"
AS IS
"
, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
"""
import
numpy
as
np
import
numpy.linalg
as
la
# noqa
import
pyopencl
as
cl
from
pytools.obj_array
import
flat_obj_array
,
make_obj_array
from
meshmode.array_context
import
PyOpenCLArrayContext
from
meshmode.dof_array
import
thaw
from
meshmode.mesh
import
BTAG_ALL
,
BTAG_NONE
# noqa
from
grudge.eager
import
(
EagerDGDiscretization
,
interior_trace_pair
,
cross_rank_trace_pairs
)
from
grudge.shortcuts
import
make_visualizer
from
grudge.symbolic.primitives
import
TracePair
from
mpi4py
import
MPI
# {{{ wave equation bits
def
wave_flux
(
discr
,
c
,
w_tpair
):
u
=
w_tpair
[
0
]
v
=
w_tpair
[
1
:]
normal
=
thaw
(
u
.
int
.
array_context
,
discr
.
normal
(
w_tpair
.
dd
))
def
normal_times
(
scalar
):
# workaround for object array behavior
return
make_obj_array
([
ni
*
scalar
for
ni
in
normal
])
flux_weak
=
flat_obj_array
(
np
.
dot
(
v
.
avg
,
normal
),
normal_times
(
u
.
avg
),
)
# upwind
v_jump
=
np
.
dot
(
normal
,
v
.
int
-
v
.
ext
)
flux_weak
-=
flat_obj_array
(
0.5
*
(
u
.
int
-
u
.
ext
),
0.5
*
normal_times
(
v_jump
),
)
return
discr
.
interp
(
w_tpair
.
dd
,
"
all_faces
"
,
c
*
flux_weak
)
def
wave_operator
(
discr
,
c
,
w
):
u
=
w
[
0
]
v
=
w
[
1
:]
dir_u
=
discr
.
interp
(
"
vol
"
,
BTAG_ALL
,
u
)
dir_v
=
discr
.
interp
(
"
vol
"
,
BTAG_ALL
,
v
)
dir_bval
=
flat_obj_array
(
dir_u
,
dir_v
)
dir_bc
=
flat_obj_array
(
-
dir_u
,
dir_v
)
return
(
discr
.
inverse_mass
(
flat_obj_array
(
c
*
discr
.
weak_div
(
v
),
c
*
discr
.
weak_grad
(
u
)
)
-
# noqa: W504
discr
.
face_mass
(
wave_flux
(
discr
,
c
=
c
,
w_tpair
=
interior_trace_pair
(
discr
,
w
))
+
wave_flux
(
discr
,
c
=
c
,
w_tpair
=
TracePair
(
BTAG_ALL
,
dir_bval
,
dir_bc
))
+
sum
(
wave_flux
(
discr
,
c
=
c
,
w_tpair
=
tpair
)
for
tpair
in
cross_rank_trace_pairs
(
discr
,
w
))
)
)
)
# }}}
def
rk4_step
(
y
,
t
,
h
,
f
):
k1
=
f
(
t
,
y
)
k2
=
f
(
t
+
h
/
2
,
y
+
h
/
2
*
k1
)
k3
=
f
(
t
+
h
/
2
,
y
+
h
/
2
*
k2
)
k4
=
f
(
t
+
h
,
y
+
h
*
k3
)
return
y
+
h
/
6
*
(
k1
+
2
*
k2
+
2
*
k3
+
k4
)
def
bump
(
discr
,
actx
,
t
=
0
):
source_center
=
np
.
array
([
0.2
,
0.35
,
0.1
])[:
discr
.
dim
]
source_width
=
0.05
source_omega
=
3
nodes
=
thaw
(
actx
,
discr
.
nodes
())
center_dist
=
flat_obj_array
([
nodes
[
i
]
-
source_center
[
i
]
for
i
in
range
(
discr
.
dim
)
])
return
(
np
.
cos
(
source_omega
*
t
)
*
actx
.
np
.
exp
(
-
np
.
dot
(
center_dist
,
center_dist
)
/
source_width
**
2
))
def
main
():
cl_ctx
=
cl
.
create_some_context
()
queue
=
cl
.
CommandQueue
(
cl_ctx
)
actx
=
PyOpenCLArrayContext
(
queue
)
comm
=
MPI
.
COMM_WORLD
num_parts
=
comm
.
Get_size
()
from
meshmode.distributed
import
MPIMeshDistributor
,
get_partition_by_pymetis
mesh_dist
=
MPIMeshDistributor
(
comm
)
dim
=
2
nel_1d
=
16
if
mesh_dist
.
is_mananger_rank
():
from
meshmode.mesh.generation
import
generate_regular_rect_mesh
mesh
=
generate_regular_rect_mesh
(
a
=
(
-
0.5
,)
*
dim
,
b
=
(
0.5
,)
*
dim
,
n
=
(
nel_1d
,)
*
dim
)
print
(
"
%d elements
"
%
mesh
.
nelements
)
part_per_element
=
get_partition_by_pymetis
(
mesh
,
num_parts
)
local_mesh
=
mesh_dist
.
send_mesh_parts
(
mesh
,
part_per_element
,
num_parts
)
del
mesh
else
:
local_mesh
=
mesh_dist
.
receive_mesh_part
()
order
=
3
discr
=
EagerDGDiscretization
(
actx
,
local_mesh
,
order
=
order
,
mpi_communicator
=
comm
)
if
dim
==
2
:
# no deep meaning here, just a fudge factor
dt
=
0.75
/
(
nel_1d
*
order
**
2
)
elif
dim
==
3
:
# no deep meaning here, just a fudge factor
dt
=
0.45
/
(
nel_1d
*
order
**
2
)
else
:
raise
ValueError
(
"
don
'
t have a stable time step guesstimate
"
)
fields
=
flat_obj_array
(
bump
(
discr
,
actx
),
[
discr
.
zeros
(
actx
)
for
i
in
range
(
discr
.
dim
)]
)
vis
=
make_visualizer
(
discr
,
discr
.
order
+
3
if
dim
==
2
else
discr
.
order
)
def
rhs
(
t
,
w
):
return
wave_operator
(
discr
,
c
=
1
,
w
=
w
)
rank
=
comm
.
Get_rank
()
t
=
0
t_final
=
3
istep
=
0
while
t
<
t_final
:
fields
=
rk4_step
(
fields
,
t
,
dt
,
rhs
)
if
istep
%
10
==
0
:
print
(
istep
,
t
,
discr
.
norm
(
fields
[
0
]))
vis
.
write_vtk_file
(
"
fld-wave-eager-mpi-%03d-%04d.vtu
"
%
(
rank
,
istep
),
[
(
"
u
"
,
fields
[
0
]),
(
"
v
"
,
fields
[
1
:]),
])
t
+=
dt
istep
+=
1
if
__name__
==
"
__main__
"
:
main
()
# vim: foldmethod=marker
This diff is collapsed.
Click to expand it.
grudge/eager.py
+
89
−
8
View file @
f5433100
...
...
@@ -24,14 +24,16 @@ THE SOFTWARE.
import
numpy
as
np
# noqa
from
grudge.discretization
import
DGDiscretizationWithBoundaries
from
pytools
import
memoize_method
from
pytools.obj_array
import
obj_array_vectorize
from
pytools.obj_array
import
obj_array_vectorize
,
make_obj_array
import
pyopencl.array
as
cla
# noqa
from
grudge
import
sym
,
bind
from
meshmode.mesh
import
BTAG_ALL
,
BTAG_NONE
# noqa
from
meshmode.dof_array
import
freeze
,
DOFArray
from
meshmode.mesh
import
BTAG_ALL
,
BTAG_NONE
,
BTAG_PARTITION
# noqa
from
meshmode.dof_array
import
freeze
,
DOFArray
,
flatten
,
unflatten
from
grudge.discretization
import
DGDiscretizationWithBoundaries
from
grudge.symbolic.primitives
import
TracePair
class
EagerDGDiscretization
(
DGDiscretizationWithBoundaries
):
...
...
@@ -115,19 +117,98 @@ class EagerDGDiscretization(DGDiscretizationWithBoundaries):
def
norm
(
self
,
vec
,
p
=
2
):
return
self
.
_norm
(
p
)(
arg
=
vec
)
@memoize_method
def
connected_ranks
(
self
):
from
meshmode.distributed
import
get_connected_partitions
return
get_connected_partitions
(
self
.
_volume_discr
.
mesh
)
def
interior_trace_pair
(
discr
,
vec
):
i
=
discr
.
interp
(
"
vol
"
,
"
int_faces
"
,
vec
)
def
interior_trace_pair
(
discrwb
,
vec
):
i
=
discrwb
.
interp
(
"
vol
"
,
"
int_faces
"
,
vec
)
if
(
isinstance
(
vec
,
np
.
ndarray
)
and
vec
.
dtype
.
char
==
"
O
"
and
not
isinstance
(
vec
,
DOFArray
)):
e
=
obj_array_vectorize
(
lambda
el
:
discr
.
opposite_face_connection
()(
el
),
lambda
el
:
discr
wb
.
opposite_face_connection
()(
el
),
i
)
from
grudge.symbolic.primitives
import
TracePair
return
TracePair
(
"
int_faces
"
,
i
,
e
)
class
RankBoundaryCommunication
:
base_tag
=
1273
def
__init__
(
self
,
discrwb
,
remote_rank
,
vol_field
,
tag
=
None
):
self
.
tag
=
self
.
base_tag
if
tag
is
not
None
:
self
.
tag
+=
tag
self
.
discrwb
=
discrwb
self
.
array_context
=
vol_field
.
array_context
self
.
remote_btag
=
BTAG_PARTITION
(
remote_rank
)
self
.
bdry_discr
=
discrwb
.
discr_from_dd
(
self
.
remote_btag
)
self
.
local_dof_array
=
discrwb
.
interp
(
"
vol
"
,
self
.
remote_btag
,
vol_field
)
local_data
=
self
.
array_context
.
to_numpy
(
flatten
(
self
.
local_dof_array
))
comm
=
self
.
discrwb
.
mpi_communicator
self
.
send_req
=
comm
.
Isend
(
local_data
,
remote_rank
,
tag
=
self
.
tag
)
self
.
remote_data_host
=
np
.
empty_like
(
local_data
)
self
.
recv_req
=
comm
.
Irecv
(
self
.
remote_data_host
,
remote_rank
,
self
.
tag
)
def
finish
(
self
):
self
.
recv_req
.
Wait
()
actx
=
self
.
array_context
remote_dof_array
=
unflatten
(
self
.
array_context
,
self
.
bdry_discr
,
actx
.
from_numpy
(
self
.
remote_data_host
))
bdry_conn
=
self
.
discrwb
.
get_distributed_boundary_swap_connection
(
sym
.
as_dofdesc
(
sym
.
DTAG_BOUNDARY
(
self
.
remote_btag
)))
swapped_remote_dof_array
=
bdry_conn
(
remote_dof_array
)
self
.
send_req
.
Wait
()
return
TracePair
(
self
.
remote_btag
,
self
.
local_dof_array
,
swapped_remote_dof_array
)
def
_cross_rank_trace_pairs_scalar_field
(
discrwb
,
vec
,
tag
=
None
):
rbcomms
=
[
RankBoundaryCommunication
(
discrwb
,
remote_rank
,
vec
,
tag
=
tag
)
for
remote_rank
in
discrwb
.
connected_ranks
()]
return
[
rbcomm
.
finish
()
for
rbcomm
in
rbcomms
]
def
cross_rank_trace_pairs
(
discrwb
,
vec
,
tag
=
None
):
if
(
isinstance
(
vec
,
np
.
ndarray
)
and
vec
.
dtype
.
char
==
"
O
"
and
not
isinstance
(
vec
,
DOFArray
)):
n
,
=
vec
.
shape
result
=
{}
for
ivec
in
range
(
n
):
for
rank_tpair
in
_cross_rank_trace_pairs_scalar_field
(
discrwb
,
vec
[
ivec
]):
assert
isinstance
(
rank_tpair
.
dd
.
domain_tag
,
sym
.
DTAG_BOUNDARY
)
assert
isinstance
(
rank_tpair
.
dd
.
domain_tag
.
tag
,
BTAG_PARTITION
)
result
[
rank_tpair
.
dd
.
domain_tag
.
tag
.
part_nr
,
ivec
]
=
rank_tpair
return
[
TracePair
(
dd
=
sym
.
as_dofdesc
(
sym
.
DTAG_BOUNDARY
(
BTAG_PARTITION
(
remote_rank
))),
interior
=
make_obj_array
([
result
[
remote_rank
,
i
].
int
for
i
in
range
(
n
)]),
exterior
=
make_obj_array
([
result
[
remote_rank
,
i
].
ext
for
i
in
range
(
n
)])
)
for
remote_rank
in
discrwb
.
connected_ranks
()]
else
:
return
_cross_rank_trace_pairs_scalar_field
(
discrwb
,
vec
,
tag
=
tag
)
# vim: foldmethod=marker
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment