class_docstr: Apply elastic distortion on sparse coordinate space. First projects the position onto a 
  voxel grid and then apply the distortion to the voxel grid.
  
  Parameters
  ----------
  granularity: List[float]
      Granularity of the noise in meters
  magnitude:List[float]
      Noise multiplier in meters
  Returns
  -------
  data: Data
      Returns the same data object with distorted grid
class_docstr_tok: ["Apply","elastic","distortion","on","sparse","coordinate","space",".","First","projects","the","position","onto","a","voxel","grid","and","then","apply","the","distortion","to","the","voxel","grid",".","Parameters","--","--","--","--","--","granularity",":","List","[","float","]","Granularity","of","the","noise","in","meters","magnitude",":","List","[","float","]","Noise","multiplier","in","meters","Returns","--","--","--","-","data",":","Data","Returns","the","same","data","object","with","distorted","grid"]
code: def elastic_distortion(coords, granularity, magnitude):
      coords = coords.numpy()
      blurx = np.ones((3, 1, 1, 1)).astype("float32") / 3
      blury = np.ones((1, 3, 1, 1)).astype("float32") / 3
      blurz = np.ones((1, 1, 3, 1)).astype("float32") / 3
      coords_min = coords.min(0)
  
      # Create Gaussian noise tensor of the size given by granularity.
      noise_dim = ((coords - coords_min).max(0) // granularity).astype(
          int
      ) + 3
      noise = np.random.randn(*noise_dim, 3).astype(np.float32)
  
      # Smoothing.
      for _ in range(2):
          noise = scipy.ndimage.filters.convolve(
              noise, blurx, mode="constant", cval=0
          )
          noise = scipy.ndimage.filters.convolve(
              noise, blury, mode="constant", cval=0
          )
          noise = scipy.ndimage.filters.convolve(
              noise, blurz, mode="constant", cval=0
          )
  
      # Trilinear interpolate noise filters for each spatial dimensions.
      ax = [
          np.linspace(d_min, d_max, d)
          for d_min, d_max, d in zip(
              coords_min - granularity,
              coords_min + granularity * (noise_dim - 2),
              noise_dim,
          )
      ]
      interp = scipy.interpolate.RegularGridInterpolator(
          ax, noise, bounds_error=0, fill_value=0
      )
      coords = coords + interp(coords) * magnitude
      return torch.tensor(coords).float()
  
imports: from typing import *
  import numpy
  import numpy
  import random
  import scipy
  import re
  import torch
  import logging
  import torch.nn.functional
  from torch_scatter import scatter_mean, scatter_add
  from torch_geometric.nn.pool.consecutive import consecutive_cluster
  from torch_geometric.nn import voxel_grid
  from torch_geometric.data import Data
  from torch_cluster import grid_cluster
label_desc: Use image node_id 2 for calling the ElasticDistortion obj's underlying member method code with example usage: obj.elastic_distortion(coords, granularity, magnitude) and returns: torch