DSS

Direct stiffness summation makes a field on a continuous spectral-element space single-valued at element boundaries (DSS and numerical fluxes). Spaces.weighted_dss! is the user-level entry point; its internal phases are the Topologies functions, exposed for callers that need to overlap communication with computation, or to run DSS directly on a DataLayout.

ClimaCore.Spaces.weighted_dss!Function
weighted_dss!(data, space, dss_buffer)

Compute the weighted direct stiffness summation (DSS) of data in place: values at nodes shared between elements are replaced by their weighted average. On a discontinuous (DG) space this is a no-op.

It consists of the following steps:

  1. Spaces.weighted_dss_start!,
  2. Spaces.weighted_dss_internal!,
  3. Spaces.weighted_dss_ghost!.
source
Spaces.weighted_dss!(fv::FieldVector, dss_buffer = Spaces.create_dss_buffer(fv))

Apply weighted direct stiffness summation (DSS) to each field in fv in place. If dss_buffer is not provided, a buffer is created for each field in fv. The fields are passed to the Pair method of Spaces.weighted_dss!, which overlaps their communication.

source
Spaces.weighted_dss!(f::Field, dss_buffer = Spaces.create_dss_buffer(field))

Apply weighted direct stiffness summation (DSS) to f in place and return f. dss_buffer holds the buffers for communication in a distributed setting; see Spaces.create_dss_buffer. On a discontinuous (DG) space this is a no-op.

This is a projection operation from the piecewise polynomial space $V_0$ to the continuous space $V_1 = V_0 \cap C_0$, defined as the field $\theta \in V_1$ such that for all $\phi \in V_1$

\[\int_\Omega \phi \theta \,d\Omega = \int_\Omega \phi f \,d\Omega\]

In matrix form, we define $\bar \theta$ to be the unique global node representation, and $Q$ to be the "scatter" operator which maps to the redundant node representation $\theta$

\[\theta = Q \bar \theta\]

Then the problem can be written as

\[(Q \bar\phi)^\top W J Q \bar\theta = (Q \bar\phi)^\top W J f\]

which reduces to

\[\theta = Q \bar\theta = Q (Q^\top W J Q)^{-1} Q^\top W J f\]

source
Spaces.weighted_dss!(field1 => dss_buffer1, field2 => dss_buffer2, ...)

Call Spaces.weighted_dss! on multiple fields at once, overlapping the communication of all fields with computation. Returns nothing.

source
ClimaCore.Spaces.weighted_dss_start!Function
weighted_dss_start!(data, space, dss_buffer)

Start the weighted DSS of data: prepare the perimeter data of the elements on the process boundary and begin communication with neighboring processes. Returns nothing.

It consists of the following steps:

  1. Apply Spaces.dss_transform! on perimeter elements. This weights, and transforms to the physical basis if needed, the vector fields; scalar fields are weighted. The result is stored in dss_buffer.perimeter_data.
  2. Apply Spaces.dss_local_ghost!, which computes the partial weighted DSS on ghost vertices using only the information from local vertices.
  3. Apply Spaces.fill_send_buffer!, which loads the send buffer from perimeter_data. For unique ghost vertices, only the representative vertices, which hold the result of the "ghost local" DSS, are loaded.
  4. Start the DSS communication with neighboring processes.
source
ClimaCore.Spaces.weighted_dss_internal!Function
weighted_dss_internal!(data, space, dss_buffer)

Perform the part of the weighted DSS of data that needs no communication, while the communication started by Spaces.weighted_dss_start! is in flight. Returns nothing.

It consists of the following steps:

  1. Apply Spaces.dss_transform! on interior elements. Local elements are split into interior and perimeter elements so that communication overlaps with computation.
  2. Apply Spaces.dss_local!, which computes the weighted DSS on local vertices and faces.
  3. Apply Spaces.dss_untransform! on interior elements.

On a 1D spectral element space, the whole DSS is performed here with dss_1d!.

source
ClimaCore.Spaces.weighted_dss_ghost!Function
weighted_dss_ghost!(data, space, dss_buffer)

Finish the weighted DSS of data started by Spaces.weighted_dss_start!. Returns data.

It consists of the following steps:

  1. Finish the communication.
  2. Apply Spaces.load_from_recv_buffer!, which adds the data in the receive buffer to the corresponding locations in perimeter_data. For ghost vertices, the data is added only to the representative vertices; the values are then scattered to the other local vertices of each unique ghost vertex by dss_ghost!.
  3. Apply Spaces.dss_untransform! on perimeter elements, which transforms the summed vectors back to their original basis and copies the summed data from perimeter_data to data.
source
ClimaCore.Spaces.unique_nodesFunction
unique_nodes(space::SpectralElementSpace2D)

Return an iterator over the unique nodes of space. Each node is represented by the first ((i, j), e) triple at which it occurs.

This function is experimental, and may change in future.

source

Buffers

ClimaCore.Topologies.DSSBufferType
DSSBuffer{T, G, D, A, B, VI}

Buffers and index maps for the direct stiffness summation (DSS) of one data layout with element type T on a Topology2D. Construct with create_dss_buffer(data, topology, local_geometry = nothing, dss_weights = nothing).

Fields

  • graph_context: ClimaComms graph context for communication.
  • perimeter_data: DataLayout holding the (transformed) values at the perimeter nodes of each element.
  • send_data: Send buffer, an AbstractVector{FT}.
  • recv_data: Receive buffer, an AbstractVector{FT}.
  • send_buf_idx: Indexing array for loading the send buffer from perimeter_data.
  • recv_buf_idx: Indexing array for adding the receive buffer into perimeter_data.
  • internal_elems: Local elements (lidx) that touch no ghost element.
  • perimeter_elems: Local elements (lidx) on the process boundary.
source
ClimaCore.Topologies.create_dss_bufferFunction
create_dss_buffer(data, space)

Create a Topologies.DSSBuffer for the field data data on space. Return nothing if space is discontinuous (DG) or has no second horizontal dimension (1D spectral element spaces use dss_1d! and need no buffer).

source
Spaces.create_dss_buffer(fv::FieldVector)

Create a NamedTuple mapping the name of each field in fv to its DSS buffer.

source
Spaces.create_dss_buffer(field::Field)

Create a DSS buffer for communicating the neighbor information of field, or nothing if field needs no buffer.

source
ClimaCore.Topologies.Perimeter2DType
Perimeter2D(Nq)

Construct an iterator over the (i, j) node indices on the perimeter of a 2D spectral element with Nq nodes per dimension (polynomial degree Nq - 1). The four vertices come first, followed by the interior nodes of each face.

source

Phases

ClimaCore.Topologies.dss!Function
dss!(data, topology)

Perform unweighted DSS of data in place: values at nodes shared between elements are replaced by their sum. Returns nothing.

source
ClimaCore.Topologies.fill_send_buffer!Function
fill_send_buffer!(topology, data, ghost_buffer::GhostBuffer)

Load the send buffer of ghost_buffer with the data of the elements that neighboring processes need for their ghost elements. Returns nothing.

source
fill_send_buffer!(device, dss_buffer)

Load the send buffer of dss_buffer from its perimeter_data. For unique ghost vertices, only the representative vertices, which hold the result of the "ghost local" DSS, are loaded.

Part of ClimaCore.Spaces.weighted_dss!.

source
ClimaCore.Topologies.load_from_recv_buffer!Function
load_from_recv_buffer!(device, dss_buffer)

Add the data in the receive buffer of dss_buffer to the corresponding locations in its perimeter_data. For ghost vertices, the data is added only to the representative vertices; dss_ghost! then scatters the values to the other local vertices of each unique ghost vertex.

Part of ClimaCore.Spaces.weighted_dss!.

source