{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The idea here is to try to index some unknown unit cell by using lattice translational symmetry. \n",
    "\n",
    "Pick one of the g-vectors at random and then create a new dataset which is shifted by this g-vector. (g-vector is a scattering vector from the sample, one of the points in the reciprocal lattice of the crystal).\n",
    "\n",
    "Then we look for coincident points between the original and shifted data. \n",
    "\n",
    "Points that correspond to overlaps after lattice translation might come from the same lattice as the chosen point, or you might be unlucky and get an overlap.\n",
    "\n",
    "This is similar to the idea in grainspotter which used rotational symmetry. The interest here is that using a g-vector from the dataset means you are looking for other spots which come from the same lattice as the spot you picked.\n",
    "\n",
    "The big \"problem\" is the $N^2$ search of overlapping the original with the shifted data. This is reduced by using a KDTree structure from scipy. You could also mess about with grids (e.g. put the g-vectors onto a fine 3D grid first, now intersect grid points to reduce the problem sizes). In principle you need to repeat for all possible shift vectors in the dataset, but this is probably more like the number of lattices as you can remove peaks when you find lattices.\n",
    "\n",
    "We can think about using +/- the vector as there is always a Friedel pair in diffraction pattern. Probably better to choose shift vectors where we observed both +/- g from a real experiment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np, pylab as pl, scipy.spatial\n",
    "from ImageD11 import indexing\n",
    "\n",
    "%matplotlib notebook"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def readgv(f):\n",
    "    i = indexing.indexer()\n",
    "    i.readgvfile(f)\n",
    "    return i.gv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# demo dataset\n",
    "g3 = readgv( \"3.ubi.gve\" )\n",
    "# Note: the omega values are missing in the simulation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pl.figure()\n",
    "pl.plot(g3[:,0],g3[:,1],\".\")\n",
    "\n",
    "# select a 'random' peak\n",
    "np.random.seed(10037) # reproducible\n",
    "j = np.round( g3.shape[0] * np.random.random() ).astype(int)\n",
    "g3s = g3 - g3[j]\n",
    "pl.plot(g3s[:,0],g3s[:,1],\".\",alpha=0.5)\n",
    "g3s = g3 + g3[j]\n",
    "pl.plot(g3s[:,0],g3s[:,1],\".\",alpha=0.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "kd0 = scipy.spatial.cKDTree( g3 )\n",
    "kd1 = scipy.spatial.cKDTree( g3 + g3[j] )\n",
    "kd2 = scipy.spatial.cKDTree( g3 - g3[j] )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%time\n",
    "#  Which number to pick for max_distance is a problem\n",
    "#     ideally maje some error bar for scattering vector\n",
    "#  ... all the time is in here ?!\n",
    "sd1 = kd0.sparse_distance_matrix( kd1, max_distance=0.01 ).tocoo()\n",
    "sd2 = kd0.sparse_distance_matrix( kd2, max_distance=0.01 ).tocoo()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# distances between pairs of peaks after shifting\n",
    "peaks = np.concatenate( (sd1.row, sd1.col, sd2.row, sd2.col ))\n",
    "distances = np.concatenate(( sd1.data, sd2.data) )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pl.figure()\n",
    "_=pl.hist(distances,bins=128)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pl.figure()\n",
    "pl.plot(g3[:,0],g3[:,1],\".\", alpha=0.2)\n",
    "pl.plot(g3[peaks,0],g3[peaks,1],\".\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
