Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/docker-bases.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
############## Basic gcc CPU ##########################
#######################################################
deploy-cpu-bases:
if: inputs.cpu
if: ${{ github.event_name != 'workflow_dispatch' || inputs.cpu }}
name: "cpu-base-${{ matrix.arch }}-gcc${{ matrix.gcc }}"
runs-on: ${{ matrix.runner }}
env:
Expand Down Expand Up @@ -88,7 +88,7 @@ jobs:
tags: "devitocodes/bases:cpu-gcc${{ matrix.gcc }}-${{ matrix.arch }}"

deploy-cpu-bases-manifest:
if: inputs.cpu
if: ${{ github.event_name != 'workflow_dispatch' || inputs.cpu }}
name: "cpu-base-manifest"
runs-on: ubuntu-latest
needs: deploy-cpu-bases
Expand Down Expand Up @@ -123,7 +123,7 @@ jobs:
############## Intel OneApi CPU #######################
#######################################################
deploy-oneapi-bases:
if: inputs.intel
if: ${{ github.event_name != 'workflow_dispatch' || inputs.intel }}
name: "oneapi-base"
runs-on: ubuntu-latest
env:
Expand Down Expand Up @@ -181,7 +181,7 @@ jobs:
################### Nvidia nvhpc ######################
#######################################################
deploy-nvidia-bases:
if: inputs.nvidia
if: ${{ github.event_name != 'workflow_dispatch' || inputs.nvidia }}
name: "nvidia-bases-${{ matrix.arch }}"
runs-on: ${{ matrix.runner }}
env:
Expand Down Expand Up @@ -270,7 +270,7 @@ jobs:
tags: "devitocodes/bases:cpu-nvc${{ matrix.extra_tag }}-${{ matrix.arch }}"

deploy-nvidia-bases-manifest:
if: inputs.nvidia
if: ${{ github.event_name != 'workflow_dispatch' || inputs.nvidia }}
name: "nvidia-base-manifest"
runs-on: ubuntu-latest
needs: deploy-nvidia-bases
Expand Down Expand Up @@ -305,7 +305,7 @@ jobs:
##################### AMD #############################
#######################################################
deploy-amd-bases:
if: inputs.amd
if: ${{ github.event_name != 'workflow_dispatch' || inputs.amd }}
name: "amd-base"
runs-on: ["self-hosted", "amdgpu"]
env:
Expand Down
5 changes: 4 additions & 1 deletion devito/ir/clusters/algorithms.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ def guard(clusters):

# Chain together all `cds` conditions from all expressions in `c`
guards = {}
mode = sympy.Or
for cd in cds:
# `BOTTOM` parent implies a guard that lives outside of
# any iteration space, which corresponds to the placeholder None
Expand All @@ -270,6 +271,7 @@ def guard(clusters):

# Pull `cd` from any expr
condition = guards.setdefault(k, [])
mode = mode and cd.relation
for e in exprs:
try:
condition.append(e.conditionals[cd])
Expand All @@ -284,7 +286,8 @@ def guard(clusters):
conditionals.pop(cd, None)
exprs[i] = e.func(*e.args, conditionals=conditionals)

guards = {d: sympy.And(*v, evaluate=False) for d, v in guards.items()}
# Combination mode is And by default and Or if all conditions are
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Combination mode is And by default. If all conditions are Or then Or combination mode is used." may be less ambiguous

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nitpicking, with backtips ` around mode)

guards = {d: mode(*v, evaluate=False) for d, v in guards.items()}

# Construct a guarded Cluster
processed.append(c.rebuild(exprs=exprs, guards=guards))
Expand Down
2 changes: 1 addition & 1 deletion devito/ir/equations/equation.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def __new__(cls, *args, **kwargs):
else:
cond = diff2sympy(lower_exprs(d.condition))
if d._factor is not None:
cond = sympy.And(cond, GuardFactor(d))
cond = d.relation(cond, GuardFactor(d))
conditionals[d] = cond
# Replace dimension with index
index = d.index
Expand Down
11 changes: 9 additions & 2 deletions devito/types/dimension.py
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,8 @@ class ConditionalDimension(DerivedDimension):
If True, use `self`, rather than the parent Dimension, to
index into arrays. A typical use case is when arrays are accessed
indirectly via the ``condition`` expression.
relation: Or/And, default=And
How this ConditionalDimension will be combined with other ones.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems slightly unintuitive to specify this here? Surely it would make more sense to specify how ConditionalDimensions are combined at the point of combination?

Perhaps with an API like cdim.and(other) and cdim.or(other) which returns a new ConditionalDimension which combines the conditions of its constituent ConditionalDimensions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surely it would make more sense to specify how ConditionalDimensions are combined at the point of combination?

You cannot so that's not relvant. A Function a defined dimension. It will be combined with any indices and implicit_dims at lowering. Combinining it by hand won't do anything as it will be combined yet again at lowering with And making it useless

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah ok, so this is to do with how it's handled during lowering and the combination is not exposed at the API level? It might be worth adding a note to the notebook explaining when you would want to change relation?


Examples
--------
Expand Down Expand Up @@ -913,10 +915,10 @@ class ConditionalDimension(DerivedDimension):
is_Conditional = True

__rkwargs__ = DerivedDimension.__rkwargs__ + \
('factor', 'condition', 'indirect')
('factor', 'condition', 'indirect', 'relation')

def __init_finalize__(self, name, parent=None, factor=None, condition=None,
indirect=False, **kwargs):
indirect=False, relation=sympy.And, **kwargs):
# `parent=None` degenerates to a ConditionalDimension outside of
# any iteration space
if parent is None:
Expand All @@ -937,6 +939,7 @@ def __init_finalize__(self, name, parent=None, factor=None, condition=None,

self._condition = condition
self._indirect = indirect
self._relation = relation

@property
def uses_symbolic_factor(self):
Expand Down Expand Up @@ -978,6 +981,10 @@ def condition(self):
def indirect(self):
return self._indirect

@property
def relation(self):
return self._relation

@cached_property
def free_symbols(self):
retval = set(super().free_symbols)
Expand Down
4 changes: 2 additions & 2 deletions docker/Dockerfile.intel
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ FROM base AS oneapi

# Download the key to system keyring
# https://www.intel.com/content/www/us/en/develop/documentation/installation-guide-for-intel-oneapi-toolkits-linux/top/installation/install-using-package-managers/apt.html#apt
SHELL /bin/bash -o pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN wget --progress=dot:giga -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor > /usr/share/keyrings/oneapi-archive-keyring.gpg
RUN echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" > /etc/apt/sources.list.d/oneAPI.list

Expand All @@ -37,7 +37,7 @@ RUN apt-get update -y && \

# Drivers mandatory for intel gpu
# https://dgpu-docs.intel.com/driver/installation.html#ubuntu-install-steps
SHELL /bin/bash -o pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN wget -qO - https://repositories.intel.com/graphics/intel-graphics.key | gpg --dearmor > /usr/share/keyrings/intel-graphics.gpg
RUN echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/graphics/ubuntu jammy unified" > /etc/apt/sources.list.d/intel-gpu-jammy.list

Expand Down
4 changes: 2 additions & 2 deletions docker/Dockerfile.nvidia
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ RUN apt-get update && \
dh-autoreconf python3-venv python3-dev python3-pip

# nodesource: nvdashboard requires nodejs>=10
SHELL /bin/bash -o pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN curl https://developer.download.nvidia.com/hpc-sdk/ubuntu/DEB-GPG-KEY-NVIDIA-HPC-SDK | gpg --yes --dearmor -o /usr/share/keyrings/nvidia-hpcsdk-archive-keyring.gpg
RUN arch="$(uname -m)" && \
case "$arch" in \
Expand Down Expand Up @@ -92,7 +92,7 @@ ENV UCX_TLS=cuda,cuda_copy,cuda_ipc,sm,shm,self
#ENV UCX_TLS=cuda,cuda_copy,cuda_ipc,sm,shm,self,rc_x,gdr_copy

# Make simlink for path setup since ENV doesn't accept shell commands.
SHELL /bin/bash -o pipefail
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN arch="$(uname -m)" && \
case "$arch" in \
x86_64) linux=Linux_x86_64 ;; \
Expand Down
34 changes: 20 additions & 14 deletions examples/userapi/05_conditional_dimension.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@
" If True, use `self`, rather than the parent Dimension, to\n",
" index into arrays. A typical use case is when arrays are accessed\n",
" indirectly via the ``condition`` expression.\n",
" relation: Or/And, default=And\n",
" How this ConditionalDimension will be combined with other ones.\n",
"\n",
" Examples\n",
" --------\n",
Expand Down Expand Up @@ -248,9 +250,7 @@
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"metadata": {},
"outputs": [
{
"name": "stderr",
Expand Down Expand Up @@ -323,7 +323,7 @@
"START(section0)\n",
"for (int x = x_m; x <= x_M; x += 1)\n",
"{\n",
" #pragma omp simd aligned(f:32)\n",
" #pragma omp simd aligned(f:64)\n",
" for (int y = y_m; y <= y_M; y += 1)\n",
" {\n",
" if (f[x + 1][y + 1] > 0)\n",
Expand Down Expand Up @@ -399,7 +399,7 @@
"START(section0)\n",
"for (int x = x_m; x <= x_M; x += 1)\n",
"{\n",
" #pragma omp simd aligned(f,g:32)\n",
" #pragma omp simd aligned(f,g:64)\n",
" for (int y = y_m; y <= y_M; y += 1)\n",
" {\n",
" if (y < 5 && g[x + 1][y + 1] != 0)\n",
Expand Down Expand Up @@ -551,13 +551,6 @@
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Operator `Kernel` ran in 0.01 s\n"
]
},
{
"name": "stdout",
"output_type": "stream",
Expand All @@ -570,7 +563,20 @@
" f[i / cif] = g[i];\n",
" }\n",
"}\n",
"STOP(section0,timers)\n",
"STOP(section0,timers)\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Operator `Kernel` ran in 0.01 s\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
" Data in g \n",
" [ 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15.]\n",
Expand Down Expand Up @@ -831,7 +837,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.2"
"version": "3.11.0rc1"
}
},
"nbformat": 4,
Expand Down
36 changes: 35 additions & 1 deletion tests/test_buffering.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import numpy as np
import pytest
from sympy import Or

from conftest import skipif
from devito import (
ConditionalDimension, Constant, Eq, Grid, Operator, SubDimension, SubDomain,
CondEq, ConditionalDimension, Constant, Eq, Grid, Operator, SubDimension, SubDomain,
TimeFunction, configuration, switchconfig
)
from devito.arch.archinfo import AppleArm
Expand Down Expand Up @@ -751,3 +752,36 @@ def test_buffer_reuse():

assert all(np.all(usave.data[i-1] == i) for i in range(1, nt + 1))
assert all(np.all(vsave.data[i-1] == i + 1) for i in range(1, nt + 1))


def test_multi_cond():
grid = Grid((3, 3))
nt = 5

x, y = grid.dimensions

factor = 2
ntmod = (nt - 1) * factor + 1

ct1 = ConditionalDimension(name="ct1", parent=grid.time_dim,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API is pretty unintuitive imo - it isn't really clear to me what the relation keyword does to the condition/factor without digging into documentation

factor=factor, relation=Or)
ctend = ConditionalDimension(name="ctend", parent=grid.time_dim,
condition=CondEq(grid.time_dim, ntmod - 2),
relation=Or)

f = TimeFunction(grid=grid, name='f', time_order=0,
space_order=0, save=nt, time_dim=ct1)
T = TimeFunction(grid=grid, name='T', time_order=0, space_order=0)

eqs = [Eq(T, grid.time_dim)]
# this to save times from 0 to nt - 2
eqs.append(Eq(f, T))
# this to save the last time sample nt - 1
eqs.append(Eq(f.forward, T+1, implicit_dims=ctend))

# run operator with buffering
op = Operator(eqs, opt=('streaming', 'buffering'))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need or want "streaming" here

op.apply(time_m=0, time_M=ntmod-2)

for i in range(nt):
assert np.allclose(f.data[i], i*2)
Loading