FOR_EACH_IN_PRODUCT

The FOR_EACH_IN_PRODUCT macro is a utility in SPECFEMPP for processing combinations of tags that represent different element dimensions, medium types, property types, boundary conditions, and connection types.

Description

This macro executes a specified operation for every combination in the Cartesian product of the provided tag sequences. It significantly reduces code duplication when implementing functionality across multiple specializations.

Syntax

FOR_EACH_IN_PRODUCT(
    (DIMENSION_TAG(VALUES...), MEDIUM_TAG(VALUES...), ...),
    OPERATION)

The first argument is a tuple of tag sequences, each defined by a macro that can be one of the following:

  • DIMENSION_TAG(VALUES...): Specifies the element dimensions (e.g., DIM2, DIM3).

  • MEDIUM_TAG(VALUES...): Specifies the medium types (e.g., ACOUSTIC, ELASTIC_SH, ELASTIC_PSV).

  • CONNECTION_TAG(VALUES...): Specifies the connection types (e.g., WEAKLY_CONFORMING, NONCONFORMING).

  • PROPERTY_TAG(VALUES...): Specifies the property types (e.g., ISOTROPIC, ANISOTROPIC).

  • BOUNDARY_TAG(VALUES...): Specifies the boundary conditions (e.g., NONE, STACEY, COMPOSITE_STACEY_DIRICHLET).

The second argument OPERATION can be one of three types:

  • INSTANTIATE - For template instantiation

  • DECLARE - For variable declaration

  • A code block (with optional CAPTURE)

Usage Patterns

Template Instantiation with INSTANTIATE

Used to explicitly instantiate templates for all combinations of the specified tags.

FOR_EACH_IN_PRODUCT(
    (DIMENSION_TAG(DIM2),
    MEDIUM_TAG(ELASTIC_PSV, ELASTIC_SH, ACOUSTIC, POROELASTIC, ELASTIC_PSV_T),
    PROPERTY_TAG(ISOTROPIC, ANISOTROPIC, ISOTROPIC_COSSERAT),
    BOUNDARY_TAG(NONE, ACOUSTIC_FREE_SURFACE, STACEY, COMPOSITE_STACEY_DIRICHLET)),
    INSTANTIATE(
        (template void specfem::kokkos_kernels::impl::compute_mass_matrix,
        (_DIMENSION_TAG_, specfem::wavefield::simulation_field::forward, 5,
        _MEDIUM_TAG_, _PROPERTY_TAG_, _BOUNDARY_TAG_),
        (const type_real &, const specfem::assembly::assembly &);)))

This expands to template instantiations for each combination of the specified tags. The placeholders _DIMENSION_TAG_, _MEDIUM_TAG_, etc. are substituted with the actual tags defined in the first argument.

Variable Declaration with DECLARE

Used to declare variables for each tag combination.

FOR_EACH_IN_PRODUCT(
    (DIMENSION_TAG(DIM2),
    MEDIUM_TAG(ACOUSTIC, ELASTIC_PSV)),
    DECLARE((IndexViewType, elements),
            (IndexViewType::HostMirror, h_elements)))

This generates declarations like

IndexViewType dim2_elements_acoustic;
IndexViewType::HostMirror dim2_h_elements_acoustic;
IndexViewType dim2_elements_elastic_psv;
IndexViewType::HostMirror dim2_h_elements_elastic_psv;

Code Execution with Code Blocks

The third usage pattern executes code blocks for each tag combination:

FOR_EACH_IN_PRODUCT(
    (DIMENSION_TAG(DIM2),
    MEDIUM_TAG(ELASTIC_PSV, ELASTIC_SH, ACOUSTIC, POROELASTIC, ELASTIC_PSV_T)),
    {
        if constexpr (dimension == _dimension_tag_ && medium == _medium_tag_) {
            impl::divide_mass_matrix<dimension, wavefield, _medium_tag_>(assembly);
        }
    })

Inside the code, the current tags are accessible via references like _dimension_tag_ and _medium_tag_. Optionally, you can capture existing variables using the CAPTURE macro:

FOR_EACH_IN_PRODUCT(
    (DIMENSION_TAG(DIM2),
    MEDIUM_TAG(ELASTIC_PSV, ELASTIC_SH, ACOUSTIC, POROELASTIC, ELASTIC_PSV_T)),
    CAPTURE(elements, h_elements) {
        // Code that uses elements and h_elements with type-specific logic
        if (_medium_tag_ == medium_tag) {
            return _elements_;
        }
    })

The variables inside the CAPTURE block are captured by reference as variables __elements__ and _h_elements_.

Material Tags

Dimension Tags

DIMENSION_TAG_DIM2   (0, specfem::dimension::type::dim2, dim2, _ENUM_ID_DIMENSION_TAG)

Dimension tag for 2D.

DIMENSION_TAG_DIM3   (1, specfem::dimension::type::dim3, dim3, _ENUM_ID_DIMENSION_TAG)

Dimension tag for 3D.

Medium Tags

MEDIUM_TAG_ELASTIC_PSV   (0, specfem::element::medium_tag::elastic_psv, elastic_psv,                  \    _ENUM_ID_MEDIUM_TAG)

Medium tag for Elastic P-SV.

MEDIUM_TAG_ELASTIC_SH   (1, specfem::element::medium_tag::elastic_sh, elastic_sh, _ENUM_ID_MEDIUM_TAG)

Medium tag for Elastic SH.

MEDIUM_TAG_ELASTIC_PSV_T   (2, specfem::element::medium_tag::elastic_psv_t, elastic_psv_t,              \    _ENUM_ID_MEDIUM_TAG)

Medium tag for Elastic P-SV Transverse Isotropic.

MEDIUM_TAG_ACOUSTIC   (3, specfem::element::medium_tag::acoustic, acoustic, _ENUM_ID_MEDIUM_TAG)

Medium tag for Acoustic.

MEDIUM_TAG_POROELASTIC   (4, specfem::element::medium_tag::poroelastic, poroelastic,                  \    _ENUM_ID_MEDIUM_TAG)

Medium tag for Poroelastic.

MEDIUM_TAG_ELECTROMAGNETIC_TE   (5, specfem::element::medium_tag::electromagnetic_te, electromagnetic_te,    \    _ENUM_ID_MEDIUM_TAG)

Medium tag for Electromagnetic TE.

MEDIUM_TAG_ELASTIC   (6, specfem::element::medium_tag::elastic, elastic, _ENUM_ID_MEDIUM_TAG)

Medium tag for Elastic.

Property Tags

PROPERTY_TAG_ISOTROPIC   (0, specfem::element::property_tag::isotropic, isotropic,                    \    _ENUM_ID_PROPERTY_TAG)

Property tag for Isotropic.

PROPERTY_TAG_ANISOTROPIC   (1, specfem::element::property_tag::anisotropic, anisotropic,                \    _ENUM_ID_PROPERTY_TAG)

Property tag for Anisotropic.

PROPERTY_TAG_ISOTROPIC_COSSERAT   (2, specfem::element::property_tag::isotropic_cosserat, isotropic_cosserat,  \    _ENUM_ID_PROPERTY_TAG)

Property tag for Isotropic Cosserat.

Boundary Tags

BOUNDARY_TAG_NONE   (0, specfem::element::boundary_tag::none, none, _ENUM_ID_BOUNDARY_TAG)

Boundary tag for None.

BOUNDARY_TAG_STACEY   (1, specfem::element::boundary_tag::stacey, stacey, _ENUM_ID_BOUNDARY_TAG)

Boundary tag for Stacey.

BOUNDARY_TAG_ACOUSTIC_FREE_SURFACE   (2, specfem::element::boundary_tag::acoustic_free_surface

,                   \

acoustic_free_surface,

_ENUM_ID_BOUNDARY_TAG)

Boundary tag for Acoustic Free Surface.

BOUNDARY_TAG_COMPOSITE_STACEY_DIRICHLET   (3, specfem::element::boundary_tag::composite_stacey_dirichlet

,              \

composite_stacey_dirichlet,

_ENUM_ID_BOUNDARY_TAG)

Boundary tag for Composite Stacey Dirichlet.

Interface Tags

Connection Tags

CONNECTION_TAG_STRONGLY_CONFORMING   (0, specfem::connections::type::strongly_conforming, strongly_conforming,    \    _ENUM_ID_CONNECTION_TAG)

Strongly conforming connection tag.

CONNECTION_TAG_WEAKLY_CONFORMING   (1, specfem::connections::type::weakly_conforming, weakly_conforming,        \    _ENUM_ID_CONNECTION_TAG)

Weakly conforming connection tag.

CONNECTION_TAG_NONCONFORMING   (2, specfem::connections::type::nonconforming, nonconforming,                \    _ENUM_ID_CONNECTION_TAG)

Non-conforming connection tag.

Interface Type Tags

INTERFACE_TAG_ELASTIC_ACOUSTIC   (0, specfem::interface::interface_tag::elastic_acoustic, elastic_acoustic,   \    _ENUM_ID_INTERFACE_TAG)

Elastic-Acoustic interface tag.

INTERFACE_TAG_ACOUSTIC_ELASTIC   (1, specfem::interface::interface_tag::acoustic_elastic, acoustic_elastic,   \    _ENUM_ID_INTERFACE_TAG)

Acoustic-Elastic interface tag.

Enum Tags

_ENUM_ID_DIMENSION_TAG 0

ID for dimension tags.

Used to identify dimension tags such as DIMENSION_TAG_DIM2 and DIMENSION_TAG_DIM3. See Material Iterator Macros.

_ENUM_ID_MEDIUM_TAG 1

ID for medium tags.

Used to identify medium tags such as MEDIUM_TAG_ELASTIC_PSV, MEDIUM_TAG_ACOUSTIC, etc. See Material Iterator Macros.

_ENUM_ID_PROPERTY_TAG 2

ID for property tags.

Used to identify property tags such as PROPERTY_TAG_ISOTROPIC and PROPERTY_TAG_ANISOTROPIC. See Material Iterator Macros.

_ENUM_ID_BOUNDARY_TAG 3

ID for boundary tags.

Used to identify boundary tags such as BOUNDARY_TAG_NONE and BOUNDARY_TAG_STACEY. See Material Iterator Macros.

_ENUM_ID_CONNECTION_TAG 4

ID for connection tags.

Used to identify connection tags in interface definitions. See Interface Iterator Macros.

_ENUM_ID_INTERFACE_TAG 5

ID for interface tags.

Used to identify interface tags in interface definitions. See Interface Iterator Macros.

Tag Combinations

MEDIUM_TAGS_DIM2   ((DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV

))(                              \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_SH

))(                            \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV_T

))(                         \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ACOUSTIC

))(                              \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_POROELASTIC

))(                           \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELECTROMAGNETIC_TE))

Macro to generate a list of medium types.

MEDIUM_TAGS_DIM3 ((DIMENSION_TAG_DIM3, MEDIUM_TAG_ELASTIC))
MEDIUM_TAGS MEDIUM_TAGS_DIM2 MEDIUM_TAGS_DIM3
MATERIAL_SYSTEMS_DIM2   ((DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV, PROPERTY_TAG_ISOTROPIC

))(      \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV, PROPERTY_TAG_ANISOTROPIC

))( \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_SH, PROPERTY_TAG_ISOTROPIC

))(    \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_SH, PROPERTY_TAG_ANISOTROPIC

))(  \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV_T,                           \        PROPERTY_TAG_ISOTROPIC_COSSERAT

))(                                      \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ACOUSTIC, PROPERTY_TAG_ISOTROPIC

))(      \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_POROELASTIC, PROPERTY_TAG_ISOTROPIC

))(   \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELECTROMAGNETIC_TE,                      \        PROPERTY_TAG_ISOTROPIC))

Macro to generate a list of material systems.

MATERIAL_SYSTEMS_DIM3   ((DIMENSION_TAG_DIM3, MEDIUM_TAG_ELASTIC, PROPERTY_TAG_ISOTROPIC))
MATERIAL_SYSTEMS MATERIAL_SYSTEMS_DIM2 MATERIAL_SYSTEMS_DIM3
ELEMENT_TYPES_DIM2   ((DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV, PROPERTY_TAG_ISOTROPIC,        \     BOUNDARY_TAG_NONE))((DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV,           \                          PROPERTY_TAG_ISOTROPIC, BOUNDARY_TAG_STACEY

))(        \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_SH, PROPERTY_TAG_ISOTROPIC,      \        BOUNDARY_TAG_NONE))((DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_SH,         \                             PROPERTY_TAG_ISOTROPIC, BOUNDARY_TAG_STACEY

))(     \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV_T,                           \        PROPERTY_TAG_ISOTROPIC_COSSERAT, BOUNDARY_TAG_NONE

))(                   \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV_T,                           \        PROPERTY_TAG_ISOTROPIC_COSSERAT,                                        \        BOUNDARY_TAG_STACEY))((DIMENSION_TAG_DIM2, MEDIUM_TAG_ACOUSTIC,         \                               PROPERTY_TAG_ISOTROPIC, BOUNDARY_TAG_NONE

))(     \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ACOUSTIC, PROPERTY_TAG_ISOTROPIC,        \        BOUNDARY_TAG_ACOUSTIC_FREE_SURFACE

))(                                   \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ACOUSTIC, PROPERTY_TAG_ISOTROPIC,        \        BOUNDARY_TAG_STACEY))((DIMENSION_TAG_DIM2, MEDIUM_TAG_ACOUSTIC,         \                               PROPERTY_TAG_ISOTROPIC,                          \                               BOUNDARY_TAG_COMPOSITE_STACEY_DIRICHLET

))(       \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV, PROPERTY_TAG_ANISOTROPIC,   \        BOUNDARY_TAG_NONE))((DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_PSV,        \                             PROPERTY_TAG_ANISOTROPIC, BOUNDARY_TAG_STACEY

))(   \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_SH, PROPERTY_TAG_ANISOTROPIC,    \        BOUNDARY_TAG_NONE))((DIMENSION_TAG_DIM2, MEDIUM_TAG_ELASTIC_SH,         \                             PROPERTY_TAG_ANISOTROPIC, BOUNDARY_TAG_STACEY

))(   \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_POROELASTIC, PROPERTY_TAG_ISOTROPIC,     \        BOUNDARY_TAG_NONE))((DIMENSION_TAG_DIM2, MEDIUM_TAG_POROELASTIC,        \                             PROPERTY_TAG_ISOTROPIC, BOUNDARY_TAG_STACEY

))(     \

(

DIMENSION_TAG_DIM2, MEDIUM_TAG_ELECTROMAGNETIC_TE,                      \        PROPERTY_TAG_ISOTROPIC, BOUNDARY_TAG_NONE))

Macro to generate a list of element types.

ELEMENT_TYPES_DIM3   ((DIMENSION_TAG_DIM3, MEDIUM_TAG_ELASTIC, PROPERTY_TAG_ISOTROPIC,            \     BOUNDARY_TAG_NONE))
ELEMENT_TYPES ELEMENT_TYPES_DIM2 ELEMENT_TYPES_DIM3