Exemplo n.º 1
0
    def _indices(cls, **kwargs):
        """Return the default dimension indices for a given data shape

        :param dimensions: Optional, list of :class:`Dimension`
                           objects that defines data layout.
        :param shape: Optional, shape of the spatial data to
                      automatically infer dimension symbols.
        :return: Dimension indices used for each axis.
        """
        dimensions = kwargs.get('dimensions', None)
        if dimensions is None:
            # Infer dimensions from default and data shape
            if 'shape' not in kwargs:
                error("Creating symbolic data objects requries either"
                      "a 'shape' or 'dimensions' argument")
                raise ValueError("Unknown symbol dimensions or shape")
            _indices = (x, y, z)
            shape = kwargs.get('shape')
            if len(shape) <= 3:
                dimensions = _indices[:len(shape)]
            else:
                dimensions = [
                    Dimension("x%d" % i) for i in range(1,
                                                        len(shape) + 1)
                ]
        return dimensions
Exemplo n.º 2
0
    def _indices(cls, **kwargs):
        """Return the default dimension indices for a given data shape

        :param grid: :class:`Grid` object from which to infer the data
                     shape and :class:`Dimension` indices.
        :return: Dimension indices used for each axis.
        """
        save = kwargs.get('save', None)
        grid = kwargs.get('grid', None)
        time_dim = kwargs.get('time_dim', None)

        if grid is None:
            error('TimeFunction objects require a grid parameter.')
            raise ValueError('No grid provided for TimeFunction.')

        if time_dim is None:
            time_dim = grid.time_dim if save else grid.stepping_dim
        elif not isinstance(time_dim, TimeDimension):
            raise ValueError("time_dim must be a TimeDimension, not %s" %
                             type(time_dim))

        assert (isinstance(time_dim, Dimension) and time_dim.is_Time)

        _indices = Function._indices(**kwargs)
        return tuple([time_dim] + list(_indices))
Exemplo n.º 3
0
def malloc_aligned(shape, alignment=None, dtype=np.float32):
    """ Allocate memory using the C function malloc_aligned
    :param shape: Shape of the array to allocate
    :param alignment: number of bytes to align to. Defaults to
    page size if not set.
    :param dtype: Numpy datatype to allocate. Default to np.float32

    :returns (pointer, data_pointer) the first element of the tuple
    is the reference that can be used to access the data as a ctypes
    object. The second element is the low-level reference that is
    needed only for the call to free.
    """
    libc = ctypes.CDLL(find_library('c'))
    data_pointer = ctypes.cast(ctypes.c_void_p(),
                               ctypes.POINTER(ctypes.c_float))
    arraysize = int(reduce(mul, shape))
    ctype = convert_dtype_to_ctype(dtype)
    if alignment is None:
        alignment = libc.getpagesize()

    ret = libc.posix_memalign(ctypes.byref(data_pointer), alignment,
                              ctypes.c_ulong(arraysize * ctypes.sizeof(ctype)))
    if not ret == 0:
        error("Unable to allocate memory for shape %s", str(shape))
        return None

    data_pointer = ctypes.cast(
        data_pointer, np.ctypeslib.ndpointer(dtype=dtype, shape=shape))

    pointer = np.ctypeslib.as_array(data_pointer, shape=shape)
    return (pointer, data_pointer)
Exemplo n.º 4
0
    def __new__(cls,
                name,
                grid,
                ntime=None,
                npoint=None,
                data=None,
                coordinates=None,
                **kwargs):
        p_dim = kwargs.get('dimension', Dimension(name='p_%s' % name))
        npoint = npoint or coordinates.shape[0]
        if data is None:
            if ntime is None:
                error('Either data or ntime are required to'
                      'initialise source/receiver objects')
        else:
            ntime = ntime or data.shape[0]

        # Create the underlying SparseTimeFunction object
        obj = SparseTimeFunction.__new__(cls,
                                         name=name,
                                         grid=grid,
                                         dimensions=[grid.time_dim, p_dim],
                                         npoint=npoint,
                                         nt=ntime,
                                         coordinates=coordinates,
                                         **kwargs)

        # If provided, copy initial data into the allocated buffer
        if data is not None:
            obj.data[:] = data
        return obj
Exemplo n.º 5
0
    def __init__(self, *args, **kwargs):
        if not self._cached():
            self.name = kwargs.get('name')
            self.grid = kwargs.get('grid', None)

            if self.grid is None:
                self.shape_domain = kwargs.get('shape', None)
                self.dtype = kwargs.get('dtype', np.float32)
                if self.shape_domain is None:
                    error("Creating a Function requires either 'shape'"
                          "or a 'grid' argument")
                    raise ValueError("Unknown symbol dimensions or shape")
            else:
                self.shape_domain = self.grid.shape_domain
                self.dtype = kwargs.get('dtype', self.grid.dtype)
            self.indices = self._indices(**kwargs)
            self.staggered = kwargs.get('staggered',
                                        tuple(0 for _ in self.indices))
            if len(self.staggered) != len(self.indices):
                error("Staggering argument needs %s entries for indices %s" %
                      (len(self.indices), self.indices))
                raise ValueError("Insufficient staggered entries")

            self.space_order = kwargs.get('space_order', 1)
            self.initializer = kwargs.get('initializer', None)
            if self.initializer is not None:
                assert (callable(self.initializer))
            self._first_touch = kwargs.get('first_touch',
                                           configuration['first_touch'])
            self._data_object = None

            # Dynamically add derivative short-cuts
            self._initialize_derivatives()
Exemplo n.º 6
0
    def _indices(cls, **kwargs):
        """Return the default dimension indices for a given data shape

        :param grid: :class:`Grid` that defines the spatial domain.
        :param dimensions: Optional, list of :class:`Dimension`
                           objects that defines data layout.
        :return: Dimension indices used for each axis.

        ..note::

        Only one of :param grid: or :param dimensions: is required.
        """
        grid = kwargs.get('grid', None)
        dimensions = kwargs.get('dimensions', None)
        if grid is None:
            if dimensions is None:
                error("Creating a Function object requries either "
                      "a 'grid' or the 'dimensions' argument.")
                raise ValueError("Unknown symbol dimensions or shape")
        else:
            if dimensions is not None:
                warning(
                    "Creating Function with 'grid' and 'dimensions' "
                    "argument; ignoring the 'dimensions' and using 'grid'.")
            dimensions = grid.dimensions
        return dimensions
Exemplo n.º 7
0
    def coefficients(self):
        """Symbolic expression for the coefficients for sparse point
        interpolation according to:
        https://en.wikipedia.org/wiki/Bilinear_interpolation.

        :returns: List of coefficients, eg. [b_11, b_12, b_21, b_22]
        """
        # Grid indices corresponding to the corners of the cell
        x1, y1, z1, x2, y2, z2 = sympy.symbols('x1, y1, z1, x2, y2, z2')
        # Coordinate values of the sparse point
        px, py, pz = self.point_symbols
        if self.grid.dim == 2:
            A = sympy.Matrix([[1, x1, y1, x1*y1],
                              [1, x1, y2, x1*y2],
                              [1, x2, y1, x2*y1],
                              [1, x2, y2, x2*y2]])

            p = sympy.Matrix([[1],
                              [px],
                              [py],
                              [px*py]])

            # Map to reference cell
            x, y = self.grid.dimensions
            reference_cell = {x1: 0, y1: 0, x2: x.spacing, y2: y.spacing}

        elif self.grid.dim == 3:
            A = sympy.Matrix([[1, x1, y1, z1, x1*y1, x1*z1, y1*z1, x1*y1*z1],
                              [1, x1, y2, z1, x1*y2, x1*z1, y2*z1, x1*y2*z1],
                              [1, x2, y1, z1, x2*y1, x2*z1, y2*z1, x2*y1*z1],
                              [1, x1, y1, z2, x1*y1, x1*z2, y1*z2, x1*y1*z2],
                              [1, x2, y2, z1, x2*y2, x2*z1, y2*z1, x2*y2*z1],
                              [1, x1, y2, z2, x1*y2, x1*z2, y2*z2, x1*y2*z2],
                              [1, x2, y1, z2, x2*y1, x2*z2, y1*z2, x2*y1*z2],
                              [1, x2, y2, z2, x2*y2, x2*z2, y2*z2, x2*y2*z2]])

            p = sympy.Matrix([[1],
                              [px],
                              [py],
                              [pz],
                              [px*py],
                              [px*pz],
                              [py*pz],
                              [px*py*pz]])

            # Map to reference cell
            x, y, z = self.grid.dimensions
            reference_cell = {x1: 0, y1: 0, z1: 0, x2: x.spacing,
                              y2: y.spacing, z2: z.spacing}
        else:
            error('Point interpolation only supported for 2D and 3D')
            raise NotImplementedError('Interpolation coefficients not '
                                      'implemented for %d dimensions.'
                                      % self.grid.dim)

        A = A.subs(reference_cell)
        return A.inv().T.dot(p)
Exemplo n.º 8
0
def sniff_compiler_version(cc):
    """
    Detect the compiler version.

    Adapted from: ::

        https://github.com/OP2/PyOP2/
    """
    try:
        res = run([cc, "--version"], stdout=PIPE, stderr=DEVNULL)
        ver = res.stdout.decode("utf-8")
        if not ver:
            return version.LooseVersion("unknown")
    except UnicodeDecodeError:
        return version.LooseVersion("unknown")
    except FileNotFoundError:
        error("The `%s` compiler isn't available on this system" % cc)
        sys.exit(1)

    if ver.startswith("gcc"):
        compiler = "gcc"
    elif ver.startswith("clang"):
        compiler = "clang"
    elif ver.startswith("Apple LLVM"):
        compiler = "clang"
    elif ver.startswith("icc"):
        compiler = "icc"
    elif ver.startswith("pgcc"):
        compiler = "pgcc"
    else:
        compiler = "unknown"

    ver = version.LooseVersion("unknown")
    if compiler in ["gcc", "icc"]:
        try:
            # gcc-7 series only spits out patch level on dumpfullversion.
            res = run([cc, "-dumpfullversion"], stdout=PIPE, stderr=DEVNULL)
            ver = res.stdout.decode("utf-8")
            ver = '.'.join(ver.strip().split('.')[:3])
            if not ver:
                res = run([cc, "-dumpversion"], stdout=PIPE, stderr=DEVNULL)
                ver = res.stdout.decode("utf-8")
                ver = '.'.join(ver.strip().split('.')[:3])
                if not ver:
                    return version.LooseVersion("unknown")
            ver = version.StrictVersion(ver)
        except UnicodeDecodeError:
            pass

    # Pure integer versions (e.g., ggc5, rather than gcc5.0) need special handling
    try:
        ver = version.StrictVersion(float(ver))
    except TypeError:
        pass

    return ver
Exemplo n.º 9
0
    def _write_block_report(self, times):
        """Writes auto tuning report for block sizes

        :param times: sorted list - times with block sizes
        :raises IOError: if fails to write report
        """
        try:
            full_report_text = ["%s %f\n" % (str(block), timee) for block, timee in times]

            # Cache blocking dimensions
            cb_dims = str(self.blocked_dims).replace(" ", '')
            shape = str(self.op.shape).replace(" ", '')

            # Writes all auto tuning information into full report
            with open(path.join(self.report_dir,
                                "%s_time_o_%s_spc_bo_%s_shp_%s_b_%s_report.txt" %
                      (self.op.getName(), self.op.time_order,
                       self.op.spc_border, shape, cb_dims)), 'w') as f:
                f.writelines(full_report_text)

            # string that describes the model
            model_desc_str = self.model_desc_template % (self.op.getName(),
                                                         self.op.time_order,
                                                         self.op.spc_border,
                                                         shape, cb_dims)
            str_to_write = "%s %s\n" % (model_desc_str, str(times[0][0]).replace(" ", ''))

            # initialises report file if it does not exist
            if not path.isfile(self.final_report_path):
                with open(self.final_report_path, 'w') as final_report:
                    final_report.write("f name, time o, space bo ,"
                                       "shape, block dims, best block size\n")
                    final_report.write(str_to_write)  # writes the string
                return
            else:
                # reads all the contents, checks whether entry already exist and updates.
                # Otherwise appends to the end of the file
                with open(self.final_report_path, 'r') as final_report:
                    lines = final_report.readlines()
                entry_found = False

                for i in range(1, len(lines)):
                    if model_desc_str in lines[i]:
                        lines[i] = str_to_write
                        entry_found = True
                        break

            if not entry_found:  # if entry not found append string to the end of file
                lines.append(str_to_write)
            # writes all the contents
            with open(self.final_report_path, 'w') as final_report:
                final_report.writelines(lines)

        except IOError as e:
            error("Failed to write auto tuning report because %s" % e.message)
Exemplo n.º 10
0
def GradientOperator(model,
                     source,
                     receiver,
                     space_order=4,
                     save=True,
                     kernel='OT2',
                     **kwargs):
    """
    Constructor method for the gradient operator in an acoustic media

    :param model: :class:`Model` object containing the physical parameters
    :param source: :class:`PointData` object containing the source geometry
    :param receiver: :class:`PointData` object containing the acquisition geometry
    :param time_order: Time discretization order
    :param space_order: Space discretization order
    """
    m, damp = model.m, model.damp

    # Gradient symbol and wavefield symbols
    grad = Function(name='grad', grid=model.grid)
    u = TimeFunction(name='u',
                     grid=model.grid,
                     save=source.nt if save else None,
                     time_order=2,
                     space_order=space_order)
    v = TimeFunction(name='v',
                     grid=model.grid,
                     save=None,
                     time_order=2,
                     space_order=space_order)
    rec = Receiver(name='rec',
                   grid=model.grid,
                   time_range=receiver.time_range,
                   npoint=receiver.npoint)

    s = model.grid.stepping_dim.spacing
    eqn = iso_stencil(v, m, s, damp, kernel, forward=False)

    if kernel == 'OT2':
        gradient_update = Inc(grad, grad - u.dt2 * v)
    elif kernel == 'OT4':
        gradient_update = Inc(
            grad, grad - (u.dt2 + s**2 / 12.0 * u.laplace2(m**(-2))) * v)
    else:
        error("Unrecognized kernel, has to be OT2 or OT4")
    # Add expression for receiver injection
    receivers = rec.inject(field=v.backward,
                           expr=rec * s**2 / m,
                           offset=model.nbpml)

    # Substitute spacing terms to reduce flops
    return Operator(eqn + receivers + [gradient_update],
                    subs=model.spacing_map,
                    name='Gradient',
                    **kwargs)
Exemplo n.º 11
0
 def point_increments(self):
     """Index increments in each dimension for each point symbol"""
     if self.grid.dim == 2:
         return ((0, 0), (0, 1), (1, 0), (1, 1))
     elif self.grid.dim == 3:
         return ((0, 0, 0), (0, 1, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0),
                 (0, 1, 1), (1, 0, 1), (1, 1, 1))
     else:
         error('Point interpolation only supported for 2D and 3D')
         raise NotImplementedError('Point increments not defined '
                                   'for %d dimensions.' % self.grid.dim)
Exemplo n.º 12
0
 def adjoint(self, matvec):
     if matvec == direct:
         return self
     else:
         if self == centered:
             return centered
         elif self == right:
             return left
         elif self == left:
             return right
         else:
             error("Unsupported side value")
Exemplo n.º 13
0
def sniff_compiler_version(cc):
    """
    Detect the compiler version.

    Adapted from: ::

        https://github.com/OP2/PyOP2/
    """
    try:
        ver = check_output([cc, "--version"]).decode("utf-8")
    except (CalledProcessError, UnicodeDecodeError):
        return version.LooseVersion("unknown")
    except FileNotFoundError:
        error("The `%s` compiler isn't available on this system" % cc)
        sys.exit(1)

    if ver.startswith("gcc"):
        compiler = "gcc"
    elif ver.startswith("clang"):
        compiler = "clang"
    elif ver.startswith("Apple LLVM"):
        compiler = "clang"
    elif ver.startswith("icc"):
        compiler = "icc"
    else:
        compiler = "unknown"

    ver = version.LooseVersion("unknown")
    if compiler in ["gcc", "icc"]:
        try:
            # gcc-7 series only spits out patch level on dumpfullversion.
            ver = check_output([cc, "-dumpfullversion"], stderr=DEVNULL).decode("utf-8")
            ver = '.'.join(ver.strip().split('.')[:3])
            ver = version.StrictVersion(ver)
        except CalledProcessError:
            try:
                ver = check_output([cc, "-dumpversion"], stderr=DEVNULL).decode("utf-8")
                ver = '.'.join(ver.strip().split('.')[:3])
                ver = version.StrictVersion(ver)
            except (CalledProcessError, UnicodeDecodeError):
                pass
        except UnicodeDecodeError:
            pass

    # Pure integer versions (e.g., ggc5, rather than gcc5.0) need special handling
    try:
        ver = version.StrictVersion(float(ver))
    except TypeError:
        pass

    return ver
Exemplo n.º 14
0
 def __indices_setup__(cls, **kwargs):
     grid = kwargs.get('grid')
     dimensions = kwargs.get('dimensions')
     if grid is None:
         if dimensions is None:
             error("Creating a Function object requries either "
                   "a 'grid' or the 'dimensions' argument.")
             raise ValueError("Unknown symbol dimensions or shape")
     else:
         if dimensions is not None:
             warning(
                 "Creating Function with 'grid' and 'dimensions' "
                 "argument; ignoring the 'dimensions' and using 'grid'.")
         dimensions = grid.dimensions
     return dimensions
Exemplo n.º 15
0
    def __indices_setup__(cls, **kwargs):
        save = kwargs.get('save')
        grid = kwargs.get('grid')
        time_dim = kwargs.get('time_dim')

        if grid is None:
            error('TimeFunction objects require a grid parameter.')
            raise ValueError('No grid provided for TimeFunction.')

        if time_dim is None:
            time_dim = grid.time_dim if save else grid.stepping_dim
        elif not (isinstance(time_dim, Dimension) and time_dim.is_Time):
            raise ValueError("'time_dim' must be a time dimension")

        return (time_dim, ) + Function.__indices_setup__(**kwargs)
Exemplo n.º 16
0
 def apply(self, *args, **kwargs):
     """Apply defined stencil kernel to a set of data objects"""
     if len(args) <= 0:
         args = self.signature
     args = [a.data if isinstance(a, SymbolicData) else a for a in args]
     # Check shape of argument data
     for arg, v in zip(args, self.signature):
         if not isinstance(arg, np.ndarray):
             raise TypeError('No array data found for argument %s' % v.name)
         if arg.shape != v.shape:
             error('Expected argument %s with shape %s, but got shape %s' %
                   (v.name, v.shape, arg))
             raise ValueError('Argument with wrong shape')
     # Invoke kernel function with args
     self.cfunction(*args)
Exemplo n.º 17
0
    def _indices(cls, **kwargs):
        """Return the default dimension indices for a given data shape

        :param grid: :class:`Grid` object from which to infer the data
                     shape and :class:`Dimension` indices.
        :return: Dimension indices used for each axis.
        """
        save = kwargs.get('save', None)
        grid = kwargs.get('grid', None)

        if grid is None:
            error('TimeFunction objects require a grid parameter.')
            raise ValueError('No grid provided for TimeFunction.')

        tidx = grid.time_dim if save else grid.stepping_dim
        _indices = Function._indices(**kwargs)
        return tuple([tidx] + list(_indices))
Exemplo n.º 18
0
 def _dle_arguments(self, dim_sizes):
     # Add user-provided block sizes, if any
     dle_arguments = OrderedDict()
     autotune = True
     for i in self.dle_arguments:
         dim_size = dim_sizes.get(i.original_dim.name, i.original_dim.size)
         if dim_size is None:
             error('Unable to derive size of dimension %s from defaults. '
                   'Please provide an explicit value.' % i.original_dim.name)
             raise InvalidArgument('Unknown dimension size')
         if i.value:
             try:
                 dle_arguments[i.argument.name] = i.value(dim_size)
             except TypeError:
                 dle_arguments[i.argument.name] = i.value
                 autotune = False
         else:
             dle_arguments[i.argument.name] = dim_size
     return dle_arguments, autotune
Exemplo n.º 19
0
def laplacian(field, time_order, m, s):
    """
    Spacial discretization for the isotropic acoustic wave equation. For a 4th
    order in time formulation, the 4th order time derivative is replaced by a
    double laplacian:
    H = (laplacian + s**2/12 laplacian(1/m*laplacian))
    :param field: Symbolic TimeFunction object, solution to be computed
    :param time_order: time order
    :param m: square slowness
    :param s: symbol for the time-step
    :return: H
    """
    if time_order == 2:
        biharmonic = 0
    elif time_order == 4:
        biharmonic = field.laplace2(1 / m)
    else:
        error("Unsupported time order %d, order has to be 2 or 4" % time_order)
    return field.laplace + s**2 / 12 * biharmonic
Exemplo n.º 20
0
    def __init__(self, *args, **kwargs):
        if not self._cached():
            self.nt = kwargs.get('nt', 0)
            self.npoint = kwargs.get('npoint')
            kwargs['shape'] = (self.nt, self.npoint)
            super(SparseFunction, self).__init__(self, *args, **kwargs)

            if self.grid is None:
                error('SparseFunction objects require a grid parameter.')
                raise ValueError('No grid provided for SparseFunction.')

            # Allocate and copy coordinate data
            d = Dimension('d')
            self.coordinates = Function(name='%s_coords' % self.name,
                                        dimensions=[self.indices[-1], d],
                                        shape=(self.npoint, self.grid.dim))
            self._children.append(self.coordinates)
            coordinates = kwargs.get('coordinates', None)
            if coordinates is not None:
                self.coordinates.data[:] = coordinates[:]
Exemplo n.º 21
0
    def __new__(cls, *args, **kwargs):
        options = kwargs.get('options', {})

        key = cls
        obj = cls._cache_get(key)

        if obj is not None:
            newobj = sympy.Function.__new__(cls, *args, **options)
            newobj.__init_cached__(key)
            return newobj

        p_dim = kwargs.get('dimension', Dimension('p_%s' % kwargs.get("name")))
        npoint = kwargs.get("npoint")
        coords = kwargs.get("coordinates")
        if npoint is None:
            if coords is None:
                raise TypeError("Need either `npoint` or `coordinates`")
            else:
                npoint = coords.shape[0]

        grid = kwargs.get("grid")
        ntime = kwargs.get("ntime")
        if kwargs.get("data") is None:
            if ntime is None:
                error('Either data or ntime are required to'
                      'initialise source/receiver objects')
        else:
            ntime = kwargs.get("ntime") or kwargs.get("data").shape[0]

        # Create the underlying SparseTimeFunction object
        kwargs["nt"] = ntime
        kwargs['npoint'] = npoint
        obj = SparseTimeFunction.__new__(cls,
                                         dimensions=[grid.time_dim, p_dim],
                                         **kwargs)

        # If provided, copy initial data into the allocated buffer
        if kwargs.get("data") is not None:
            obj.data[:] = kwargs.get("data")

        return obj
Exemplo n.º 22
0
    def __init__(self, *args, **kwargs):
        if not self._cached():
            super(TimeFunction, self).__init__(*args, **kwargs)
            self.time_dim = kwargs.get('time_dim', None)
            self.time_order = kwargs.get('time_order', 1)
            self.save = kwargs.get('save', False)

            if not self.save:
                if self.time_dim is not None:
                    warning(
                        'Explicit time dimension size (time_dim) found for '
                        'TimeFunction symbol %s, despite \nusing a stepping time '
                        'dimension (save=False). This value will be ignored!' %
                        self.name)
                self.time_dim = self.time_order + 1
                self.indices[0].modulo = self.time_dim
            else:
                if self.time_dim is None:
                    error('Time dimension (time_dim) is required'
                          'to save intermediate data with save=True')
                    raise ValueError("Unknown time dimensions")
Exemplo n.º 23
0
    def unique(self, key):
        """
        Returns a unique value for a given key, if such a value
        exists, and raises a ``ValueError`` if it does not.

        :param key: Key for which to retrieve a unique value
        """
        candidates = self.getall(key)

        def compare_to_first(v):
            first = candidates[0]
            if isinstance(first, np.ndarray) or isinstance(v, np.ndarray):
                return (first == v).all()
            else:
                return first == v

        if len(candidates) == 1:
            return candidates[0]
        elif all(map(compare_to_first, candidates)):
            return candidates[0]
        else:
            error("Unable to find unique value for key %s, candidates: %s" %
                  (key, candidates))
            raise ValueError('Inconsistent values for key reduction')
Exemplo n.º 24
0
def locate_intel_advisor():
    """
    Detect if Intel Advisor is installed on the machine and return
    its location if it is.

    """
    path = None

    try:
        # Check if the directory to Intel Advisor is specified
        path = Path(os.environ['DEVITO_ADVISOR_DIR'])
    except KeyError:
        # Otherwise, 'sniff' the location of Advisor's directory
        error_msg = 'Intel Advisor cannot be found on your system, consider if you'\
                    ' have sourced its environment variables correctly. Information can'\
                    ' be found at https://software.intel.com/content/www/us/en/develop/'\
                    'documentation/advisor-user-guide/top/launch-the-intel-advisor/'\
                    'intel-advisor-cli/setting-and-using-intel-advisor-environment'\
                    '-variables.html'
        try:
            res = run(["advixe-cl", "--version"], stdout=PIPE, stderr=DEVNULL)
            ver = res.stdout.decode("utf-8")
            if not ver:
                error(error_msg)
                return None
        except (UnicodeDecodeError, FileNotFoundError):
            error(error_msg)
            return None

        env_path = os.environ["PATH"]
        env_path_dirs = env_path.split(":")

        for env_path_dir in env_path_dirs:
            # intel/advisor is the advisor directory for Intel Parallel Studio,
            # intel/oneapi/advisor is the directory for Intel oneAPI
            if "intel/advisor" in env_path_dir or "intel/oneapi/advisor" in env_path_dir:
                path = Path(env_path_dir)
                if path.name.startswith('bin'):
                    path = path.parent

        if not path:
            error(error_msg)
            return None

    if path.joinpath('bin64').joinpath('advixe-cl').is_file():
        return path
    else:
        warning("Requested `advisor` profiler, but couldn't locate executable"
                "in advisor directory")
        return None
Exemplo n.º 25
0
def staggered_diff(f, dim, order, stagger=centered, theta=0, phi=0):
    """
    Utility function to generate staggered derivatives
    :param f: function objects, eg. `f(x, y)` or `g(t, x, y, z)`.
    :param dims: symbol defining the dimension wrt. which
       to differentiate, eg. `x`, `y`, `z` or `t`.
    :param order: Order of the coefficient discretization and thus
                  the width of the resulting stencil expression.
    :param stagger: Shift for the FD, `left`, `right` or `centered`
    :param theta: Dip (or polar) angle for rotated FD
    :param phi: Azimuth angle for rotated FD
    """
    ndim = len(f.space_dimensions)
    off = dict([(d, 0) for d in f.space_dimensions])
    if stagger == left:
        off[dim] = -.5
    elif stagger == right:
        off[dim] = .5
    else:
        off[dim] = 0

    if theta == 0 and phi == 0:
        diff = dim.spacing
        idx = list(
            set([(dim + int(i + .5 + off[dim]) * diff)
                 for i in range(-int(order / 2), int(order / 2))]))
        if int(order / 2) == 1:
            idx = [dim - diff, dim]
        deriv = f.diff(dim).as_finite_difference(idx,
                                                 x0=dim +
                                                 off[dim] * dim.spacing)
        return deriv.evalf(_PRECISION)
    else:
        if ndim < 2 or ndim > 3:
            error("Only 2D and 3D supports rotated finite difference,"
                  " %d dimensions as input" % ndim)
            raise ValueError("Non supported number of dimensions")

        x = f.space_dimensions[0]
        z = f.space_dimensions[-1]
        idxx = list(
            set([(x + int(i + .5 + off[x]) * x.spacing)
                 for i in range(-int(order / 2), int(order / 2))]))
        dx = f.diff(x).as_finite_difference(idxx, x0=x + off[x] * x.spacing)
        dx = dx.evalf(_PRECISION)

        idxz = list(
            set([(z + int(i + .5 + off[z]) * z.spacing)
                 for i in range(-int(order / 2), int(order / 2))]))
        dz = f.diff(z).as_finite_difference(idxz, x0=z + off[z] * z.spacing)
        dz = dx.evalf(_PRECISION)

        dy = 0
        is_y = False

        if ndim == 3:
            y = f.space_dimensions[1]
            idxy = list(
                set([(y + int(i + .5 + off[y]) * y.spacing)
                     for i in range(-int(order / 2), int(order / 2))]))
            dy = f.diff(y).as_finite_difference(idxy,
                                                x0=y + off[y] * y.spacing)
            dy = dy.evalf(_PRECISION)
            is_y = (dim == y)

        if dim == x:
            return cos(theta) * cos(phi) * dx + sin(phi) * cos(theta) * dy -\
                sin(theta) * dz
        elif dim == z:
            return sin(theta) * cos(phi) * dx + sin(phi) * sin(theta) * dy +\
                cos(theta) * dz
        elif is_y:
            return -sin(phi) * dx + cos(phi) * dy
        else:
            return 0
Exemplo n.º 26
0
def fwi_gradient_shot(vp_in, i, solver_params):
    error("Initialising solver")
    tn = solver_params['tn']
    nbl = solver_params['nbl']
    space_order = solver_params['space_order']
    dtype = solver_params['dtype']
    origin = solver_params['origin']
    spacing = solver_params['spacing']

    shots_container = solver_params['shots_container']

    true_d, source_location, old_dt = load_shot(i, container=shots_container)

    model = Model(vp=vp_in,
                  nbl=nbl,
                  space_order=space_order,
                  dtype=dtype,
                  shape=vp_in.shape,
                  origin=origin,
                  spacing=spacing,
                  bcs="damp")
    geometry = create_geometry(model, tn, source_location)

    error("tn: %d, nt: %d, dt: %f" % (geometry.tn, geometry.nt, geometry.dt))

    error("Reinterpolate shot from %d samples to %d samples" %
          (true_d.shape[0], geometry.nt))
    true_d = reinterpolate(true_d, geometry.nt, old_dt)

    solver = AcousticWaveSolver(model,
                                geometry,
                                kernel='OT2',
                                nbl=nbl,
                                space_order=space_order,
                                dtype=dtype)

    grad = Function(name="grad", grid=model.grid)

    residual = Receiver(name='rec',
                        grid=model.grid,
                        time_range=geometry.time_axis,
                        coordinates=geometry.rec_positions)

    u0 = TimeFunction(name='u',
                      grid=model.grid,
                      time_order=2,
                      space_order=solver.space_order,
                      save=geometry.nt)

    error("Forward prop")
    smooth_d, _, _ = solver.forward(save=True, u=u0)
    error("Misfit")
    residual.data[:] = smooth_d.data[:] - true_d[:]

    objective = .5 * np.linalg.norm(residual.data.ravel())**2
    error("Gradient")
    solver.gradient(rec=residual, u=u0, grad=grad)

    grad = clip_boundary_and_numpy(grad.data, model.nbl)

    return objective, -grad
Exemplo n.º 27
0
def demo_model(preset, **kwargs):
    """
    Utility function to create preset :class:`Model` objects for
    demonstration and testing purposes. The particular presets are ::

    * 'layer2D': Simple two-layer model with velocities 1.5 km/s
                 and 2.5 km/s in the top and bottom layer respectively.
    * 'marmousi2D': Loads the 2D Marmousi data set from the given
                    filepath. Requires the ``opesci/data`` repository
                    to be available on your machine.
    """
    if preset.lower() in ['constant-isotropic']:
        # A constant single-layer model in a 2D or 3D domain
        # with velocity 1.5km/s.
        shape = kwargs.pop('shape', (101, 101))
        spacing = kwargs.pop('spacing', tuple([10. for _ in shape]))
        origin = kwargs.pop('origin', tuple([0. for _ in shape]))
        nbpml = kwargs.pop('nbpml', 10)
        vp = kwargs.pop('vp', 1.5)

        return Model(vp=vp,
                     origin=origin,
                     shape=shape,
                     spacing=spacing,
                     nbpml=nbpml,
                     **kwargs)

    elif preset.lower() in ['constant-tti']:
        # A constant single-layer model in a 2D or 3D domain
        # with velocity 1.5km/s.
        shape = kwargs.pop('shape', (101, 101))
        spacing = kwargs.pop('spacing', tuple([10. for _ in shape]))
        origin = kwargs.pop('origin', tuple([0. for _ in shape]))
        nbpml = kwargs.pop('nbpml', 10)
        v = np.empty(shape, dtype=np.float32)
        v[:] = 1.5
        epsilon = .3 * np.ones(shape)
        delta = .2 * np.ones(shape)
        theta = .7 * np.ones(shape)
        phi = None
        if len(shape) > 2:
            phi = .35 * np.ones(shape)

        return Model(vp=v,
                     origin=origin,
                     shape=shape,
                     spacing=spacing,
                     nbpml=nbpml,
                     epsilon=epsilon,
                     delta=delta,
                     theta=theta,
                     phi=phi,
                     **kwargs)

    elif preset.lower() in [
            'layers-isotropic', 'twolayer-isotropic', '2layer-isotropic'
    ]:
        # A two-layer model in a 2D or 3D domain with two different
        # velocities split across the height dimension:
        # By default, the top part of the domain has 1.5 km/s,
        # and the bottom part of the domain has 2.5 km/s.
        shape = kwargs.pop('shape', (101, 101))
        spacing = kwargs.pop('spacing', tuple([10. for _ in shape]))
        origin = kwargs.pop('origin', tuple([0. for _ in shape]))
        nbpml = kwargs.pop('nbpml', 10)
        ratio = kwargs.pop('ratio', 2)
        vp_top = kwargs.pop('vp_top', 1.5)
        vp_bottom = kwargs.pop('vp_bottom', 2.5)

        # Define a velocity profile in km/s
        v = np.empty(shape, dtype=np.float32)
        v[:] = vp_top  # Top velocity (background)
        v[..., int(shape[-1] / ratio):] = vp_bottom  # Bottom velocity

        return Model(vp=v,
                     origin=origin,
                     shape=shape,
                     spacing=spacing,
                     nbpml=nbpml,
                     **kwargs)

    elif preset.lower() in ['layers-tti', 'twolayer-tti', '2layer-tti']:
        # A two-layer model in a 2D or 3D domain with two different
        # velocities split across the height dimension:
        # By default, the top part of the domain has 1.5 km/s,
        # and the bottom part of the domain has 2.5 km/s.\
        shape = kwargs.pop('shape', (101, 101))
        spacing = kwargs.pop('spacing', tuple([10. for _ in shape]))
        origin = kwargs.pop('origin', tuple([0. for _ in shape]))
        nbpml = kwargs.pop('nbpml', 10)
        ratio = kwargs.pop('ratio', 2)
        vp_top = kwargs.pop('vp_top', 1.5)
        vp_bottom = kwargs.pop('vp_bottom', 2.5)

        # Define a velocity profile in km/s
        v = np.empty(shape, dtype=np.float32)
        v[:] = vp_top  # Top velocity (background)
        v[..., int(shape[-1] / ratio):] = vp_bottom  # Bottom velocity

        epsilon = .3 * (v - 1.5)
        delta = .2 * (v - 1.5)
        theta = .5 * (v - 1.5)
        phi = None
        if len(shape) > 2:
            phi = .1 * (v - 1.5)

        return Model(vp=v,
                     origin=origin,
                     shape=shape,
                     spacing=spacing,
                     nbpml=nbpml,
                     epsilon=epsilon,
                     delta=delta,
                     theta=theta,
                     phi=phi,
                     **kwargs)

    elif preset.lower() in ['circle-isotropic']:
        # A simple circle in a 2D domain with a background velocity.
        # By default, the circle velocity is 2.5 km/s,
        # and the background veloity is 3.0 km/s.
        shape = kwargs.pop('shape', (101, 101))
        spacing = kwargs.pop('spacing', tuple([10. for _ in shape]))
        origin = kwargs.pop('origin', tuple([0. for _ in shape]))
        nbpml = kwargs.pop('nbpml', 10)
        vp = kwargs.pop('vp', 3.0)
        vp_background = kwargs.pop('vp_background', 2.5)
        r = kwargs.pop('r', 15)

        # Only a 2D preset is available currently
        assert (len(shape) == 2)

        v = np.empty(shape, dtype=np.float32)
        v[:] = vp_background

        a, b = shape[0] / 2, shape[1] / 2
        y, x = np.ogrid[-a:shape[0] - a, -b:shape[1] - b]
        v[x * x + y * y <= r * r] = vp

        return Model(vp=v,
                     origin=origin,
                     shape=shape,
                     spacing=spacing,
                     nbpml=nbpml)

    elif preset.lower() in ['marmousi-isotropic', 'marmousi2d-isotropic']:
        shape = (1601, 401)
        spacing = (7.5, 7.5)
        origin = (0., 0.)

        # Read 2D Marmousi model from opesc/data repo
        data_path = kwargs.get('data_path', None)
        if data_path is None:
            error("Path to opesci/data not found! Please specify with "
                  "'data_path=<path/to/opesci/data>'")
            raise ValueError("Path to model data unspecified")
        path = os.path.join(data_path, 'Simple2D/vp_marmousi_bi')
        v = np.fromfile(path, dtype='float32', sep="")
        v = v.reshape(shape)

        # Cut the model to make it slightly cheaper
        v = v[301:-300, :]

        return Model(vp=v,
                     origin=origin,
                     shape=v.shape,
                     spacing=spacing,
                     nbpml=20)

    elif preset.lower() in ['marmousi-tti2d', 'marmousi2d-tti']:

        shape_full = (201, 201, 70)
        shape = (201, 70)
        spacing = (10., 10.)
        origin = (0., 0.)
        nbpml = kwargs.pop('nbpml', 20)

        # Read 2D Marmousi model from opesc/data repo
        data_path = kwargs.pop('data_path', None)
        if data_path is None:
            error("Path to opesci/data not found! Please specify with "
                  "'data_path=<path/to/opesci/data>'")
            raise ValueError("Path to model data unspecified")
        path = os.path.join(data_path, 'marmousi3D/vp_marmousi_bi')

        # velocity
        vp = 1e-3 * np.fromfile(os.path.join(data_path,
                                             'marmousi3D/MarmousiVP.raw'),
                                dtype='float32',
                                sep="")
        vp = vp.reshape(shape_full)
        vp = vp[101, :, :]
        # Epsilon, in % in file, resale between 0 and 1
        epsilon = np.fromfile(os.path.join(data_path,
                                           'marmousi3D/MarmousiEps.raw'),
                              dtype='float32',
                              sep="") * 1e-2
        epsilon = epsilon.reshape(shape_full)
        epsilon = epsilon[101, :, :]
        # Delta, in % in file, resale between 0 and 1
        delta = np.fromfile(os.path.join(data_path,
                                         'marmousi3D/MarmousiDelta.raw'),
                            dtype='float32',
                            sep="") * 1e-2
        delta = delta.reshape(shape_full)
        delta = delta[101, :, :]
        # Theta, in degrees in file, resale in radian
        theta = np.fromfile(os.path.join(data_path,
                                         'marmousi3D/MarmousiTilt.raw'),
                            dtype='float32',
                            sep="")
        theta = np.float32(np.pi / 180 * theta.reshape(shape_full))
        theta = theta[101, :, :]

        return Model(vp=vp,
                     origin=origin,
                     shape=shape,
                     spacing=spacing,
                     nbpml=nbpml,
                     epsilon=epsilon,
                     delta=delta,
                     theta=theta,
                     **kwargs)

    elif preset.lower() in ['marmousi-tti3d', 'marmousi3d-tti']:

        shape = (201, 201, 70)
        spacing = (10., 10., 10.)
        origin = (0., 0., 0.)
        nbpml = kwargs.pop('nbpml', 20)

        # Read 2D Marmousi model from opesc/data repo
        data_path = kwargs.pop('data_path', None)
        if data_path is None:
            error("Path to opesci/data not found! Please specify with "
                  "'data_path=<path/to/opesci/data>'")
            raise ValueError("Path to model data unspecified")
        path = os.path.join(data_path, 'marmousi3D/vp_marmousi_bi')

        # Velcoity
        vp = 1e-3 * np.fromfile(os.path.join(data_path,
                                             'marmousi3D/MarmousiVP.raw'),
                                dtype='float32',
                                sep="")
        vp = vp.reshape(shape)
        # Epsilon, in % in file, resale between 0 and 1
        epsilon = np.fromfile(os.path.join(data_path,
                                           'marmousi3D/MarmousiEps.raw'),
                              dtype='float32',
                              sep="") * 1e-2
        epsilon = epsilon.reshape(shape)
        # Delta, in % in file, resale between 0 and 1
        delta = np.fromfile(os.path.join(data_path,
                                         'marmousi3D/MarmousiDelta.raw'),
                            dtype='float32',
                            sep="") * 1e-2
        delta = delta.reshape(shape)
        # Theta, in degrees in file, resale in radian
        theta = np.fromfile(os.path.join(data_path,
                                         'marmousi3D/MarmousiTilt.raw'),
                            dtype='float32',
                            sep="")
        theta = np.float32(np.pi / 180 * theta.reshape(shape))
        # Phi, in degrees in file, resale in radian
        phi = np.fromfile(os.path.join(data_path, 'marmousi3D/Azimuth.raw'),
                          dtype='float32',
                          sep="")
        phi = np.float32(np.pi / 180 * phi.reshape(shape))

        return Model(vp=vp,
                     origin=origin,
                     shape=shape,
                     spacing=spacing,
                     nbpml=nbpml,
                     epsilon=epsilon,
                     delta=delta,
                     theta=theta,
                     phi=phi,
                     **kwargs)

    else:
        error('Unknown model preset name %s' % preset)
Exemplo n.º 28
0
    def arguments(self, *args, **kwargs):
        """
        Return the arguments necessary to apply the Operator.
        """
        if len(args) == 0:
            args = self.parameters

        # Will perform auto-tuning if the user requested it and loop blocking was used
        maybe_autotune = kwargs.get('autotune', False)

        # Initialise argument map and a map of dimension names to values
        arguments = OrderedDict([(arg.name, arg) for arg in self.parameters])
        dim_sizes = dict([(arg.name, arg.size) for arg in self.parameters
                          if isinstance(arg, Dimension)])

        o_vals = {}
        for name, arg in kwargs.items():
            # Override explicitly provided dim sizes from **kwargs
            if name in dim_sizes:
                dim_sizes[name] = arg

            # Override explicitly provided SymbolicData
            if name in arguments and isinstance(arguments[name], SymbolicData):
                # Override the original symbol
                o_vals[name] = arg

                original = arguments[name]
                if original.is_CompositeData:
                    for orig, child in zip(original.children, arg.children):
                        o_vals[orig.name] = child

        # Replace the overridden values with the provided ones
        for argname in o_vals.keys():
            arguments[argname] = o_vals[argname]

        # Traverse positional args and infer loop sizes for open dimensions
        f_args = [(name, f) for name, f in arguments.items()
                  if isinstance(f, SymbolicData)]
        for fname, f in f_args:
            arguments[fname] = self._arg_data(f)
            shape = self._arg_shape(f)

            # Ensure data dimensions match symbol dimensions
            for i, dim in enumerate(f.indices):
                # We don't need to check sizes for buffered dimensions
                # against data shapes, all we need is the size of the parent.
                if dim.is_Buffered:
                    continue

                # Check data sizes for dimensions with a fixed size
                if dim.size is not None:
                    if not shape[i] <= dim.size:
                        error(
                            'Size of data argument for %s is greater than the size '
                            'of dimension %s: %d' %
                            (fname, dim.name, dim.size))
                        raise InvalidArgument('Wrong data shape encountered')
                    else:
                        continue

                if dim_sizes[dim.name] is None:
                    # We haven't determined the size of this dimension yet,
                    # try to infer it from the data shape.
                    dim_sizes[dim.name] = shape[i]
                else:
                    # We know the dimension size, check if data shape agrees
                    if not dim_sizes[dim.name] <= shape[i]:
                        error('Size of dimension %s was determined to be %d, '
                              'but data for symbol %s has shape %d.' %
                              (dim.name, dim_sizes[dim.name], fname, shape[i]))
                        raise InvalidArgument('Wrong data shape encountered')

        # Make sure we have defined all buffered dimensions and their parents,
        # even if they are not explicitly given or used.
        d_args = [d for d in arguments.values() if isinstance(d, Dimension)]
        for d in d_args:
            if d.is_Buffered:
                if dim_sizes[d.parent.name] is None:
                    dim_sizes[d.parent.name] = dim_sizes[d.name]
                if dim_sizes[d.name] is None:
                    dim_sizes[d.name] = dim_sizes[d.parent.name]

        # Add user-provided block sizes, if any
        dle_arguments = OrderedDict()
        for i in self._dle_state.arguments:
            dim_size = dim_sizes.get(i.original_dim.name, i.original_dim.size)
            if dim_size is None:
                error('Unable to derive size of dimension %s from defaults. '
                      'Please provide an explicit value.' %
                      i.original_dim.name)
                raise InvalidArgument('Unknown dimension size')
            if i.value:
                try:
                    dle_arguments[i.argument.name] = i.value(dim_size)
                except TypeError:
                    dle_arguments[i.argument.name] = i.value
                    # User-provided block size available, do not autotune
                    maybe_autotune = False
            else:
                dle_arguments[i.argument.name] = dim_size
        dim_sizes.update(dle_arguments)

        # Insert loop size arguments from dimension values
        d_args = [d for d in arguments.values() if isinstance(d, Dimension)]
        for d in d_args:
            arguments[d.name] = dim_sizes[d.name]

        # Might have been asked to auto-tune the block size
        if maybe_autotune:
            arguments = self._autotune(arguments)

        # Add profiler structs
        arguments.update(self._extra_arguments())

        # Sanity check argument derivation
        for name, arg in arguments.items():
            if isinstance(arg, SymbolicData) or isinstance(arg, Dimension):
                raise ValueError('Runtime argument %s not defined' % arg)
        return arguments, dim_sizes
Exemplo n.º 29
0
 def _arg_data(self, argument):
     # Ensure we're dealing or deriving numpy arrays
     data = argument.data
     if not isinstance(data, np.ndarray):
         error('No array data found for argument %s' % argument.name)
     return data