question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Volume averaging interpolation

See original GitHub issue

As a follow up of questions I asked on Slack (Simpeg#discretize and Swung#python). EM fields are arguably best interpolated by a cubic spline (#175). Up- or downscaling model parameters is, however, often best done with a method which keeps the total value constant (X*Y*Z*value = constant), something which is not given with linear nor cubic spline interpolation. Although there are more sophisticated solutions (based on effective medium theory) the volume averaging technique is a simple method to ensure the total value of the property remains unchanged.

I implemented the technique in emg3d, following Plessix et al., 2007, Geophysics. I post it here if you ever want to implement it in discretize. This is a numba-version, but it could be re-written for a Cython (unless discretize makes numba a dependency):

import numba as nb
import numpy as np


@nb.njit(nogil=True, fastmath=True, cache=True)
def volume_average(edges_x, edges_y, edges_z, values,
                   new_edges_x, new_edges_y, new_edges_z, new_values):
    """Interpolation using the volume averaging technique.

    The result is added to new_values.


    Parameters
    ----------
    edges_[x, y, z] : ndarray
        The edges in x-, y-, and z-directions for the original grid.

    values : ndarray
        Values corresponding to ``grid``.

    new_edges_[x, y, z] : ndarray
        The edges in x-, y-, and z-directions for the new grid.

    new_values : ndarray
        Array where values corresponding to ``new_grid`` will be added.

    """

    # Get cell indices.
    # First and last edges ignored => first and last cells extend to +/- infty.
    ix_l = np.searchsorted(edges_x[1:-1], new_edges_x, 'left')
    ix_r = np.searchsorted(edges_x[1:-1], new_edges_x, 'right')
    iy_l = np.searchsorted(edges_y[1:-1], new_edges_y, 'left')
    iy_r = np.searchsorted(edges_y[1:-1], new_edges_y, 'right')
    iz_l = np.searchsorted(edges_z[1:-1], new_edges_z, 'left')
    iz_r = np.searchsorted(edges_z[1:-1], new_edges_z, 'right')

    # Get number of cells.
    ncx = len(new_edges_x)-1
    ncy = len(new_edges_y)-1
    ncz = len(new_edges_z)-1

    # Working arrays for edges.
    x_edges = np.empty(len(edges_x)+2)
    y_edges = np.empty(len(edges_y)+2)
    z_edges = np.empty(len(edges_z)+2)

    # Loop over new_grid cells.
    for iz in range(ncz):
        hz = np.diff(new_edges_z[iz:iz+2])[0]  # To calc. current cell volume.

        for iy in range(ncy):
            hyz = hz*np.diff(new_edges_y[iy:iy+2])[0]  # " "

            for ix in range(ncx):
                hxyz = hyz*np.diff(new_edges_x[ix:ix+2])[0]  # " "

                # Get start edge and number of cells of original grid involved.
                s_cx = ix_r[ix]
                n_cx = ix_l[ix+1] - s_cx

                s_cy = iy_r[iy]
                n_cy = iy_l[iy+1] - s_cy

                s_cz = iz_r[iz]
                n_cz = iz_l[iz+1] - s_cz

                # Get the involved original grid edges for this cell.
                x_edges[0] = new_edges_x[ix]
                for i in range(n_cx):
                    x_edges[i+1] = edges_x[s_cx+i+1]
                x_edges[n_cx+1] = new_edges_x[ix+1]

                y_edges[0] = new_edges_y[iy]
                for j in range(n_cy):
                    y_edges[j+1] = edges_y[s_cy+j+1]
                y_edges[n_cy+1] = new_edges_y[iy+1]

                z_edges[0] = new_edges_z[iz]
                for k in range(n_cz):
                    z_edges[k+1] = edges_z[s_cz+k+1]
                z_edges[n_cz+1] = new_edges_z[iz+1]

                # Loop over each (partial) cell of the original grid which
                # contributes to the current cell of the new grid and add its
                # (partial) value.
                for k in range(n_cz+1):
                    dz = np.diff(z_edges[k:k+2])[0]
                    k += s_cz

                    for j in range(n_cy+1):
                        dyz = dz*np.diff(y_edges[j:j+2])[0]
                        j += s_cy

                        for i in range(n_cx+1):
                            dxyz = dyz*np.diff(x_edges[i:i+2])[0]
                            i += s_cx

                            # Add this cell's contribution.
                            new_values[ix, iy, iz] += values[i, j, k]*dxyz

                # Normalize by new_grid-cell volume.
                new_values[ix, iy, iz] /= hxyz

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:14 (14 by maintainers)

github_iconTop GitHub Comments

1reaction
prisaecommented, Jul 25, 2019

Unless you change the algorithm per se I’d be surprised if a cython implementation is significantly faster than numba.

0reactions
prisaecommented, Nov 18, 2020

Volume averaging was implemented in #212

Read more comments on GitHub >

github_iconTop Results From Across the Web

Partial volume averaging (CT artifact)
Partial volume artifact occurs when tissues of widely different absorption are encompassed on the same CT voxel producing a beam attenuation ...
Read more >
Volume Reconstruction by Inverse Interpolation - NCBI - NIH
We introduce in this work a novel algorithm for volume reconstruction from data acquired on an irregular grid, e.g., from multiple co-registered images....
Read more >
What Is Interpolation, and How Do Investors and Analysts ...
Interpolation is a statistical method by which related known values are used to estimate an unknown price or potential yield of a security....
Read more >
Smart averaging interpolation algorithm comparative test
Smart averaging interpolation is done in a “live” window. The position, form, and size of the window are determined by some mathematical ...
Read more >
Interpolation and averaging of diffusion MRI multi ...
IEEE TRANSACTIONS ON MEDICAL IMAGING, VOL. XX, NO. XX, XXXX 2020. 2. Interpolation and averaging of diffusion MRI multi-compartment models.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found