formelsammlung/scripts/crystal_lattices-Copy1.ipynb

190 lines
51 KiB
Plaintext
Raw Normal View History

2024-07-10 07:43:50 +02:00
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "eaed683c-c6f1-45e4-aaee-ae4e57209f5f",
"metadata": {},
"outputs": [],
"source": [
"import scipy as scp\n",
"from scipy.spatial import Voronoi, voronoi_plot_2d\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "efd84ecd-9fb3-4d2f-9f7a-47cd1ff09eea",
"metadata": {},
"outputs": [],
"source": [
"class Lattice:\n",
" def __init__(self, *vecs):\n",
" # if the vecs were put in an iterable\n",
" if len(vecs) == 1:\n",
" vecs = vecs[0]\n",
" if len(vecs) == 3:\n",
" pass\n",
" elif len(vecs) == 2:\n",
" pass\n",
" else: raise ValueError(\"Vecs must contain either 2 or 3 vectors\")\n",
" self.dim = len(vecs)\n",
" self.vecs = list(vecs)\n",
" for i, v in enumerate(self.vecs):\n",
" if type(v) != np.ndarray:\n",
" self.vecs[i] = np.array(v)\n",
" if self.vecs[i].shape != (self.dim,):\n",
" raise ValueError(f\"Got {self.dim} vectors, therefore all vectors must be {self.dim} dimensional but vector {i+1} has shape {self.vecs[i].shape}\")\n",
" self.vecs = np.array(self.vecs)\n",
" self.vec_lengths = np.array([np.linalg.norm(v) for v in self.vecs])\n",
" self.center = np.zeros(self.dim)\n",
"\n",
" def get_point(self, *ns):\n",
" if len(ns) != len(self.vecs): raise ValueError(f\"Requires one index for each lattice vector {len(self.vecs)}, but got only {ns}\")\n",
" point = self.center.copy()\n",
" for i, n in enumerate(ns):\n",
" point += n * self.vecs[i]\n",
" return point\n",
"\n",
" \n",
" def get_points_around_center(self, n):\n",
" import itertools\n",
" ns = [i for i in range(-i, i+1)]\n",
" for n in itertools.product(*[])\n",
" for i in range(self.dim):\n",
" \n",
" \n",
" for i in range(-n, n+1):\n",
" for j "
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "2855d08e-70d8-4ef7-ba19-2c06316caf15",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"<scipy.spatial._qhull.Voronoi object at 0x7e3efffb4a70>\n",
"1.7320508075688774 [0.70710678 1.58113883 0.70710678 0.70710678 1.58113883 0.70710678]\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAi8AAAGdCAYAAADaPpOnAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAA/fUlEQVR4nO3deVyU9d7/8fcAgqgwpsgmCNqvo6kthuWWuYZ7iyfTW1OsTo+oPGnmnXq6K7W7bDl17LSZ57awbPHk0klckk6ilrRoam6ZFSkhhCug6YDw/f0xMacRRFBmhgtez8djHjLf+V4zn68X18yb6/pe19iMMUYAAAAW4efrAgAAAKqD8AIAACyF8AIAACyF8AIAACyF8AIAACyF8AIAACyF8AIAACyF8AIAACwlwNcF1LTS0lIdOHBAISEhstlsvi4HAABUgTFGhYWFio6Olp9f5ftW6lx4OXDggGJjY31dBgAAOA9ZWVmKiYmptE+dCy8hISGSnIMPDQ31cTUAAKAqCgoKFBsb6/ocr0ydCy9lh4pCQ0MJLwAAWExVpnwwYRcAAFgK4QUAAFgK4QUAAFgK4QUAAFgK4QUAAFgK4QUAAFgK4QUAAFgK4QUAAFhKnbtIHQAA8IySEmnDBiknR4qKknr2lPz9vV+HR/e8zJ49W1dffbVCQkIUHh6um266SXv27DnncuvWrVNCQoIaNmyoNm3aaO7cuZ4sEwAAnMPSpVJ8vNSnjzR6tPPf+Hhnu7d5NLysW7dO9913nz7//HOlpaXp9OnTSkxM1IkTJ866TGZmpgYPHqyePXtqy5Yt+stf/qL7779fS5Ys8WSpAADgLJYulW65Rfr5Z/f27Gxnu7cDjM0YY7z1YgcPHlR4eLjWrVun6667rsI+U6dO1Ycffqjdu3e72pKTk7Vt2zZlZGSc8zUKCgpkt9uVn5/PdxsBAHCBSkqce1jODC5lbDYpJkbKzLywQ0jV+fz26oTd/Px8SVKzZs3O2icjI0OJiYlubQMGDNCmTZtUXFxcrr/D4VBBQYHbDQAA1IwNG84eXCTJGCkry9nPW7wWXowxmjx5sq699lp17NjxrP1yc3MVERHh1hYREaHTp0/r0KFD5frPnj1bdrvddYuNja3x2gEAqK9ycmq2X03wWniZMGGCvvnmG7377rvn7Hvm12GXHdmq6Guyp0+frvz8fNctKyurZgoGAACKiqrZfjXBK6dK//nPf9aHH36o9evXKyYmptK+kZGRys3NdWvLy8tTQECAmjdvXq5/UFCQgoKCarReAADg1LOnc05LdrbzENGZyua89OzpvZo8uufFGKMJEyZo6dKl+uSTT9S6detzLtOtWzelpaW5ta1Zs0adO3dWgwYNPFUqAACogL+/9MILzp/PPABSdn/OHO9e78Wj4eW+++7TwoUL9c477ygkJES5ubnKzc3VyZMnXX2mT5+ucePGue4nJydr3759mjx5snbv3q3XX39d8+fP15QpUzxZKgAAOIvhw6XFi6WWLd3bY2Kc7cOHe7cej54qXdEcFUl64403NH78eEnS+PHj9dNPPyk9Pd31+Lp16/TAAw9o586dio6O1tSpU5WcnFyl1+RUaQAAPMOTV9itzue3V6/z4g2EFwAArKfWXucFAADgQhFeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApRBeAACApXg0vKxfv17Dhg1TdHS0bDabPvjgg0r7p6eny2azlbt9++23niwTAABYSIAnn/zEiRO64oordPvtt+uPf/xjlZfbs2ePQkNDXfdbtGjhifIAAIAFeTS8DBo0SIMGDar2cuHh4WratGnNFwQAACyvVs556dSpk6KiotSvXz+tXbu20r4Oh0MFBQVuNwAAUHfVqvASFRWlefPmacmSJVq6dKnatm2rfv36af369WddZvbs2bLb7a5bbGysFysGAADeZjPGGK+8kM2mZcuW6aabbqrWcsOGDZPNZtOHH35Y4eMOh0MOh8N1v6CgQLGxscrPz3ebNwMAAGqvgoIC2e32Kn1+16o9LxXp2rWr9u7de9bHg4KCFBoa6nYDAAB1V60PL1u2bFFUVJSvywAAALWER882On78uL7//nvX/czMTG3dulXNmjVTq1atNH36dGVnZ+vNN9+UJM2ZM0fx8fHq0KGDioqKtHDhQi1ZskRLlizxZJkAAMBCPBpeNm3apD59+rjuT548WZKUlJSklJQU5eTkaP/+/a7Hi4qKNGXKFGVnZys4OFgdOnTQihUrNHjwYE+WCQAALMRrE3a9pToTfgAAQO1QpybsAgAA/B7hBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWArhBQAAWEqArwsAgKooKZE2bJBycqSoKKlnT8nf39dVAfVLbdkOPbrnZf369Ro2bJiio6Nls9n0wQcfnHOZdevWKSEhQQ0bNlSbNm00d+5cT5YIwAKWLpXi46U+faTRo53/xsc72wF4R23aDj0aXk6cOKErrrhCL730UpX6Z2ZmavDgwerZs6e2bNmiv/zlL7r//vu1ZMkST5YJoBZbulS65Rbp55/d27Ozne0EGMDzatt2aDPGGK+8kM2mZcuW6aabbjprn6lTp+rDDz/U7t27XW3Jycnatm2bMjIyqvQ6BQUFstvtys/PV2ho6IWWDcCHSkqcf9md+YZZxmaTYmKkzEwOIQGe4q3tsDqf37VqzktGRoYSExPd2gYMGKD58+eruLhYDRo0KLeMw+GQw+Fw3S8oKPB4nQC8Y8OGs79hSpIxUlaWs1/v3l4rC6gT5s2bp4kTJ6pFixZq1aqV4uLi1LJlS8XExLj9u2dPpH7++exxwRfbYa0KL7m5uYqIiHBri4iI0OnTp3Xo0CFFRUWVW2b27NmaOXOmt0oE4EU5OTXbD8B/NG/eXKdOnVJWVpaysrKUkZEhf39/lZSUqLS01NXPZvOT1ExS499uX0hqUu75vLkd1rpTpW02m9v9sqNaZ7aXmT59uvLz8123rKwsj9cIwDvK/73ys6Tuko6cox+Acxk6dKjb4ZnS0lIVFxe7BRdJMqZU0iFJ+yT9IKni2Sbe3A5rVXiJjIxUbm6uW1teXp4CAgLUvHnzCpcJCgpSaGio2w1A3dCzp/NY+n/+dpkqKUPSDEnO9thYZz8A1RMUFKTbbrtNAQFVOQhjk3SRpJ2SQtwf8cF2WKvCS7du3ZSWlubWtmbNGnXu3LnC+S4A6jZ/f+mFF8ru5Ula/NvPr0tyzm+bM4fJusD5Gj9+vE6fPl1pHz8/PzVs2ERSumy2i90eK/vDwtvboUfDy/Hjx7V161Zt3bpVkvNU6K1bt2r//v2SnId8xo0b5+qfnJysffv2afLkydq9e7def/11zZ8/X1OmTPFkmQBqseHDpcWLpSZNnpVU9ib7q+z2F7V4sfNxANVXWlqq/Px8hYSEnLWPn5+fAgMD9cknH2nJksvVsqX74zEx8sl26NFTpdPT09WnT59y7UlJSUpJSdH48eP1008/KT093fXYunXr9MADD2jnzp2Kjo7W1KlTlZycXOXX5FRpoO7Jy8tTq1ZxcjhOudpCQkL1889ZbOdANe3du1cLFizQm2++qaysLIWFhenw4cM6Mw7YbDb5+/tr5cqVuv766yV59gq71fn89tp1XryF8ALUPf/93/+tv/3tbyopKXG1+fn5adasWXr44Yd9WBl
"text/plain": [
"<Figure size 640x480 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"sphere_point = lambda rad: np.array([np.cos(rad), np.sin(rad)])\n",
"\n",
"square_lattice = Lattice([1, 0], [0, 1])\n",
"tilted_lattice = Lattice([1, 1], [0, 1])\n",
"honeycomb_lattice = Lattice(sphere_point(0), sphere_point(np.pi * 2/3))\n",
"\n",
"def get_elementary_cell(lattice: Lattice):\n",
" points = []\n",
" for n1 in range(-1, 2):\n",
" for n2 in range(-1, 2):\n",
" p = lattice.get_point(n1, n2)\n",
" p_len = np.linalg.norm(p)\n",
" # if (p_len <= lattice.vec_lengths).any():\n",
" points.append(p)\n",
" return points\n",
"\n",
"def get_n_points_around_center(n)\n",
"\n",
"points = get_elementary_cell(tilted_lattice)\n",
"vor = Voronoi(points)\n",
"\n",
"print(vor)\n",
"fig = voronoi_plot_2d(vor)\n",
"\n",
"def get_orthogonal_2D(vec):\n",
" return np.array((vec[1], -vec[0]))\n",
"def plot_voronoi(lattice, v: Voronoi, subplot_kw={}):\n",
" fig, ax = plt.subplots(**subplot_kw) \n",
" lattice_points = v.points\n",
" lattice_vec_norm = np.sqrt(np.sum(lattice.vec_lengths**2))\n",
" print(lattice_vec_norm, np.linalg.norm(v.vertices, axis=1))\n",
" cell_vertices = v.vertices[np.linalg.norm(v.vertices, axis=1) <= 0.5 * lattice_vec_norm]\n",
" \n",
" x, y = zip(*lattice_points)\n",
" ax.scatter(x, y, color=\"blue\")\n",
" x, y = zip(*cell_vertices)\n",
" arrowprops = dict(arrowstyle=\"-|>,head_width=0.4,head_length=0.8\", color=\"black\", shrinkA=0,shrinkB=0)\n",
" for i, vec in enumerate(lattice.vecs):\n",
" ax.annotate(f\"\", xy=lattice.vecs[i], xytext=lattice.center, arrowprops=arrowprops)\n",
" # add name of vector at a perpendicular offset starting at half length\n",
" ax.annotate(r\"$\\vec{a}_\"+f\"{i+1}$\", xy=0.7*lattice.vecs[i], xytext=0.7*lattice.vecs[i] + 0.06*get_orthogonal_2D(lattice.vecs[i]))\n",
" \n",
" ax.scatter(x, y, color=\"orange\")\n",
" ax.fill(x, y, color=\"#4444\")\n",
" return fig\n",
" \n",
"\n",
"plot_voronoi(tilted_lattice, vor)\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c2faef81-5f2a-4950-b986-e891ddfa7da8",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "a6b6ccf4-34c7-419d-8bcc-f3ce2870ba25",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "conda",
"language": "python",
"name": "conda"
},
"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.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}