SEM domain decomposition¶
sweep.sem.dd splits one model into x strips across GPUs on the impl='c'
backend, the SEM mirror of the FD ModelParallel: a built
PropSEM carries the configuration, global coordinates go in and
gather_record assembles the record. Usage and scope are in
Domain decomposition.
from sweep.sem.dd import SEMModelParallel, StripTopology
ddp = SEMModelParallel(prop, StripTopology(px=world, rank=rank))
rec = ddp(wavelet, src_node, rec_nodes, [vp])
full = ddp.gather_record(rec)
sweep.sem.dd.SEMModelParallel ¶
DD wrapper over the impl='c' SEM acoustic C-PML propagator.
prop is a built :class:~sweep.sem.prop_base.PropSEM used as the
CONFIG CARRIER (mirroring FD ModelParallel(prop, mesh)); the compute
runs on the stepped CUDA entry points regardless of prop's impl.
Scope: AcousticPotentialSEM2D, ElasticSEM2DDeformed,
AcousticElasticSEM2D, AcousticSEM3D and AcousticSEM3DDeformed
-- all C-PML, one shot per call, records at global-node receivers. The
equation whitelist is exact (is, not issubclass) on purpose: each
family needs its own stepped entry points and consts builder, so a
near-miss must fail loudly rather than fall through to a sibling's path.
The two 3-D acoustic families share _parts3d and the same stepped
kernels -- the deformed one only swaps which geometry the strip consts
carry (per element-node w_J plus the nine inverse-Jacobian metrics,
instead of the flat mesh's per-thread w_jac and 1/2h scalars).
That works because the strip mesh is rebuilt for its ibool TOPOLOGY only
and every geometric quantity is sliced from the global build -- the same
rule that keeps the C-PML profile intact across a cut.
for_equation
classmethod
¶
A wrapper over a BUILT 3-D acoustic equation, for callers that
hold one and no PropSEM (the low-level propagator): the config the
strips need is read off the equation, and there is no model to
resolve, so drive it with :meth:run. One strip unless topo
says otherwise.
forward ¶
One shot; source/receivers are GLOBAL node indices of the
row-major global grid. Returns (nt, nrec) -- fully assembled in
single-process mode, own-columns-only under dist.
The gradient memory is the propagator's own. memory=
BoundarySaving() stores each strip's C-PML band ring instead of its
save-all tape; the two memory levers compose because both strips give
a shared cut the same band membership (see :func:_band_nodes). Its
storage_dtype picks the ring's storage precision -- 'fp32',
'bf16' (2x) or 'int8' (4x, one amax scale per field and step).
The propagator's bs_store_dtype_elem overrides it for the ELEMENT
rings, which the elastic and fluid-solid paths carry; on the elastic
path they are 82% of the ring memory and quantise ~70x better than the
node rings, so storage_dtype='fp32', bs_store_dtype_elem='int8' is
the setting that actually pays there. Refused on paths that ring nodes
only.
run ¶
run(
eq_g,
wavelet,
source,
receivers,
memory=None,
bs_store_dtype=None,
bs_store_dtype_elem=None,
)
One shot on a BUILT equation eq_g -- what :meth:forward does
after resolving the model, and how the low-level
:class:~sweep.sem.prop_c.SEMCudaPropagator (which holds a built
equation and no PropSEM) reaches the strip driver.
source is a global node id, a :class:_Stamps, or a tuple of
(n_global,) patterns in source-field order; receivers global
node ids or a :class:_Stamps. Returns (nt, nrec)
((nt, nrec, ncomp) on the elastic and fluid-solid paths).
Refuse -> normalise -> build the strips -> check the cuts -> step -> gather, one method each, in that order: the refusals have to precede every allocation, and the cut check has to precede the first step.
gather_record ¶
Assemble the global record on rank 0 (dist mode); identity in
single-process mode. Mirrors FD ModelParallel.gather_record.
sweep.sem.dd.StripTopology ¶
1-D x-strip rank grid (the py == 1 row of FD's MeshTopology).
px strips over the element columns; z is never split. Pure
arithmetic -- no torch.distributed calls.
rank
class-attribute
¶
int([x]) -> integer int(x, base=10) -> integer
Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.int(). For floating point numbers, this truncates towards zero.
If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by '+' or '-' and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal.
int('0b100', base=0) 4
local_elems ¶
Element-column range [ex0, ex1) (uniform tiles, the FD v1
rule: pad the domain to a multiple of px yourself).