Source code for stride.physics.common.devito


import os
import gc
import sympy
import logging
import functools
import itertools
import numpy as np
import scipy.special

import mosaic
from mosaic.types import Struct

from . import import_devito as devito
from ...problem.base import Gridded


__all__ = ['OperatorDevito', 'GridDevito', 'config_devito']


class FullDomain(devito.SubDomain):

    name = 'full_domain'

    def __init__(self, space_order, extra):
        super().__init__()

        self.space_order = space_order
        self.extra = extra

    def define(self, dimensions):
        return {dimension: dimension for dimension in dimensions}


class InteriorDomain(devito.SubDomain):

    name = 'interior_domain'

    def __init__(self, space_order, extra):
        super().__init__()

        self.space_order = space_order
        self.extra = extra

    def define(self, dimensions):
        return {dimension: ('middle', extra, extra)
                for dimension, extra in zip(dimensions, self.extra)}


class PMLSide(devito.SubDomain):

    def __init__(self, space_order, extra, dim, side):
        self.dim_i = dim
        self.side = side
        self.name = 'pml_side_' + side + str(dim)

        super().__init__()

        self.space_order = space_order
        self.extra = extra

    def define(self, dimensions):
        domain = {dimension: dimension for dimension in dimensions}
        domain[dimensions[self.dim_i]] = (self.side, self.extra[self.dim_i])

        return domain


class PMLCentre(devito.SubDomain):

    def __init__(self, space_order, extra, dim, side):
        self.dim_i = dim
        self.side = side
        self.name = 'pml_centre_' + side + str(dim)

        super().__init__()

        self.space_order = space_order
        self.extra = extra

    def define(self, dimensions):
        domain = {dimension: ('middle', extra, extra)
                  for dimension, extra in zip(dimensions, self.extra)}
        domain[dimensions[self.dim_i]] = (self.side, self.extra[self.dim_i])

        return domain


class PMLCorner(devito.SubDomain):

    def __init__(self, space_order, extra, *sides):
        self.sides = sides
        self.name = 'pml_corner_' + '_'.join(sides)

        super().__init__()

        self.space_order = space_order
        self.extra = extra

    def define(self, dimensions):
        domain = {dimension: (side, extra)
                  for dimension, side, extra in zip(dimensions, self.sides, self.extra)}

        return domain


class PMLCentreCorner(devito.SubDomain):

    def __init__(self, space_order, extra, *sides):
        self.sides = sides
        self.name = 'pml_centre_corner_' + '_'.join(sides)

        super().__init__()

        self.space_order = space_order
        self.extra = extra

    def define(self, dimensions):
        domain = {dimension: (side, extra) if side != 'middle' else ('middle', extra, extra)
                  for dimension, side, extra in zip(dimensions, self.sides, self.extra)}

        return domain


class PMLPartial(devito.SubDomain):

    def __init__(self, space_order, extra, dim, side):
        self.dim_i = dim
        self.side = side
        self.name = 'pml_partial_' + side + str(dim)

        super().__init__()

        self.space_order = space_order
        self.extra = extra

    def define(self, dimensions):
        domain = {dimension: ('middle', extra, extra)
                  for dimension, extra in zip(dimensions, self.extra)}

        domain[dimensions[0]] = dimensions[0]
        if len(dimensions) > 2:
            domain[dimensions[1]] = dimensions[1]

        domain[dimensions[self.dim_i]] = (self.side, self.extra[self.dim_i])

        return domain


def _cached(func):

    @functools.wraps(func)
    def cached_wrapper(self, *args, **kwargs):
        name = args[0]
        cached = kwargs.get('cached', True)
        replace_cached = kwargs.get('replace_cached', True)

        if cached is True:
            fun = self.vars.get(name, None)
            if fun is not None:
                _args, _kwargs = self.cached_args[name]

                same_args = True
                for arg, _arg in zip(args, _args):
                    try:
                        same_args = same_args and bool(arg == _arg)
                    except ValueError:
                        pass

                for arg, _arg in zip(kwargs.values(), _kwargs.values()):
                    try:
                        same_args = same_args and bool(arg == _arg)
                    except ValueError:
                        pass

                if same_args:
                    return fun

        elif replace_cached:
            self.vars.pop(name, None)
            self.cached_args.pop(name, None)

        if name not in self.cached_funcs:
            self.cached_funcs[name] = cached_wrapper

        fun = func(self, *args, **kwargs)

        if replace_cached:
            self.vars[name] = fun
            self.cached_args[name] = (args, kwargs)

        return fun

    return cached_wrapper


[docs] class GridDevito(Gridded): """ Instances of this class encapsulate the Devito grid, and interact with it by generating appropriate functions on demand. Instances will also keep a cache of created Devito functions under the ``vars`` attribute, which can be accessed by name using dot notation. Parameters ---------- space_order : int Default space order of the discretisation for functions of the grid. time_order : int Default time order of the discretisation for functions of the grid. time_dim : Time, optional Time dimension on which to step. or ``False`` if no time dependency. grid : Grid, optional Existing grid, if not provided one will be created. Either a grid or space, time and slow_time need to be provided. space : Space, optional time : Time, optional slow_time : SlowTime, optional """ def __init__(self, space_order, time_order, time_dim=None, **kwargs): super().__init__(**kwargs) self.vars = Struct() self.cached_args = Struct() self.cached_funcs = Struct() self.space_order = space_order self.time_order = time_order self.time_dim = time_dim if time_dim is not None else self.time self._time_under_count = 0 grid_kwargs = dict() space = self.space if space is None: origin = (0,) extended_shape = (2,) extended_extent = (1,) else: extra = space.absorbing origin = space.pml_origin extended_shape = space.extended_shape extended_extent = tuple(np.array(space.spacing) * (np.array(space.extended_shape) - 1)) self.full = FullDomain(space_order, extra) self.interior = InteriorDomain(space_order, extra) self.pml_left = tuple() self.pml_right = tuple() self.pml_centres = tuple() self.pml_partials = tuple() self.pml_centre_corners = tuple() for dim in range(space.dim): self.pml_left += (PMLSide(space_order, extra, dim, 'left'),) self.pml_right += (PMLSide(space_order, extra, dim, 'right'),) self.pml_centres += (PMLCentre(space_order, extra, dim, 'left'), PMLCentre(space_order, extra, dim, 'right')) self.pml_partials += (PMLPartial(space_order, extra, dim, 'left'), PMLPartial(space_order, extra, dim, 'right')) for sides in itertools.product(['left', 'right'], repeat=space.dim-1): sides = list(sides) sides.insert(dim, 'middle') self.pml_centre_corners += (PMLCentreCorner(space_order, extra, *sides),) self.pml_corners = [PMLCorner(space_order, extra, *sides) for sides in itertools.product(['left', 'right'], repeat=space.dim)] self.pml_corners = tuple(self.pml_corners) self.pml = self.pml_partials grid_kwargs['subdomains'] = (self.full, self.interior,) + \ self.pml + self.pml_left + self.pml_right + \ self.pml_centres + self.pml_corners + self.pml_centre_corners dimensions = None time_dimension = None parent_grid = kwargs.pop('parent_grid', None) if parent_grid is not None: dimensions = parent_grid.dimensions time_dimension = devito.TimeDimension(name='time_inner', spacing=devito.Scalar(name='dt_inner', is_const=True)) self.num_inner = kwargs.pop('num_inner', 1) else: self.num_inner = None self.dtype = kwargs.pop('dtype', np.float32) self.devito_grid = devito.Grid(extent=extended_extent, shape=extended_shape, origin=origin, dimensions=dimensions, time_dimension=time_dimension, dtype=self.dtype, **grid_kwargs)
[docs] @_cached def symbol(self, name, dtype=np.float32, **kwargs): """ Create a Devito Function with parameters provided. Parameters ---------- name : str Name of the function. dtype : data-type, optional Data type for the symbol, defaults to float32. kwargs Additional arguments for the Devito constructor. Returns ------- devito.Symbol Generated symobl. """ fun = devito.Symbol(name=name, dtype=dtype, **kwargs) return fun
[docs] @_cached def function(self, name, space_order=None, **kwargs): """ Create a Devito Function with parameters provided. Parameters ---------- name : str Name of the function. space_order : int, optional Space order of the discretisation, defaults to the grid space order. kwargs Additional arguments for the Devito constructor. Returns ------- devito.Function Generated function. """ space_order = self.space_order if space_order is None else space_order fun = devito.Function(name=name, grid=kwargs.pop('grid', self.devito_grid), space_order=space_order, dtype=kwargs.pop('dtype', self.dtype), **kwargs) return fun
[docs] @_cached def time_function(self, name, space_order=None, time_order=None, **kwargs): """ Create a Devito TimeFunction with parameters provided. Parameters ---------- name : str Name of the function. space_order : int, optional Space order of the discretisation, defaults to the grid space order. time_order : int, optional Time order of the discretisation, defaults to the grid time order. kwargs Additional arguments for the Devito constructor. Returns ------- devito.TimeFunction Generated function. """ space_order = self.space_order if space_order is None else space_order time_order = self.time_order if time_order is None else time_order fun = devito.TimeFunction(name=name, grid=kwargs.pop('grid', self.devito_grid), time_order=time_order, space_order=space_order, dtype=kwargs.pop('dtype', self.dtype), **kwargs) return fun
[docs] @_cached def vector_function(self, name, space_order=None, **kwargs): """ Create a Devito VectorFunction with parameters provided. Parameters ---------- name : str Name of the function. space_order : int, optional Space order of the discretisation, defaults to the grid space order. kwargs Additional arguments for the Devito constructor. Returns ------- devito.VectorFunction Generated function. """ space_order = self.space_order if space_order is None else space_order fun = devito.VectorFunction(name=name, grid=kwargs.pop('grid', self.devito_grid), space_order=space_order, dtype=kwargs.pop('dtype', self.dtype), **kwargs) return fun
[docs] @_cached def vector_time_function(self, name, space_order=None, time_order=None, **kwargs): """ Create a Devito VectorTimeFunction with parameters provided. Parameters ---------- name : str Name of the function. space_order : int, optional Space order of the discretisation, defaults to the grid space order. time_order : int, optional Time order of the discretisation, defaults to the grid time order. kwargs Additional arguments for the Devito constructor. Returns ------- devito.VectorTimeFunction Generated function. """ space_order = self.space_order if space_order is None else space_order time_order = self.time_order if time_order is None else time_order fun = devito.VectorTimeFunction(name=name, grid=kwargs.pop('grid', self.devito_grid), time_order=time_order, space_order=space_order, dtype=kwargs.pop('dtype', self.dtype), **kwargs) return fun
[docs] @_cached def tensor_time_function(self, name, space_order=None, time_order=None, **kwargs): """ Create a Devito TensorTimeFunction with parameters provided. Parameters ---------- name : str Name of the function. space_order : int, optional Space order of the discretisation, defaults to the grid space order. time_order : int, optional Time order of the discretisation, defaults to the grid time order. kwargs Additional arguments for the Devito constructor. Returns ------- devito.TimeFunction Generated function. """ space_order = self.space_order if space_order is None else space_order time_order = self.time_order if time_order is None else time_order fun = devito.TensorTimeFunction(name=name, grid=kwargs.pop('grid', self.devito_grid), time_order=time_order, space_order=space_order, dtype=kwargs.pop('dtype', self.dtype), **kwargs) return fun
[docs] @_cached def undersampled_time_function(self, name, factor, time_bounds=None, space_order=None, time_order=None, **kwargs): """ Create an undersampled version of a Devito function with parameters provided. Parameters ---------- name : str Name of the function. factor : int Undersampling factor. time_bounds : tuple, optional Timestep bounds in which the function is sampled, defaults to all timesteps. space_order : int, optional Space order of the discretisation, defaults to the grid space order. time_order : int, optional Time order of the discretisation, defaults to the grid time order. kwargs Additional arguments for the Devito constructor. Returns ------- devito.Function Generated function. """ time_bounds = time_bounds or (0, self.time.extended_num-1) time_under, buffer_size = self._time_undersampled('time_under', factor, time_bounds) compression = kwargs.pop('compression', None) fun = self.time_function(name, space_order=space_order, time_order=time_order, time_dim=time_under, save=buffer_size, dtype=kwargs.pop('dtype', self.dtype), compression=compression, **kwargs) space_dims = fun.dimensions[1:] return fun.func(time_under - int(time_bounds[0] // factor), *space_dims)
[docs] def undersampled_time_derivative(self, fun, factor, time_bounds=None, offset=None, deriv_order=1, fd_order=1): offset = offset or (0, 0) time_under, buffer_size = self._time_undersampled('time_under_d', factor, time_bounds, offset) deriv = devito.Derivative(fun, (fun.dimensions[0], deriv_order), fd_order=fd_order) deriv = deriv.xreplace({fun.dimensions[0]: time_under}) return deriv
def _time_undersampled(self, name, factor, time_bounds=None, offset=None): time_bounds = time_bounds or (0, self.time.extended_num - 1) offset = offset or (0, 0) time_dim = self.devito_grid.time_dim condition = sympy.And(devito.symbolics.CondEq(time_dim % factor, 0), devito.Ge(time_dim, time_bounds[0] + offset[0]), devito.Le(time_dim, time_bounds[1] - offset[1]), ) time_under = devito.ConditionalDimension('%s%d' % (name, self._time_under_count), parent=time_dim, factor=factor, condition=condition) self._time_under_count += 1 # buffer_size = (time_bounds[1] - time_bounds[0] + factor) // factor + 1 # TODO Force larger buffer size to prevent devito issue buffer_size = (self.time.extended_num - 1 - 0 + factor) // factor + 1 return time_under, buffer_size
[docs] @_cached def sparse_time_function(self, name, num=1, space_order=None, time_order=None, coordinates=None, interpolation_type='linear', **kwargs): """ Create a Devito SparseTimeFunction with parameters provided. Parameters ---------- name : str Name of the function. num : int, optional Number of points in the function, defaults to 1. space_order : int, optional Space order of the discretisation, defaults to the grid space order. time_order : int, optional Time order of the discretisation, defaults to the grid time order. coordinates : ndarray, optional Spatial coordinates of the sparse points (num points, dimensions), only needed when interpolation is not linear. interpolation_type : str, optional Type of interpolation to perform (``linear``, ``sinc``, or ``hicks``), defaults to ``linear``, computationally more efficient but less accurate. kwargs Additional arguments for the Devito constructor. Returns ------- devito.SparseTimeFunction Generated function. """ space_order = self.space_order if space_order is None else space_order time_order = self.time_order if time_order is None else time_order time_bounds = kwargs.pop('time_bounds', (0, self.time.extended_num)) smooth = kwargs.pop('smooth', False) # Define variables p_dim = kwargs.pop('p_dim', devito.Dimension(name='p_%s' % name)) sparse_kwargs = dict(name=name, grid=kwargs.pop('grid', self.devito_grid), dimensions=kwargs.get('dimensions', (self.devito_grid.time_dim, p_dim)), npoint=num, nt=time_bounds[1]-0, space_order=space_order, time_order=time_order, dtype=kwargs.pop('dtype', self.dtype)) sparse_kwargs.update(kwargs) if interpolation_type == 'linear': fun = devito.SparseTimeFunction(**sparse_kwargs) elif interpolation_type == 'sinc': r = sparse_kwargs.pop('r', 7) fun = devito.SparseTimeFunction(interpolation='sinc', r=r, coordinates=coordinates, **sparse_kwargs) elif interpolation_type == 'hicks': r = sparse_kwargs.pop('r', 7) reference_gridpoints, coefficients = self._calculate_hicks(coordinates, smooth=smooth) fun = devito.PrecomputedSparseTimeFunction(r=r+1, gridpoints=reference_gridpoints, interpolation_coeffs=coefficients, **sparse_kwargs) else: raise ValueError('Only "linear" and "hicks" interpolations are allowed.') return fun
[docs] @_cached def sparse_function(self, name, num=1, space_order=None, coordinates=None, interpolation_type='linear', **kwargs): """ Create a Devito SparseFunction with parameters provided. Parameters ---------- name : str Name of the function. num : int, optional Number of points in the function, defaults to 1. space_order : int, optional Space order of the discretisation, defaults to the grid space order. coordinates : ndarray, optional Spatial coordinates of the sparse points (num points, dimensions), only needed when interpolation is not linear. interpolation_type : str, optional Type of interpolation to perform (``linear`` or ``hicks``), defaults to ``linear``, computationally more efficient but less accurate. kwargs Additional arguments for the Devito constructor. Returns ------- devito.SparseTimeFunction Generated function. """ space_order = self.space_order if space_order is None else space_order # Define variables p_dim = kwargs.pop('p_dim', devito.Dimension(name='p_%s' % name)) sparse_kwargs = dict(name=name, grid=kwargs.pop('grid', self.devito_grid), dimensions=kwargs.get('dimensions', (p_dim,)), npoint=num, space_order=space_order, dtype=kwargs.pop('dtype', self.dtype)) sparse_kwargs.update(kwargs) if interpolation_type == 'linear': fun = devito.SparseFunction(**sparse_kwargs) elif interpolation_type == 'hicks': r = sparse_kwargs.pop('r', 7) reference_gridpoints, coefficients = self._calculate_hicks(coordinates) fun = devito.PrecomputedSparseFunction(r=r+1, gridpoints=reference_gridpoints, interpolation_coeffs=coefficients, **sparse_kwargs) else: raise ValueError('Only "linear" and "hicks" interpolations are allowed.') return fun
[docs] def func(self, name, cached=False): """ Re-instantiate devito function, if ``name`` is cached. Parameters ---------- name : str Name of the function. cached : bool, optional Whether to cache the result of the func call, defaults to ``False``. Returns ------- """ func = self.cached_funcs[name] args, kwargs = self.cached_args[name] return func(self, *args, **kwargs, cached=cached, replace_cached=cached)
[docs] def deallocate(self, name, collect=False): """ Remove internal references to data buffers, if ``name`` is cached. Parameters ---------- name : str Name of the function. collect : bool, optional Whether to garbage collect after deallocate, defaults to ``False``. Returns ------- """ if name in self.vars: if hasattr(self.vars[name], 'is_VectorValued') and self.vars[name].is_VectorValued: for dim in range(self.space.dim): del self.vars[name][dim]._data self.vars[name][dim]._data = None else: del self.vars[name]._data self.vars[name]._data = None if collect: gc.collect()
[docs] def delete(self, name, collect=False): """ Remove internal references to devito function, if ``name`` is cached. Parameters ---------- name : str Name of the function. collect : bool, optional Whether to garbage collect after deallocate, defaults to ``False``. Returns ------- """ if name in self.vars: del self.vars[name] del self.cached_funcs[name] del self.cached_args[name] if collect: devito.clear_cache(force=True)
[docs] def with_halo(self, data, value=None, time_dependent=False, is_vector=False, **kwargs): """ Pad ndarray with appropriate halo given the grid space order. Parameters ---------- data : ndarray Array to pad value : float, optional Value used for the filling, defaults to edge value. time_dependent : bool, optional Whether the array should be considered time dependent, defaults to ``False``. is_vector : bool, optional Whether the array should be considered a vector field, defaults to ``False``. Returns ------- ndarray Padded array. """ space_order = kwargs.pop('space_order', self.space_order) pad_widths = [[space_order, space_order] for _ in self.space.shape] if time_dependent: pad_widths.insert(0, [0, 0]) if is_vector: pad_widths.insert(0, [0, 0]) if value is None: return np.pad(data, pad_widths, mode='edge') else: return np.pad(data, pad_widths, mode='constant', constant_values=value)
def _calculate_hicks(self, coordinates, smooth=False): space = self.space # Calculate the reference gridpoints and offsets grid_coordinates = (coordinates - np.array(space.pml_origin)) / np.array(space.spacing) reference_gridpoints = np.floor(grid_coordinates).astype(np.int32) offsets = grid_coordinates - reference_gridpoints # Pre-calculate stuff kaiser_b = 4.14 kaiser_half_width = 3 kaiser_den = scipy.special.iv(0, kaiser_b) kaiser_extended_width = kaiser_half_width/0.99 # Calculate coefficients r = 2*kaiser_half_width+1 num = coordinates.shape[0] coefficients = np.zeros((num, space.dim, r+1)) for grid_point in range(-kaiser_half_width, kaiser_half_width+1): index = kaiser_half_width + grid_point x = offsets - grid_point weights = (x / kaiser_extended_width)**2 weights[weights > 1] = 1 b_weights = scipy.special.iv(0, kaiser_b * np.sqrt(1 - weights)) / kaiser_den coefficients[:, :, index] = np.sinc(x) * b_weights # Smooth if needed if smooth: n = kaiser_half_width-1 a = coefficients[:, :, n] b = coefficients[:, :, n+1] c = coefficients[:, :, n+2] coefficients[:, :, n-1] = coefficients[:, :, n-1] + a*0.01 coefficients[:, :, n] = a*0.98 + b*0.03 coefficients[:, :, n+1] = b*0.94 + (a+c)*0.01 coefficients[:, :, n+2] = c*0.98 + b*0.03 coefficients[:, :, n+3] = coefficients[:, :, n+3] + c*0.01 return reference_gridpoints, coefficients
[docs] class OperatorDevito: """ Instances of this class encapsulate Devito operators, how to configure them and how to run them. Parameters ---------- grid : GridDevito, optional Predefined GridDevito. A new one will be created unless specified. name : str Name to give to the operator, defaults to ``kernel``. """ def __init__(self, *args, grid=None, name='kernel', **kwargs): self.name = name self.devito_operator = None self.devito_context = {} self.grid = GridDevito(*args, **kwargs) if grid is None else grid
[docs] def set_operator(self, op, **kwargs): """ Set up a Devito operator from a list of operations. Parameters ---------- op : list List of operations to be given to the devito.Operator instance. kwargs : optional Configuration parameters to set for Devito overriding defaults. Returns ------- """ from mosaic.utils.logger import log_level platform = kwargs.pop('platform', None) devito_config = kwargs.pop('devito_config', {}) subs = self.grid.devito_grid.spacing_map if self.grid.time_dim: time = self.grid.time_dim time_spacing = self.grid.devito_grid.time_dim.spacing subs = {**subs, **{time_spacing: devito_config.get('dt', time.step)}} if platform is None or platform == 'cpu': default_config = { 'name': self.name, 'subs': subs, 'opt': 'advanced', } elif platform == 'cpu-icc': default_config = { 'name': self.name, 'subs': subs, 'opt': 'advanced', 'compiler': 'icc', } elif platform == 'cpu-nvc': default_config = { 'name': self.name, 'subs': subs, 'opt': 'advanced', 'compiler': 'nvc', } elif platform == 'nvidia-acc' or platform == 'nvidia-nvc': default_config = { 'name': self.name, 'subs': subs, 'opt': 'advanced', 'autotuning': 'off', 'compiler': 'nvc', 'language': 'openacc', 'platform': 'nvidiaX', } elif platform == 'nvidia-cuda' and devito.pro_available: default_config = { 'name': self.name, 'subs': subs, 'opt': 'advanced', 'compiler': 'cuda', 'language': 'cuda', 'platform': 'nvidiaX', } elif platform == 'amd-hip' and devito.pro_available: default_config = { 'name': self.name, 'subs': subs, 'opt': 'advanced', 'compiler': 'hip', 'language': 'hip', 'platform': 'amdgpuX', } else: raise ValueError('Unrecognised platform %s' % platform) default_config.update(devito_config) context = {'log-level': 'DEBUG' if log_level in ['perf', 'debug'] else 'INFO'} compiler_config = {} for key, value in default_config.items(): if key in devito.configuration and key != 'opt': context[key] = value else: compiler_config[key] = value self.devito_context = context logger = mosaic.logger() logger.perf('Operator `%s` instance configuration:' % self.name) for key, value in default_config.items(): logger.perf('\t * %s=%s' % (key, value)) with devito.switchconfig(**self.devito_context): self.devito_operator = devito.Operator(op, **compiler_config)
[docs] def compile(self): """ Compile the operator. Returns ------- """ self.devito_operator.cfunction
[docs] def run(self, **kwargs): """ Run the operator. Returns ------- """ default_kwargs = {} for arg in self.devito_operator.parameters: if arg.name in self.grid.vars: default_kwargs[arg.name] = self.grid.vars[arg.name] autotune = kwargs.pop('autotune', None) default_kwargs.update(kwargs) if self.grid.time_dim: time = self.grid.time_dim default_kwargs['dt'] = default_kwargs.get('dt', time.step) if self.grid.num_inner is not None: default_kwargs['dt_inner'] = default_kwargs.get('dt_inner', time.step/self.grid.num_inner) default_kwargs['time_inner_m'] = default_kwargs.get('time_inner_m', 0) default_kwargs['time_inner_M'] = default_kwargs.get('time_inner_M', self.grid.num_inner-1) runtime_context = {} runtime_kwargs = {} for key, value in default_kwargs.items(): if key in devito.configuration: runtime_context[key] = value else: runtime_kwargs[key] = value with devito.switchconfig(**self.devito_context, **runtime_context): if autotune is None: try: tuned = self.devito_operator._state['autotuning'][-1]['tuned'] runtime_kwargs.update(tuned) runtime_kwargs['autotune'] = 'off' except KeyError: pass self.devito_operator.apply(**runtime_kwargs)
def config_devito(**kwargs): from mosaic.utils.logger import log_level # global devito config default_config = { 'autotuning': ['aggressive', 'runtime'], 'develop-mode': False, 'mpi': False, 'log-level': 'DEBUG' if log_level in ['perf', 'debug'] else 'INFO', } compiler = os.getenv('DEVITO_COMPILER', None) if compiler is not None: default_config['compiler'] = compiler language = os.getenv('DEVITO_LANGUAGE', 'openmp') if language is not None: default_config['language'] = language devito_config = kwargs.pop('devito_config', {}) default_config.update(devito_config) logger = mosaic.logger() logger.perf('Default Devito configuration:') for key, value in default_config.items(): logger.perf('\t * %s=%s' % (key, value)) devito.parameters.configuration[key] = value # fix devito logging devito_logger = logging.getLogger('Devito') devito_logger.setLevel(logging.DEBUG if log_level in ['perf', 'debug'] else logging.INFO) devito.logger.logger = devito_logger class RerouteFilter(logging.Filter): def __init__(self): super().__init__() def filter(self, record): _logger = mosaic.logger() if record.levelno == devito.logger.PERF: _logger.perf(record.msg) elif record.levelno == logging.ERROR: _logger.error(record.msg) elif record.levelno == logging.WARNING: _logger.warning(record.msg) elif record.levelno == logging.DEBUG: _logger.debug(record.msg) else: _logger.perf(record.msg) return False devito_logger.addFilter(RerouteFilter()) runtime = mosaic.runtime() if runtime is not None and runtime.mode == 'local': devito_logger.propagate = False