diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..22071f1 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index 02fba5f..87b5a54 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ job* *.out __pycache__/ +./mp_20/*.csv \ No newline at end of file diff --git a/.ipynb_checkpoints/try-checkpoint.ipynb b/.ipynb_checkpoints/try-checkpoint.ipynb new file mode 100644 index 0000000..7c3710d --- /dev/null +++ b/.ipynb_checkpoints/try-checkpoint.ipynb @@ -0,0 +1,375 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'epochs': 10000, 'batchsize': 100, 'lr': 0.0001, 'lr_decay': 0.0, 'weight_decay': 0.0, 'clip_grad': 1.0, 'optimizer': 'adam', 'folder': './', 'restore_path': None, 'training_name': '${folder}${optimizer}_bs_${batchsize}_lr_${lr}_decay_${lr_decay}_clip_${clip_grad}', 'train_path': '/data/zdcao/crystal_gpt/dataset/mp_20/train.csv', 'valid_path': '/data/zdcao/crystal_gpt/dataset/mp_20/val.csv', 'test_path': '/data/zdcao/crystal_gpt/dataset/mp_20/test.csv', 'Nf': 5, 'Kx': 16, 'Kl': 4, 'h0_size': 256, 'transformer_layers': 16, 'num_heads': 16, 'key_size': 64, 'model_size': 64, 'embed_size': 32, 'dropout_rate': 0.5, 'transformer_name': 'Nf_${Nf}_Kx_${Kx}_Kl_${Kl}_h0_${h0_size}_l_${transformer_layers}_H_${num_heads}_k_${key_size}_m_${model_size}_e_${embed_size}_drop_${dropout_rate}', 'lamb_a': 1.0, 'lamb_w': 1.0, 'lamb_l': 1.0, 'loss_name': 'a_${lamb_a}_w_${lamb_w}_l_${lamb_l}', 'n_max': 21, 'atom_types': 119, 'wyck_types': 28, 'physics_name': 'A_${atom_types}_W_${wyck_types}_N_${n_max}', 'spacegroup': None, 'elements': None, 'top_p': 1.0, 'temperature': 1.0, 'num_io_process': 40, 'num_samples': 1000, 'use_foriloop': True, 'output_filename': 'output.csv'}\n", + "\n", + "========== Load checkpoint==========\n", + "No checkpoint file found. Start from scratch.\n", + "# of transformer params 461159\n" + ] + } + ], + "source": [ + "import sys\n", + "sys.path.append('./crystalformer/src/')\n", + "\n", + "import jax\n", + "import jax.numpy as jnp\n", + "from jax.flatten_util import ravel_pytree\n", + "from hydra import initialize, compose\n", + "\n", + "\n", + "import checkpoint\n", + "from transformer import make_transformer\n", + "\n", + "with initialize(version_base=None, config_path=\"./model\"):\n", + " args = compose(config_name=\"config\")\n", + " print(args)\n", + "\n", + "key = jax.random.PRNGKey(42)\n", + "params, transformer = make_transformer(key, args.Nf, args.Kx, args.Kl, args.n_max,\n", + " args.h0_size,\n", + " 4, 8,\n", + " 32, args.model_size, args.embed_size,\n", + " args.atom_types, args.wyck_types,\n", + " 0.3)\n", + "\n", + "\n", + "print(\"\\n========== Load checkpoint==========\")\n", + "restore_path = \"./share/\"\n", + "ckpt_filename, epoch_finished = checkpoint.find_ckpt_filename(restore_path)\n", + "if ckpt_filename is not None:\n", + " print(\"Load checkpoint file: %s, epoch finished: %g\" %(ckpt_filename, epoch_finished))\n", + " ckpt = checkpoint.load_data(ckpt_filename)\n", + " params = ckpt[\"params\"]\n", + "else:\n", + " print(\"No checkpoint file found. Start from scratch.\")\n", + "\n", + "print (\"# of transformer params\", ravel_pytree(params)[0].size)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import numpy as np\n", + "from pymatgen.core import Structure, Lattice\n", + "from time import time\n", + "from pymatgen.io.ase import AseAtomsAdaptor\n", + "from ase.visualize import view\n", + "\n", + "from sample import sample_crystal\n", + "from elements import element_dict, element_list\n", + "from scripts.awl2struct import get_struct_from_lawx\n", + "\n", + "jax.config.update(\"jax_enable_x64\", True) # to get off compilation warning, and to prevent sample nan lattice\n", + "\n", + "\n", + "def generate_and_visualize(spacegroup, elements, temperature, seed):\n", + "\n", + " print(f\"Generating with spacegroup={spacegroup}, elements={elements}, temperature={temperature}\")\n", + " \n", + " top_p = 1\n", + " n_sample = 1\n", + " elements = elements.split()\n", + " if elements is not None:\n", + " idx = [element_dict[e] for e in elements]\n", + " atom_mask = [1] + [1 if a in idx else 0 for a in range(1, args.atom_types)]\n", + " atom_mask = jnp.array(atom_mask)\n", + " # print ('sampling structure formed by these elements:', elements)\n", + " # print (atom_mask)\n", + " # print(\"@\")\n", + " else:\n", + " atom_mask = jnp.zeros((args.atom_types), dtype=int) # we will do nothing to a_logit in sampling\n", + " print (atom_mask)\n", + " \n", + " # fix\n", + " atom_mask = jnp.repeat(atom_mask.reshape(1, -1), args.n_max, axis=0)\n", + " key = jax.random.PRNGKey(seed)\n", + " key, subkey = jax.random.split(key)\n", + " start_time = time()\n", + "# import pdb\n", + "# pdb.set_trace()\n", + " constraints = jnp.arange(0, args.n_max, 1)\n", + " XYZ, A, W, M, L = sample_crystal(subkey, transformer, params, args.n_max, n_sample, args.atom_types, args.wyck_types, args.Kx, args.Kl, spacegroup, None, atom_mask, top_p, temperature, temperature, constraints)\n", + " end_time = time()\n", + " print(\"executation time:\", end_time - start_time)\n", + " \n", + " XYZ = np.array(XYZ)\n", + " A = np.array(A)\n", + " W = np.array(W)\n", + " L = np.array(L)\n", + " print(W, L)\n", + " \n", + " G = np.array([spacegroup for i in range(len(L))])\n", + " \n", + " structures = [get_struct_from_lawx(g, l, a, w, xyz) for g, l, a, w, xyz in zip(G, L, A, W, XYZ)]\n", + " structures = [Structure.from_dict(_) for _ in structures]\n", + " \n", + " \n", + " atoms_list = [AseAtomsAdaptor().get_atoms(struct) for struct in structures]\n", + " return view(atoms_list[0], viewer='ngl')\n", + " # return \n", + " # return structures" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generating with spacegroup=70, elements=C, temperature=0.5\n", + "executation time: 0.026823043823242188\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "30596aefae264463a20fc2c91bbe7959", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(NGLWidget(), VBox(children=(Dropdown(description='Show', options=('All', 'C'), value='All'), Dr…" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "# ============= params to control the generation =============\n", + "spacegroup = 70 # 设置生成的晶体的空间群,范围为1-230\n", + "elements = \"C\" # 限制生成晶体所包含的元素种类,每个元素需要用空格隔开,比如 \"Ba Ti O\"\n", + "temperature = 0.5 # 控制transformer生成的温度,温度越高生成的novelty越高,推荐值为 0.5到1.5\n", + "seed = 42 # 随机种子\n", + "\n", + "# =============== generate and visualization =================\n", + "generate_and_visualize(spacegroup, elements, temperature, seed)\n", + "# structures = generate_and_visualize(spacegroup, elements, temperature, seed)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[Structure Summary\n", + " Lattice\n", + " abc : 1.9728497519367452 1.9728497519367452 1.9728497519367452\n", + " angles : 90.0 90.0 90.0\n", + " volume : 7.678599825635881\n", + " A : -1.9728497519367452 0.0 -1.2080220669539923e-16\n", + " B : 1.2080220669539923e-16 -1.9728497519367452 -1.2080220669539923e-16\n", + " C : 0.0 0.0 -1.9728497519367452\n", + " pbc : True True True\n", + " PeriodicSite: C (-1.611, 0.0, -1.001) [0.8164, 0.0, 0.5073]\n", + " PeriodicSite: C (9.863e-17, -1.611, -1.001) [0.0, 0.8164, 0.5073]\n", + " PeriodicSite: C (-0.3621, -0.3621, -1.001) [0.1836, 0.1836, 0.5073]\n", + " PeriodicSite: C (-0.3621, 0.0, -1.001) [0.1836, 0.0, 0.5073]\n", + " PeriodicSite: C (2.217e-17, -0.3621, -1.001) [0.0, 0.1836, 0.5073]\n", + " PeriodicSite: C (-1.611, -1.611, -1.001) [0.8164, 0.8164, 0.5073]\n", + " PeriodicSite: C (9.863e-17, -1.611, -0.972) [0.0, 0.8164, 0.4927]\n", + " PeriodicSite: C (-1.611, 0.0, -0.972) [0.8164, 0.0, 0.4927]\n", + " PeriodicSite: C (-0.3621, -0.3621, -0.972) [0.1836, 0.1836, 0.4927]\n", + " PeriodicSite: C (2.217e-17, -0.3621, -0.972) [0.0, 0.1836, 0.4927]\n", + " PeriodicSite: C (-0.3621, 0.0, -0.972) [0.1836, 0.0, 0.4927]\n", + " PeriodicSite: C (-1.611, -1.611, -0.972) [0.8164, 0.8164, 0.4927]\n", + " PeriodicSite: C (-1.023, 0.0, -0.1123) [0.5186, 0.0, 0.05695]\n", + " PeriodicSite: C (6.265e-17, -1.023, -0.1123) [0.0, 0.5186, 0.05695]\n", + " PeriodicSite: C (-0.9497, -0.9497, -0.1123) [0.4814, 0.4814, 0.05695]\n", + " PeriodicSite: C (-0.9497, 0.0, -0.1123) [0.4814, 0.0, 0.05695]\n", + " PeriodicSite: C (5.815e-17, -0.9497, -0.1123) [0.0, 0.4814, 0.05695]\n", + " PeriodicSite: C (-1.023, -1.023, -0.1123) [0.5186, 0.5186, 0.05695]\n", + " PeriodicSite: C (6.265e-17, -1.023, -1.861) [0.0, 0.5186, 0.9431]\n", + " PeriodicSite: C (-1.023, 0.0, -1.861) [0.5186, 0.0, 0.9431]\n", + " PeriodicSite: C (-0.9497, -0.9497, -1.861) [0.4814, 0.4814, 0.9431]\n", + " PeriodicSite: C (5.815e-17, -0.9497, -1.861) [0.0, 0.4814, 0.9431]\n", + " PeriodicSite: C (-0.9497, 0.0, -1.861) [0.4814, 0.0, 0.9431]\n", + " PeriodicSite: C (-1.023, -1.023, -1.861) [0.5186, 0.5186, 0.9431]\n", + " PeriodicSite: C (-1.47, -0.7232, -1.343e-16) [0.7449, 0.3666, 0.0]\n", + " PeriodicSite: C (-1.25, -0.7465, -1.222e-16) [0.6334, 0.3784, 0.0]\n", + " PeriodicSite: C (-1.226, -0.5032, -1.059e-16) [0.6216, 0.2551, 0.0]\n", + " PeriodicSite: C (-0.5032, -1.25, -1.073e-16) [0.2551, 0.6334, 0.0]\n", + " PeriodicSite: C (-0.7232, -1.226, -1.194e-16) [0.3666, 0.6216, 0.0]\n", + " PeriodicSite: C (-0.7465, -1.47, -1.357e-16) [0.3784, 0.7449, 0.0]\n", + " PeriodicSite: C (-0.7232, -1.47, -1.343e-16) [0.3666, 0.7449, 0.0]\n", + " PeriodicSite: C (-0.7465, -1.25, -1.222e-16) [0.3784, 0.6334, 0.0]\n", + " PeriodicSite: C (-0.5032, -1.226, -1.059e-16) [0.2551, 0.6216, 0.0]\n", + " PeriodicSite: C (-1.25, -0.5032, -1.073e-16) [0.6334, 0.2551, 0.0]\n", + " PeriodicSite: C (-1.226, -0.7232, -1.194e-16) [0.6216, 0.3666, 0.0]\n", + " PeriodicSite: C (-1.47, -0.7465, -1.357e-16) [0.7449, 0.3784, 0.0]]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "structures" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "pymatgen.core.structure.Structure" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(structures[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0.81643739, 0. , 0.50729405],\n", + " [0. , 0.81643739, 0.50729405],\n", + " [0.18356261, 0.18356261, 0.50729405],\n", + " [0.18356261, 0. , 0.50729405],\n", + " [0. , 0.18356261, 0.50729405],\n", + " [0.81643739, 0.81643739, 0.50729405],\n", + " [0. , 0.81643739, 0.49270595],\n", + " [0.81643739, 0. , 0.49270595],\n", + " [0.18356261, 0.18356261, 0.49270595],\n", + " [0. , 0.18356261, 0.49270595],\n", + " [0.18356261, 0. , 0.49270595],\n", + " [0.81643739, 0.81643739, 0.49270595],\n", + " [0.518634 , 0. , 0.05694763],\n", + " [0. , 0.518634 , 0.05694763],\n", + " [0.481366 , 0.481366 , 0.05694763],\n", + " [0.481366 , 0. , 0.05694763],\n", + " [0. , 0.481366 , 0.05694763],\n", + " [0.518634 , 0.518634 , 0.05694763],\n", + " [0. , 0.518634 , 0.94305237],\n", + " [0.518634 , 0. , 0.94305237],\n", + " [0.481366 , 0.481366 , 0.94305237],\n", + " [0. , 0.481366 , 0.94305237],\n", + " [0.481366 , 0. , 0.94305237],\n", + " [0.518634 , 0.518634 , 0.94305237],\n", + " [0.74494652, 0.36655847, 0. ],\n", + " [0.63344153, 0.37838805, 0. ],\n", + " [0.62161195, 0.25505348, 0. ],\n", + " [0.25505348, 0.63344153, 0. ],\n", + " [0.36655847, 0.62161195, 0. ],\n", + " [0.37838805, 0.74494652, 0. ],\n", + " [0.36655847, 0.74494652, 0. ],\n", + " [0.37838805, 0.63344153, 0. ],\n", + " [0.25505348, 0.62161195, 0. ],\n", + " [0.63344153, 0.25505348, 0. ],\n", + " [0.62161195, 0.36655847, 0. ],\n", + " [0.74494652, 0.37838805, 0. ]])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "abc = structures[0].lattice.abc\n", + "pos = structures[0].frac_coords\n", + "pos" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "fig = plt.figure()\n", + "ax = fig.add_subplot(111)\n", + "x = pos[:,0]*abc[0]\n", + "y = pos[:,1]*abc[1]\n", + "# x = np.array([x[2],x[1],x[2],x[0],x[2]+abc[0]])\n", + "# y = np.array([y[2]+abc[1],y[1],y[2],y[0],y[2]])\n", + "for i in range(3):\n", + " for j in range(3):\n", + " ax.scatter(x+i*abc[0],y+j*abc[1])\n", + " # ax.plot(x+i*abc[0],y+j*abc[1])\n", + " # ax.plot()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.15" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e79b0b5 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +default: test + +.PHONY: test test-% train sample + +TESTS = $(shell find ./tests -name "test_*.py") + +test-%: + python ./tests/test_$*.py + +test: + @for TEST in $(TESTS); do \ + echo "run $$TEST"; \ + python $$TEST; \ + done + +train: + python ./main.py --folder ./data/ --train_path ./mp_20/train_layer_test.csv --valid_path ./mp_20/val_layer_test.csv --epochs 200 + +sample: + python ./main.py --optimizer none --test_path ./mp_20/test_layer_test.csv --restore_path ./data/adam_bs_100_lr_0.0001_decay_0_clip_1_A_119_W_28_N_21_a_1_w_1_l_1_Nf_5_Kx_16_Kl_4_h0_256_l_16_H_16_k_64_m_64_e_32_drop_0.5/epoch_000100.pkl --spacegroup 65 --num_samples 10 --batchsize 200 --temperature 1.0 --elements C \ No newline at end of file diff --git a/c2db/.DS_Store b/c2db/.DS_Store new file mode 100644 index 0000000..2d9672e Binary files /dev/null and b/c2db/.DS_Store differ diff --git a/c2db/A/.DS_Store b/c2db/A/.DS_Store new file mode 100644 index 0000000..9667d3c Binary files /dev/null and b/c2db/A/.DS_Store differ diff --git a/c2db/A/2C/.DS_Store b/c2db/A/2C/.DS_Store new file mode 100644 index 0000000..f0f4e41 Binary files /dev/null and b/c2db/A/2C/.DS_Store differ diff --git a/c2db/A/2C/1/data.json b/c2db/A/2C/1/data.json new file mode 100644 index 0000000..ba6ce4f --- /dev/null +++ b/c2db/A/2C/1/data.json @@ -0,0 +1,44 @@ +{ + "folder": "/home/niflheim2/cmr/C2DB-ASR/tree/A/C/C2-a6735a4a3797", + "uid": "2C-1", + "olduid": "C2-a6735a4a3797", + "international": "P6/mmm", + "number": 191, + "pointgroup": "6/mmm", + "has_inversion_symmetry": true, + "lgnum": 80, + "layergroup": "p6/mmm", + "bravais_type": "Hexagonal (hp)", + "thickness": 3.224913225352566e-08, + "label": "original03-18", + "gap": 0.0003000685114302737, + "gap_dir": 0.0003000685114309398, + "gap_dir_nosoc": 0.000308946496943463, + "evac": 2.3363375983102452, + "efermi": -4.248481577688634, + "vbm": -4.248631611944349, + "cbm": -4.2483315434329185, + "minhessianeig": -7.00605419619458e-12, + "dyn_stab": "Yes", + "gap_hse": 0.0002564957267392476, + "gap_dir_hse": 0.0002564957267392476, + "efermi_hse": -4.213085568171573, + "vbm_hse": -4.213213816034942, + "cbm_hse": -4.212957320308203, + "alphax_el": 6.574592003348396, + "alphay_el": 6.574592003348392, + "alphaz_el": 0.1533681498711251, + "plasmafrequency_x": 0.0, + "plasmafrequency_y": 0.0, + "energy": -18.453766945888727, + "icsd_id": 96620, + "cod_id": 9012705, + "doi": "10.1126/science.1102896", + "is_magnetic": false, + "spin_axis": "z", + "dE_zx": 0.0, + "dE_zy": 0.0, + "topology": "Z2=1,C_M=1", + "ehull": 0.0, + "hform": -0.007391614814171277 +} \ No newline at end of file diff --git a/c2db/A/2C/1/magmoms.json b/c2db/A/2C/1/magmoms.json new file mode 100644 index 0000000..fb78ad4 --- /dev/null +++ b/c2db/A/2C/1/magmoms.json @@ -0,0 +1,4 @@ +{ +"folder": "/home/niflheim2/cmr/C2DB-ASR/tree/A/C/C2-a6735a4a3797", +"uid": "2C-1" +} \ No newline at end of file diff --git a/c2db/A/2C/1/read.py b/c2db/A/2C/1/read.py new file mode 100644 index 0000000..46aa1b4 --- /dev/null +++ b/c2db/A/2C/1/read.py @@ -0,0 +1,7 @@ +import re + +def lattice_from_file(file_path): + f = open(file_path, "r") + lines = f.readlines() + lattice_str = re.search(r'Lattice="([^"]+)"', lines[1]).group(1) + lattice_list = [eval(v) for v in lattice_str] \ No newline at end of file diff --git a/c2db/A/2C/1/results-asr.stiffness.json b/c2db/A/2C/1/results-asr.stiffness.json new file mode 100644 index 0000000..40aa7f7 --- /dev/null +++ b/c2db/A/2C/1/results-asr.stiffness.json @@ -0,0 +1,108 @@ +{ + "object_id": "asr.stiffness::Result", + "constructor": "asr.stiffness::Result", + "args": [], + "kwargs": { + "data": { + "speed_of_sound_x": 21373.063352135574, + "speed_of_sound_y": 21370.856641622737, + "c_11": 345.6538905582198, + "c_12": 70.60779871921024, + "c_13": 0.0005778599312093563, + "c_14": null, + "c_15": null, + "c_16": null, + "c_21": 70.56537570227611, + "c_22": 345.58251859948973, + "c_23": 5.3339141915441094e-05, + "c_24": null, + "c_25": null, + "c_26": null, + "c_31": -1.48020629620793e-13, + "c_32": -3.171870634731279e-14, + "c_33": 275.09324474892543, + "c_34": null, + "c_35": null, + "c_36": null, + "c_41": null, + "c_42": null, + "c_43": null, + "c_44": null, + "c_45": null, + "c_46": null, + "c_51": null, + "c_52": null, + "c_53": null, + "c_54": null, + "c_55": null, + "c_56": null, + "c_61": null, + "c_62": null, + "c_63": null, + "c_64": null, + "c_65": null, + "c_66": null, + "__links__": { + "strains--1.0%-xx": "C2-b088c34acc1b", + "strains-+1.0%-xx": "C2-df0c254be7f9", + "strains--1.0%-yy": "C2-65c455263aaa", + "strains-+1.0%-yy": "C2-2fc059f556fa", + "strains--1.0%-xy": "C2-9ec52112fdfe", + "strains-+1.0%-xy": "C2-92a5b8f033fd" + }, + "stiffness_tensor": { + "__ndarray__": [ + [ + 3, + 3 + ], + "float64", + [ + 345.6538905582198, + 70.60779871921024, + 0.0005778599312093563, + 70.56537570227611, + 345.58251859948973, + 5.3339141915441094e-05, + -1.48020629620793e-13, + -3.171870634731279e-14, + 275.09324474892543 + ] + ] + }, + "eigenvalues": { + "__ndarray__": [ + [ + 3 + ], + "float64", + [ + 416.20479762329126, + 275.03161153441835, + 275.09324474892543 + ] + ] + }, + "dynamic_stability_stiffness": "high" + }, + "metadata": { + "asr_name": "asr.stiffness", + "resources": { + "time": 0.05871438980102539, + "ncores": 1, + "tstart": 1605182101.3158286, + "tend": 1605182101.374543 + }, + "params": { + "strain_percent": 1.0 + }, + "code_versions": { + "asr": "0.4.1-fef8a0ce2ab711c3284f5dbfd158907b17f534e9", + "ase": "3.21.0b1-8a83b7f6a6fd68b95b9f542d7c054fa7204d764a", + "gpaw": "20.10.1b1-7ff8d570c9d25f2af1c40c00271000e3ab505f1c" + }, + "creates": {} + }, + "strict": true + } +} \ No newline at end of file diff --git a/c2db/A/2C/1/structure.xyz b/c2db/A/2C/1/structure.xyz new file mode 100644 index 0000000..9ae9c86 --- /dev/null +++ b/c2db/A/2C/1/structure.xyz @@ -0,0 +1,4 @@ +2 +Lattice="2.4672312604313453 -1.7550685731635223e-20 0.0 -1.233615630215672 2.1366849485446453 0.0 1.118374734265682e-17 0.0 15.0" Properties=species:S:1:pos:R:3 energy=-18.453766945888727 dipole="0.8699688255098961 -0.5022767355947244 3.473501422988429e-08" free_energy=-18.45387516640614 pbc="T T F" +C 0.00000000 0.00000000 7.49999997 +C 1.23361563 0.71222832 7.50000001 diff --git a/c2db_problem.ipynb b/c2db_problem.ipynb new file mode 100644 index 0000000..01d9cdf --- /dev/null +++ b/c2db_problem.ipynb @@ -0,0 +1,72 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "C2DB dataset has two components: `data.json` and `structure.xyz`.\n", + "The `data.json` file stores properties of the material:\n", + "```\n", + "{\n", + " \"folder\": \"/home/niflheim2/cmr/C2DB-ASR/tree/A/C/C2-a6735a4a3797\",\n", + " \"uid\": \"2C-1\",\n", + " \"olduid\": \"C2-a6735a4a3797\",\n", + " \"international\": \"P6/mmm\",\n", + " \"number\": 191,\n", + " \"pointgroup\": \"6/mmm\",\n", + " \"has_inversion_symmetry\": true,\n", + " \"lgnum\": 80,\n", + " \"layergroup\": \"p6/mmm\",\n", + " \"bravais_type\": \"Hexagonal (hp)\",\n", + " \"thickness\": 3.224913225352566e-08,\n", + " \"label\": \"original03-18\",\n", + " \"gap\": 0.0003000685114302737,\n", + " \"gap_dir\": 0.0003000685114309398,\n", + " \"gap_dir_nosoc\": 0.000308946496943463,\n", + " \"evac\": 2.3363375983102452,\n", + " \"efermi\": -4.248481577688634,\n", + " \"vbm\": -4.248631611944349,\n", + " \"cbm\": -4.2483315434329185,\n", + " \"minhessianeig\": -7.00605419619458e-12,\n", + " \"dyn_stab\": \"Yes\",\n", + " \"gap_hse\": 0.0002564957267392476,\n", + " \"gap_dir_hse\": 0.0002564957267392476,\n", + " \"efermi_hse\": -4.213085568171573,\n", + " \"vbm_hse\": -4.213213816034942,\n", + " \"cbm_hse\": -4.212957320308203,\n", + " \"alphax_el\": 6.574592003348396,\n", + " \"alphay_el\": 6.574592003348392,\n", + " \"alphaz_el\": 0.1533681498711251,\n", + " \"plasmafrequency_x\": 0.0,\n", + " \"plasmafrequency_y\": 0.0,\n", + " \"energy\": -18.453766945888727,\n", + " \"icsd_id\": 96620,\n", + " \"cod_id\": 9012705,\n", + " \"doi\": \"10.1126/science.1102896\",\n", + " \"is_magnetic\": false,\n", + " \"spin_axis\": \"z\",\n", + " \"dE_zx\": 0.0,\n", + " \"dE_zy\": 0.0,\n", + " \"topology\": \"Z2=1,C_M=1\",\n", + " \"ehull\": 0.0,\n", + " \"hform\": -0.007391614814171277\n", + "}\n", + "```\n", + "And the `structure.xyz` file stores information about the cell and the lattice:\n", + "```\n", + "2\n", + "Lattice=\"2.4672312604313453 -1.7550685731635223e-20 0.0 -1.233615630215672 2.1366849485446453 0.0 1.118374734265682e-17 0.0 15.0\" Properties=species:S:1:pos:R:3 energy=-18.453766945888727 dipole=\"0.8699688255098961 -0.5022767355947244 3.473501422988429e-08\" free_energy=-18.45387516640614 pbc=\"T T F\"\n", + "C 0.00000000 0.00000000 7.49999997\n", + "C 1.23361563 0.71222832 7.50000001\n", + "```\n" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/c2db_try.py b/c2db_try.py new file mode 100644 index 0000000..7070684 --- /dev/null +++ b/c2db_try.py @@ -0,0 +1,7 @@ +import matplotlib.pyplot as plt +from ase.db import connect + +db = connect('c2db.db') +rows = db.select('layergroup') + +rows.layergroup \ No newline at end of file diff --git a/crystalformer.egg-info/PKG-INFO b/crystalformer.egg-info/PKG-INFO new file mode 100644 index 0000000..227122a --- /dev/null +++ b/crystalformer.egg-info/PKG-INFO @@ -0,0 +1,11 @@ +Metadata-Version: 2.1 +Name: crystalformer +Version: 0.3 +Summary: CrystalFormer is a transformer-based autoregressive model specifically designed for space group-controlled generation of crystalline materials. +Home-page: https://github.com/deepmodeling/CrystalFormer +Author: iopcompphys +Author-email: zdcao@iphy.ac.cn, wanglei@iphy.ac.cn +License: Apache License +Keywords: Crystal Generation +Platform: any +License-File: LICENSE diff --git a/crystalformer.egg-info/SOURCES.txt b/crystalformer.egg-info/SOURCES.txt new file mode 100644 index 0000000..c4ee3e1 --- /dev/null +++ b/crystalformer.egg-info/SOURCES.txt @@ -0,0 +1,38 @@ +LICENSE +README.md +setup.py +crystalformer/__init__.py +crystalformer.egg-info/PKG-INFO +crystalformer.egg-info/SOURCES.txt +crystalformer.egg-info/dependency_links.txt +crystalformer.egg-info/top_level.txt +crystalformer/data/layer.csv +crystalformer/data/wyckoff_list.csv +crystalformer/data/wyckoff_symbols.csv +crystalformer/extension/__init__.py +crystalformer/extension/experimental.py +crystalformer/extension/loss.py +crystalformer/extension/mcmc.py +crystalformer/extension/model.py +crystalformer/extension/train.py +crystalformer/extension/transformer.py +crystalformer/src/__init__.py +crystalformer/src/attention.py +crystalformer/src/checkpoint.py +crystalformer/src/elements.py +crystalformer/src/lattice.py +crystalformer/src/loss.py +crystalformer/src/mcmc.py +crystalformer/src/sample.py +crystalformer/src/sym_group.py +crystalformer/src/train.py +crystalformer/src/transformer.py +crystalformer/src/utils.py +crystalformer/src/von_mises.py +crystalformer/src/wyckoff.py +tests/test_fc_mask.py +tests/test_lattice.py +tests/test_sampling.py +tests/test_transformer.py +tests/test_utils.py +tests/test_wyckoff.py \ No newline at end of file diff --git a/crystalformer.egg-info/dependency_links.txt b/crystalformer.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/crystalformer.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/crystalformer.egg-info/top_level.txt b/crystalformer.egg-info/top_level.txt new file mode 100644 index 0000000..cdc9aa0 --- /dev/null +++ b/crystalformer.egg-info/top_level.txt @@ -0,0 +1 @@ +crystalformer diff --git a/crystalformer/.DS_Store b/crystalformer/.DS_Store new file mode 100644 index 0000000..04df921 Binary files /dev/null and b/crystalformer/.DS_Store differ diff --git a/crystalformer/data/layer.csv b/crystalformer/data/layer.csv new file mode 100644 index 0000000..ff64aa9 --- /dev/null +++ b/crystalformer/data/layer.csv @@ -0,0 +1,81 @@ +Layer Group,Wyckoff Positions +1,"[['x,y,z']]" +2,"[['x,y,z','-x,-y,-z'],['1/2,1/2,0'],['1/2,0,0'],['0,1/2,0'],['0,0,0']]" +3,"[['x,y,z','-x,-y,z'],['1/2,1/2,z'],['1/2,0,z'],['0,1/2,z'],['0,0,z']]" +4,"[['x,y,z','x,y,-z'],['x,y,0']]" +5,"[['x,y,z','x+1/2,y,-z']]" +6,"[['x,y,z','-x,-y,z','-x,-y,-z','x,y,-z'],['x,y,0','-x,-y,0'],['1/2,1/2,z','1/2,1/2,-z'],['1/2,0,z','1/2,0,-z'],['0,1/2,z','0,1/2,-z'],['0,0,z','0,0,-z'],['1/2,1/2,0'],['0,1/2,0'],['1/2,0,0'],['0,0,0']]" +7,"[['x,y,z','-x+1/2,-y,z','-x,-y,-z','x+1/2,y,-z'],['1/4,1/2,z','3/4,1/2,-z'],['1/4,0,z','3/4,0,-z'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +8,"[['x,y,z','x,-y,-z'],['x,1/2,0'],['x,0,0']]" +9,"[['x,y,z','x+1/2,-y,-z']]" +10,"[['x,y,z','x,-y,-z','x+1/2,y+1/2,z','x+1/2,-y+1/2,-z'],['x,0,0','x+1/2,1/2,0']]" +11,"[['x,y,z','-x,y,z'],['1/2,y,z'],['0,y,z']]" +12,"[['x,y,z','-x,y+1/2,z']]" +13,"[['x,y,z','-x,y,z','x+1/2,y+1/2,z','-x+1/2,y+1/2,z'],['0,y,z','1/2,y+1/2,z']]" +14,"[['x,y,z','x,-y,-z','-x,-y,-z','-x,y,z'],['1/2,y,z','1/2,-y,-z'],['0,y,z','0,-y,-z'],['x,1/2,0','-x,1/2,0'],['x,0,0','-x,0,0'],['1/2,1/2,0'],['0,1/2,0'],['1/2,0,0'],['0,0,0']]" +15,"[['x,y,z','x+1/2,-y,-z','-x,-y,-z','-x+1/2,y,z'],['1/4,y,z','3/4,-y,-z'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +16,"[['x,y,z','x,-y+1/2,-z','-x,-y,-z','-x,y+1/2,z'],['x,1/4,0','-x,3/4,0'],['1/2,0,0','1/2,1/2,0'],['0,0,0','0,1/2,0']]" +17,"[['x,y,z','x+1/2,-y+1/2,-z','-x,-y,-z','-x+1/2,y+1/2,z'],['0,1/2,0','1/2,0,0'],['0,0,0','1/2,1/2,0']]" +18,"[['x,y,z','x,-y,-z','-x,-y,-z','-x,y,z','x+1/2,y+1/2,z','x+1/2,-y+1/2,-z','-x+1/2,-y+1/2,-z','-x+1/2,y+1/2,z'],['0,y,z','0,-y,-z','1/2,y+1/2,z','1/2,-y+1/2,-z'],['x,0,0','-x,0,0','x+1/2,1/2,0','-x+1/2,1/2,0'],['1/4,1/4,0','1/4,3/4,0','3/4,3/4,0','3/4,5/4,0'],['1/2,0,0','1,1/2,0'],['0,0,0','1/2,1/2,0']]" +19,"[['x,y,z','-x,-y,z','-x,y,-z','x,-y,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,1/2,z','0,1/2,-z'],['1/2,0,z','1/2,0,-z'],['0,0,z','0,0,-z'],['1/2,y,0','1/2,-y,0'],['0,y,0','0,-y,0'],['x,1/2,0','-x,1/2,0'],['x,0,0','-x,0,0'],['1/2,1/2,0'],['0,1/2,0'],['1/2,0,0'],['0,0,0']]" +20,"[['x,y,z','x+1/2,-y,-z','-x+1/2,y,-z','-x,-y,z'],['1/4,y,0','3/4,-y,0'],['0,1/2,z','1/2,1/2,-z'],['0,0,z','1/2,0,-z']]" +21,"[['x,y,z','-x,-y,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z'],['0,1/2,z','1/2,0,-z'],['0,0,z','1/2,1/2,-z']]" +22,"[['x,y,z','-x,-y,z','-x,y,-z','x,-y,-z','x+1/2,y+1/2,z','-x+1/2,-y+1/2,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z'],['1/4,1/4,z','3/4,1/4,-z','3/4,3/4,z','5/4,3/4,-z'],['0,1/2,z','0,1/2,-z','1/2,1,z','1/2,1,-z'],['0,0,z','0,0,-z','1/2,1/2,z','1/2,1/2,-z'],['0,y,0','0,-y,0','1/2,y+1/2,0','1/2,-y+1/2,0'],['x,0,0','-x,0,0','x+1/2,1/2,0','-x+1/2,1/2,0'],['0,1/2,0','1/2,1,0'],['0,0,0','1/2,1/2,0']]" +23,"[['x,y,z','-x,-y,z','x,-y,z','-x,y,z'],['1/2,y,z','1/2,-y,z'],['0,y,z','0,-y,z'],['x,1/2,z','-x,1/2,z'],['x,0,z','-x,0,z'],['1/2,1/2,z'],['1/2,0,z'],['0,1/2,z'],['0,0,z']]" +24,"[['x,y,z','-x,-y,z','x+1/2,-y,z','-x+1/2,y,z'],['1/4,y,z','3/4,-y,z'],['0,1/2,z','1/2,1/2,z'],['0,0,z','1/2,0,z']]" +25,"[['x,y,z','-x,-y,z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z'],['0,1/2,z','1/2,0,z'],['0,0,z','1/2,1/2,z']]" +26,"[['x,y,z','-x,-y,z','x,-y,z','-x,y,z','x+1/2,y+1/2,z','-x+1/2,-y+1/2,z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z'],['0,y,z','0,-y,z','1/2,y+1/2,z','1/2,-y+1/2,z'],['x,0,z','-x,0,z','x+1/2,1/2,z','-x+1/2,1/2,z'],['1/4,1/4,z','1/4,3/4,z','3/4,3/4,z','3/4,5/4,z'],['0,1/2,z','1/2,1,z'],['0,0,z','1/2,1/2,z']]" +27,"[['x,y,z','-x,y,-z','-x,y,z','x,y,-z'],['x,y,0','-x,y,0'],['1/2,y,z','1/2,y,-z'],['0,y,z','0,y,-z'],['1/2,y,0'],['0,y,0']]" +28,"[['x,y,z','-x,y+1/2,-z','x,y+1/2,-z','-x,y,z'],['1/2,y,z','1/2,y+1/2,-z'],['0,y,z','0,y+1/2,-z']]" +29,"[['x,y,z','-x,y+1/2,-z','-x,y+1/2,z','x,y,-z'],['x,y,0','-x,y+1/2,0']]" +30,"[['x,y,z','-x,y,-z','x,y+1/2,-z','-x,y+1/2,z'],['1/2,y,0','1/2,y+1/2,0'],['0,y,0','0,y+1/2,0']]" +31,"[['x,y,z','-x,y,-z','x+1/2,y,-z','-x+1/2,y,z'],['1/4,y,z','3/4,y,-z'],['0,y,0','1/2,y,0']]" +32,"[['x,y,z','-x+1/2,y+1/2,-z','x+1/2,y+1/2,-z','-x,y,z'],['0,y,z','1/2,y+1/2,-z']]" +33,"[['x,y,z','-x,y+1/2,-z','x+1/2,y,-z','-x+1/2,y+1/2,z']]" +34,"[['x,y,z','-x,y,-z','-x+1/2,y+1/2,z','x+1/2,y+1/2,-z'],['0,y,0','1/2,y+1/2,0']]" +35,"[['x,y,z','-x,y,-z','-x,y,z','x,y,-z','x+1/2,y+1/2,z','-x+1/2,y+1/2,-z','-x+1/2,y+1/2,z','x+1/2,y+1/2,-z'],['x,y,0','-x,y,0','x+1/2,y+1/2,0','-x+1/2,y+1/2,0'],['0,y,z','0,y,-z','1/2,y+1/2,z','1/2,y+1/2,-z'],['0,y,0','1/2,y+1/2,0']]" +36,"[['x,y,z','-x,y,-z','-x+1/2,y,z','x+1/2,y,-z','x+1/2,y+1/2,z','-x+1/2,y+1/2,-z','-x+1,y+1/2,z','x+1,y+1/2,-z'],['1/4,y,z','3/4,y,-z','3/4,y+1/2,z','5/4,y+1/2,-z'],['0,y,0','1/2,y,0','1/2,y+1/2,0','1,y+1/2,0']]" +37,"[['x,y,z','-x,-y,z','-x,y,-z','x,-y,-z','-x,-y,-z','x,y,-z','x,-y,z','-x,y,z'],['x,y,0','-x,-y,0','-x,y,0','x,-y,0'],['x,1/2,z','-x,1/2,z','-x,1/2,-z','x,1/2,-z'],['x,0,z','-x,0,z','-x,0,-z','x,0,-z'],['1/2,y,z','1/2,-y,z','1/2,y,-z','1/2,-y,-z'],['0,y,z','0,-y,z','0,y,-z','0,-y,-z'],['1/2,1/2,z','1/2,1/2,-z'],['1/2,0,z','1/2,0,-z'],['0,1/2,z','0,1/2,-z'],['0,0,z','0,0,-z'],['1/2,y,0','1/2,-y,0'],['0,y,0','0,-y,0'],['x,1/2,0','-x,1/2,0'],['x,0,0','-x,0,0'],['1/2,1/2,0'],['0,1/2,0'],['1/2,0,0'],['0,0,0']]" +38,"[['x,y,z','x,-y,-z','-x+1/2,-y,z','-x+1/2,y,-z','-x,-y,-z','-x,y,z','x+1/2,y,-z','x+1/2,-y,z'],['0,y,z','0,-y,-z','1/2,-y,z','1/2,y,-z'],['x,1/2,0','-x+1/2,1/2,0','-x,1/2,0','x+1/2,1/2,0'],['x,0,0','-x+1/2,0,0','-x,0,0','x+1/2,0,0'],['1/4,1/2,z','1/4,1/2,-z','3/4,1/2,-z','3/4,1/2,z'],['1/4,0,z','1/4,0,-z','3/4,0,-z','3/4,0,z'],['1/4,y,0','1/4,-y,0','3/4,-y,0','3/4,y,0'],['1/4,1/2,0','3/4,1/2,0'],['1/4,0,0','3/4,0,0'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +39,"[['x,y,z','-x+1/2,-y+1/2,z','-x+1/2,y,-z','x,-y+1/2,-z','-x,-y,-z','x+1/2,y+1/2,-z','x+1/2,-y,z','-x,y+1/2,z'],['1/4,3/4,z','1/4,3/4,-z','3/4,1/4,-z','3/4,1/4,z'],['1/4,1/4,z','1/4,1/4,-z','3/4,3/4,-z','3/4,3/4,z'],['1/4,y,0','1/4,-y+1/2,0','3/4,-y,0','3/4,y+1/2,0'],['x,1/4,0','-x+1/2,1/4,0','-x,3/4,0','x+1/2,3/4,0'],['0,0,0','1/2,1/2,0','1/2,0,0','0,1/2,0'],['3/4,1/4,0','1/4,3/4,0'],['1/4,1/4,0','3/4,3/4,0']]" +40,"[['x,y,z','-x+1/2,y,-z','-x,-y,z','x+1/2,-y,-z','-x,-y,-z','x+1/2,-y,z','x,y,-z','-x+1/2,y,z'],['1/4,y,z','1/4,y,-z','3/4,-y,z','3/4,-y,-z'],['x,y,0','-x+1/2,y,0','-x,-y,0','x+1/2,-y,0'],['0,1/2,z','1/2,1/2,-z','0,1/2,-z','1/2,1/2,z'],['0,0,z','1/2,0,-z','0,0,-z','1/2,0,z'],['1/4,y,0','3/4,-y,0'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +41,"[['x,y,z','-x+1/2,-y,z','-x,y,-z','x+1/2,-y,-z','-x,-y,-z','x+1/2,y,-z','x,-y,z','-x+1/2,y,z'],['1/4,y,z','1/4,-y,z','3/4,y,-z','3/4,-y,-z'],['x,1/2,z','-x+1/2,1/2,z','-x,1/2,-z','x+1/2,1/2,-z'],['x,0,z','-x+1/2,0,z','-x,0,-z','x+1/2,0,-z'],['0,y,0','1/2,-y,0','0,-y,0','1/2,y,0'],['1/4,1/2,z','3/4,1/2,-z'],['1/4,0,z','3/4,0,-z'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +42,"[['x,y,z','-x+1/2,y+1/2,-z','-x+1/2,-y+1/2,z','x,-y,-z','-x,-y,-z','x+1/2,-y+1/2,z','x+1/2,y+1/2,-z','-x,y,z'],['0,y,z','1/2,y+1/2,-z','1/2,-y+1/2,z','0,-y,-z'],['1/4,1/4,z','1/4,3/4,-z','3/4,3/4,-z','3/4,1/4,z'],['x,0,0','-x+1/2,1/2,0','-x,0,0','x+1/2,1/2,0'],['1/2,0,0','0,1/2,0'],['0,0,0','1/2,1/2,0']]" +43,"[['x,y,z','x,-y+1/2,-z','-x+1/2,-y,z','-x+1/2,y+1/2,-z','-x,-y,-z','-x,y+1/2,z','x+1/2,y,-z','x+1/2,-y+1/2,z'],['x,1/4,0','-x+1/2,3/4,0','-x,3/4,0','x+1/2,1/4,0'],['1/4,0,z','1/4,1/2,-z','3/4,0,-z','3/4,1/2,z'],['0,0,0','0,1/2,0','1/2,0,0','1/2,1/2,0']]" +44,"[['x,y,z','-x,-y,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','-x,-y,-z','x,y,-z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z'],['x,y,0','-x,-y,0','-x+1/2,y+1/2,0','x+1/2,-y+1/2,0'],['0,1/2,z','1/2,0,-z','0,1/2,-z','1/2,0,z'],['0,0,z','1/2,1/2,-z','0,0,-z','1/2,1/2,z'],['0,1/2,0','1/2,0,0'],['0,0,0','1/2,1/2,0']]" +45,"[['x,y,z','-x,y+1/2,-z','x+1/2,-y+1/2,-z','-x+1/2,-y,z','-x,-y,-z','x,-y+1/2,z','-x+1/2,y+1/2,z','x+1/2,y,-z'],['x,1/4,z','-x,3/4,-z','x+1/2,1/4,-z','-x+1/2,3/4,z'],['1/4,0,z','3/4,1/2,-z','3/4,0,-z','1/4,1/2,z'],['0,0,0','0,1/2,0','1/2,1/2,0','1/2,0,0']]" +46,"[['x,y,z','-x+1/2,-y+1/2,z','-x,y+1/2,-z','x+1/2,-y,-z','-x,-y,-z','x+1/2,y+1/2,-z','x,-y+1/2,z','-x+1/2,y,z'],['x,1/4,z','-x+1/2,1/4,z','-x,3/4,-z','x+1/2,3/4,-z'],['1/4,y,z','1/4,-y+1/2,z','3/4,y+1/2,-z','3/4,-y,-z'],['0,0,0','1/2,1/2,0','0,1/2,0','1/2,0,0'],['1/4,3/4,z','3/4,1/4,-z'],['1/4,1/4,z','3/4,3/4,-z']]" +47,"[['x,y,z','-x,-y,z','-x,y,-z','x,-y,-z','-x,-y,-z','x,y,-z','x,-y,z','-x,y,z','x+1/2,y+1/2,z','-x+1/2,-y+1/2,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','-x+1/2,-y+1/2,-z','x+1/2,y+1/2,-z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z'],['x,y,0','-x,-y,0','-x,y,0','x,-y,0','x+1/2,y+1/2,0','-x+1/2,-y+1/2,0','-x+1/2,y+1/2,0','x+1/2,-y+1/2,0'],['x,0,z','-x,0,z','-x,0,-z','x,0,-z','x+1/2,1/2,z','-x+1/2,1/2,z','-x+1/2,1/2,-z','x+1/2,1/2,-z'],['0,y,z','0,-y,z','0,y,-z','0,-y,-z','1/2,y+1/2,z','1/2,-y+1/2,z','1/2,y+1/2,-z','1/2,-y+1/2,-z'],['1/4,1/4,z','3/4,1/4,-z','3/4,3/4,-z','1/4,3/4,z','3/4,3/4,z','5/4,3/4,-z','5/4,5/4,-z','3/4,5/4,z'],['0,1/2,z','0,1/2,-z','1/2,1,z','1/2,1,-z'],['0,0,z','0,0,-z','1/2,1/2,z','1/2,1/2,-z'],['0,y,0','0,-y,0','1/2,y+1/2,0','1/2,-y+1/2,0'],['x,0,0','-x,0,0','x+1/2,1/2,0','-x+1/2,1/2,0'],['1/4,1/4,0','3/4,1/4,0','3/4,3/4,0','5/4,3/4,0'],['1/2,0,0','1,1/2,0'],['0,0,0','1/2,1/2,0']]" +48,"[['x,y,z','-x,-y+1/2,z','-x,y+1/2,-z','x,-y,-z','-x,-y,-z','x,y+1/2,-z','x,-y+1/2,z','-x,y,z','x+1/2,y+1/2,z','-x+1/2,-y+1,z','-x+1/2,y+1,-z','x+1/2,-y+1/2,-z','-x+1/2,-y+1/2,-z','x+1/2,y+1,-z','x+1/2,-y+1,z','-x+1/2,y+1/2,z'],['x,1/4,z','-x,1/4,z','-x,3/4,-z','x,3/4,-z','x+1/2,3/4,z','-x+1/2,3/4,z','-x+1/2,5/4,-z','x+1/2,5/4,-z'],['0,y,z','0,-y+1/2,z','0,y+1/2,-z','0,-y,-z','1/2,y+1/2,z','1/2,-y+1,z','1/2,y+1,-z','1/2,-y+1/2,-z'],['1/4,0,z','3/4,1/2,-z','3/4,0,-z','1/4,1/2,z','3/4,1/2,z','5/4,1,-z','5/4,1/2,-z','3/4,1,z'],['1/4,y,0','3/4,-y+1/2,0','3/4,-y,0','1/4,y+1/2,0','3/4,y+1/2,0','5/4,-y+1,0','5/4,-y+1/2,0','3/4,y+1,0'],['x,0,0','-x,1/2,0','-x,0,0','x,1/2,0','x+1/2,1/2,0','-x+1/2,1,0','-x+1/2,1/2,0','x+1/2,1,0'],['0,1/4,z','0,3/4,-z','1/2,3/4,z','1/2,5/4,-z'],['1/4,1/4,0','3/4,1/4,0','3/4,3/4,0','5/4,3/4,0'],['0,0,0','0,1/2,0','1/2,1/2,0','1/2,1,0'],['1/4,0,0','3/4,0,0','3/4,1/2,0','5/4,1/2,0']]" +49,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z'],['0,1/2,z','1/2,0,z'],['1/2,1/2,z'],['0,0,z']]" +50,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z'],['0,1/2,z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['1/2,1/2,0'],['0,0,0']]" +51,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x,-y,-z','x,y,-z','y,-x,-z','-y,x,-z'],['x,y,0','-x,-y,0','-y,x,0','y,-x,0'],['0,1/2,z','1/2,0,z','0,1/2,-z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['0,1/2,0','1/2,0,0'],['1/2,1/2,0'],['0,0,0']]" +52,"[['x,y,z','-x+1/2,-y+1/2,z','-y+1/2,x,z','y,-x+1/2,z','-x,-y,-z','x+1/2,y+1/2,-z','y+1/2,-x,-z','-y,x+1/2,-z'],['1/4,3/4,z','3/4,1/4,z','3/4,1/4,-z','1/4,3/4,-z'],['0,0,0','1/2,1/2,0','1/2,0,0','0,0,0'],['1/4,1/4,z','3/4,3/4,-z'],['1/4,3/4,0','3/4,1/4,0']]" +53,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x,y,-z','x,-y,-z','y,x,-z','-y,-x,-z'],['x,1/2,0','-x,1/2,0','1/2,x,0','1/2,-x,0'],['x,0,0','-x,0,0','0,x,0','0,-x,0'],['x,x,0','-x,-x,0','-x,x,0','x,-x,0'],['0,1/2,z','1/2,0,z','0,1/2,-z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['1/2,0,0','0,1/2,0'],['1/2,1/2,0'],['0,0,0']]" +54,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','y+1/2,x+1/2,-z','-y+1/2,-x+1/2,-z'],['x,x+1/2,0','-x,-x+1/2,0','-x+1/2,x,0','x+1/2,-x,0'],['0,1/2,z','1/2,0,z','1/2,0,-z','0,1/2,-z'],['0,0,z','1/2,1/2,-z'],['0,1/2,0','1/2,0,0']]" +55,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','x,-y,z','-x,y,z','-y,-x,z','y,x,z'],['x,1/2,z','-x,1/2,z','1/2,x,z','1/2,-x,z'],['x,0,z','-x,0,z','0,x,z','0,-x,z'],['x,x,z','-x,-x,z','-x,x,z','x,-x,z'],['1/2,0,z','0,1/2,z'],['1/2,1/2,z'],['0,0,z']]" +56,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z','-y+1/2,-x+1/2,z','y+1/2,x+1/2,z'],['x,x+1/2,z','-x,-x+1/2,z','-x+1/2,x,z','x+1/2,-x,z'],['1/2,0,z','0,1/2,z'],['0,0,z','1/2,1/2,z']]" +57,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z','-x,y,-z','x,-y,-z','-y,-x,z','y,x,z'],['x,x,z','-x,-x,z','x,-x,-z','-x,x,-z'],['0,1/2,z','1/2,0,-z','0,1/2,-z','1/2,0,z'],['x,1/2,0','-x,1/2,0','1/2,-x,0','1/2,x,0'],['x,0,0','-x,0,0','0,-x,0','0,x,0'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['1/2,0,0','0,1/2,0'],['1/2,1/2,0'],['0,0,0']]" +58,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','-y+1/2,-x+1/2,z','y+1/2,x+1/2,z'],['x,x+1/2,z','-x,-x+1/2,z','x+1/2,-x,-z','-x+1/2,x,-z'],['0,0,z','0,0,-z','1/2,1/2,-z','1/2,1/2,z'],['0,1/2,z','1/2,0,-z'],['0,0,0','1/2,1/2,0']]" +59,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z','x,-y,z','-x,y,z','y,x,-z','-y,-x,-z'],['x,1/2,z','-x,1/2,z','1/2,-x,-z','1/2,x,-z'],['x,0,z','-x,0,z','0,-x,-z','0,x,-z'],['x,x,0','-x,-x,0','x,-x,0','-x,x,0'],['0,1/2,z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['1/2,1/2,0'],['0,0,0']]" +60,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z','y+1/2,x+1/2,-z','-y+1/2,-x+1/2,-z'],['x,x+1/2,0','-x,-x+1/2,0','x+1/2,-x,0','-x+1/2,x,0'],['0,1/2,z','1/2,0,-z','1/2,0,z','0,1/2,-z'],['0,0,z','0,0,-z','1/2,1/2,z','1/2,1/2,-z'],['0,1/2,0','1/2,0,0'],['0,0,0','1/2,1/2,0']]" +61,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x,y,-z','x,-y,-z','y,x,-z','-y,-x,-z','-x,-y,-z','x,y,-z','y,-x,-z','-y,x,-z','x,-y,z','-x,y,z','-y,-x,z','y,x,z'],['x,1/2,z','-x,1/2,z','1/2,x,z','1/2,-x,z','-x,1/2,-z','x,1/2,-z','1/2,x,-z','1/2,-x,-z'],['x,0,z','-x,0,z','0,x,z','0,-x,z','-x,0,-z','x,0,-z','0,x,-z','0,-x,-z'],['x,x,z','-x,-x,z','-x,x,z','x,-x,z','-x,x,-z','x,-x,-z','x,x,-z','-x,-x,-z'],['x,y,0','-x,-y,0','-y,x,0','y,-x,0','-x,y,0','x,-y,0','y,x,0','-y,-x,0'],['x,1/2,0','-x,1/2,0','1/2,x,0','1/2,-x,0'],['x,0,0','-x,0,0','0,x,0','0,-x,0'],['x,x,0','-x,-x,0','-x,x,0','x,-x,0'],['0,1/2,z','1/2,0,z','0,1/2,-z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['0,1/2,0','1/2,0,0'],['1/2,1/2,0'],['0,0,0']]" +62,"[['x,y,z','-x+1/2,-y+1/2,z','-y+1/2,x,z','y,-x+1/2,z','-x+1/2,y,-z','x,-y+1/2,-z','y,x,-z','-y+1/2,-x+1/2,-z','-x,-y,-z','x+1/2,y+1/2,-z','y+1/2,-x,-z','-y,x+1/2,-z','x+1/2,-y,z','-x,y+1/2,z','-y,-x,z','y+1/2,x+1/2,z'],['x,-x,z','-x+1/2,x+1/2,z','x+1/2,x,z','-x,-x+1/2,z','-x+1/2,-x,-z','x,x+1/2,-z','-x,x,-z','x+1/2,-x+1/2,-z'],['x,1/4,0','-x+1/2,1/4,0','1/4,x,0','1/4,-x+1/2,0','-x,3/4,0','x+1/2,3/4,0','3/4,-x,0','3/4,x+1/2,0'],['x,x,0','-x+1/2,-x+1/2,0','-x+1/2,x,0','x,-x+1/2,0','-x,-x,0','x+1/2,x+1/2,0','x+1/2,-x,0','-x,x+1/2,0'],['3/4,1/4,z','1/4,3/4,z','3/4,1/4,-z','1/4,3/4,-z'],['1/4,1/4,z','1/4,1/4,-z','3/4,3/4,-z','3/4,3/4,z'],['0,0,0','1/2,1/2,0','1/2,0,0','0,1/2,0'],['3/4,1/4,0','1/4,3/4,0'],['1/4,1/4,0','3/4,3/4,0']]" +63,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','y+1/2,x+1/2,-z','-y+1/2,-x+1/2,-z','-x,-y,-z','x,y,-z','y,-x,-z','-y,x,-z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z','-y+1/2,-x+1/2,z','y+1/2,x+1/2,z'],['x,x+1/2,z','-x,-x+1/2,z','-x+1/2,x,z','x+1/2,-x,z','-x+1/2,x,-z','x+1/2,-x,-z','x,x+1/2,-z','-x,-x+1/2,-z'],['x,y,0','-x,-y,0','-y,x,0','y,-x,0','-x+1/2,y+1/2,0','x+1/2,-y+1/2,0','y+1/2,x+1/2,0','-y+1/2,-x+1/2,0'],['x,x+1/2,0','-x,-x+1/2,0','-x+1/2,x,0','x+1/2,-x,0'],['0,1/2,z','1/2,0,z','1/2,0,-z','0,1/2,-z'],['0,0,z','1/2,1/2,-z','0,0,-z','1/2,1/2,z'],['0,1/2,0','1/2,0,0'],['0,0,0','1/2,1/2,0']]" +64,"[['x,y,z','-x+1/2,-y+1/2,z','-y+1/2,x,z','y,-x+1/2,z','-x,y+1/2,-z','x+1/2,-y,-z','y+1/2,x+1/2,-z','-y,-x,-z','-x,-y,-z','x+1/2,y+1/2,-z','y+1/2,-x,-z','-y,x+1/2,-z','x,-y+1/2,z','-x+1/2,y,z','-y+1/2,-x+1/2,z','y,x,z'],['x,x,z','-x+1/2,-x+1/2,z','-x+1/2,x,z','x,-x+1/2,z','-x,x+1/2,-z','x+1/2,-x,-z','x+1/2,x+1/2,-z','-x,-x,-z'],['1/4,y,z','1/4,-y+1/2,z','-y+1/2,1/4,z','y,1/4,z','3/4,y+1/2,-z','3/4,-y,-z','y+1/2,3/4,-z','-y,3/4,-z'],['x,-x,0','-x+1/2,x+1/2,0','x+1/2,x,0','-x,-x+1/2,0','-x,x,0','x+1/2,-x+1/2,0','-x+1/2,-x,0','x,x+1/2,0'],['3/4,1/4,z','1/4,3/4,z','1/4,3/4,-z','3/4,1/4,-z'],['0,0,0','1/2,1/2,0','1/2,0,0','0,1/2,0'],['1/4,1/4,z','3/4,3/4,-z'],['3/4,1/4,0','1/4,3/4,0']]" +65,"[['x,y,z','-y,x-y,z','-x+y,-x,z'],['2/3,1/3,z'],['1/3,2/3,z'],['0,0,z']]" +66,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,-z','y,-x+y,-z','x-y,x,-z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['1/3,2/3,z','2/3,1/3,-z'],['0,0,z','0,0,-z'],['0,0,0']]" +67,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-y,-x,-z','-x+y,y,-z','x,x-y,-z'],['x,-x,0','x,2x,0','-2x,-x,0'],['2/3,1/3,z','2/3,1/3,-z'],['1/3,2/3,z','1/3,2/3,-z'],['0,0,z','0,0,-z'],['2/3,1/3,0'],['1/3,2/3,0'],['0,0,0']]" +68,"[['x,y,z','-y,x-y,z','-x+y,-x,z','y,x,-z','x-y,-y,-z','-x,-x+y,-z'],['x,0,0','0,x,0','-x,-x,0'],['1/3,2/3,z','2/3,1/3,-z'],['0,0,z','0,0,-z'],['0,0,0']]" +69,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-y,-x,z','-x+y,y,z','x,x-y,z'],['x,-x,z','x,2x,z','-2x,-x,z'],['2/3,1/3,z'],['1/3,2/3,z'],['0,0,z']]" +70,"[['x,y,z','-y,x-y,z','-x+y,-x,z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,0,z','0,x,z','-x,-x,z'],['1/3,2/3,z','2/3,1/3,z'],['0,0,z']]" +71,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-y,-x,-z','-x+y,y,-z','x,x-y,-z','-x,-y,-z','y,-x+y,-z','x-y,x,-z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,0,z','0,x,z','-x,-x,z','0,-x,-z','-x,0,-z','x,x,-z'],['x,-x,0','x,2x,0','-2x,-x,0','-x,x,0','-x,-2x,0','2x,x,0'],['1/3,2/3,z','1/3,2/3,-z','2/3,1/3,-z','2/3,1/3,z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" +72,"[['x,y,z','-y,x-y,z','-x+y,-x,z','y,x,-z','x-y,-y,-z','-x,-x+y,-z','-x,-y,-z','y,-x+y,-z','x-y,x,-z','-y,-x,z','-x+y,y,z','x,x-y,z'],['x,-x,z','x,2x,z','-2x,-x,z','-x,x,-z','2x,x,-z','-x,-2x,-z'],['x,0,0','0,x,0','-x,-x,0','-x,0,0','0,-x,0','x,x,0'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['1/3,2/3,z','2/3,1/3,-z'],['0,0,z','0,0,-z'],['0,0,0']]" +73,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z'],['1/2,0,z','0,1/2,z','1/2,1/2,z'],['1/3,2/3,z','2/3,1/3,z'],['0,0,z']]" +74,"[['x,y,z','-y,x-y,z','-x+y,-x,z','x,y,-z','-y,x-y,-z','-x+y,-x,-z'],['x,y,0','-y,x-y,0','-x+y,-x,0'],['2/3,1/3,z','2/3,1/3,-z'],['1/3,2/3,z','1/3,2/3,-z'],['0,0,z','0,0,-z'],['2/3,1/3,0'],['1/3,2/3,0'],['0,0,0']]" +75,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z','-x,-y,-z','y,-x+y,-z','x-y,x,-z','x,y,-z','-y,x-y,-z','-x+y,-x,-z'],['x,y,0','-y,x-y,0','-x+y,-x,0','-x,-y,0','y,-x+y,0','x-y,x,0'],['1/2,0,z','0,1/2,z','1/2,1/2,z','1/2,0,-z','0,1/2,-z','1/2,1/2,-z'],['1/3,2/3,z','2/3,1/3,z','1/3,2/3,-z','2/3,1/3,-z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" +76,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z','y,x,-z','x-y,-y,-z','-x,-x+y,-z','-y,-x,-z','-x+y,y,-z','x,x-y,-z'],['x,-x,0','x,2x,0','-2x,-x,0','-x,x,0','-x,-2x,0','2x,x,0'],['x,0,0','0,x,0','-x,-x,0','-x,0,0','0,-x,0','x,x,0'],['1/2,0,z','0,1/2,z','1/2,1/2,z','0,1/2,-z','1/2,0,-z','1/2,1/2,-z'],['1/3,2/3,z','2/3,1/3,z','2/3,1/3,-z','1/3,2/3,-z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" +77,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z','-y,-x,z','-x+y,y,z','x,x-y,z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,-x,z','x,2x,z','-2x,-x,z','-x,x,z','-x,-2x,z','2x,x,z'],['x,0,z','0,x,z','-x,-x,z','-x,0,z','0,-x,z','x,x,z'],['1/2,0,z','0,1/2,z','1/2,1/2,z'],['1/3,2/3,z','2/3,1/3,z'],['0,0,z']]" +78,"[['x,y,z','-y,x-y,z','-x+y,-x,z','x,y,-z','-y,x-y,-z','-x+y,-x,-z','-y,-x,z','-x+y,y,z','x,x-y,z','-y,-x,-z','-x+y,y,-z','x,x-y,-z'],['x,-x,z','x,2x,z','-2x,-x,z','x,-x,-z','x,2x,-z','-2x,-x,-z'],['x,y,0','-y,x-y,0','-x+y,-x,0','-y,-x,0','-x+y,y,0','x,x-y,0'],['x,-x,0','x,2x,0','-2x,-x,0'],['2/3,1/3,z','2/3,1/3,-z'],['1/3,2/3,z','1/3,2/3,-z'],['0,0,z','0,0,-z'],['2/3,1/3,0'],['1/3,2/3,0'],['0,0,0']]" +79,"[['x,y,z','-y,x-y,z','-x+y,-x,z','x,y,-z','-y,x-y,-z','-x+y,-x,-z','y,x,-z','x-y,-y,-z','-x,-x+y,-z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,y,0','-y,x-y,0','-x+y,-x,0','y,x,0','x-y,-y,0','-x,-x+y,0'],['x,0,z','0,x,z','-x,-x,z','x,0,-z','0,x,-z','-x,-x,-z'],['1/3,2/3,z','1/3,2/3,-z','2/3,1/3,-z','2/3,1/3,z'],['x,0,0','0,x,0','-x,-x,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" +80,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z','y,x,-z','x-y,-y,-z','-x,-x+y,-z','-y,-x,-z','-x+y,y,-z','x,x-y,-z','-x,-y,-z','y,-x+y,-z','x-y,x,-z','x,y,-z','-y,x-y,-z','-x+y,-x,-z','-y,-x,z','-x+y,y,z','x,x-y,z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,y,0','-y,x-y,0','-x+y,-x,0','-x,-y,0','y,-x+y,0','x-y,x,0','y,x,0','x-y,-y,0','-x,-x+y,0','-y,-x,0','-x+y,y,0','x,x-y,0'],['x,2x,z','-2x,-x,z','x,-x,z','-x,-2x,z','2x,x,z','-x,x,z','2x,x,-z','-x,-2x,-z','-x,x,-z','-2x,-x,-z','x,2x,-z','x,-x,-z'],['x,0,z','0,x,z','-x,-x,z','-x,0,z','0,-x,z','x,x,z','0,x,-z','x,0,-z','-x,-x,-z','0,-x,-z','-x,0,-z','x,x,-z'],['x,2x,0','-2x,-x,0','x,-x,0','-x,-2x,0','2x,x,0','-x,x,0'],['x,0,0','0,x,0','-x,-x,0','-x,0,0','0,-x,0','x,x,0'],['1/2,0,z','0,1/2,z','1/2,1/2,z','0,1/2,-z','1/2,0,-z','1/2,1/2,-z'],['1/3,2/3,z','2/3,1/3,z','2/3,1/3,-z','1/3,2/3,-z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" diff --git a/crystalformer/data/layer_list.csv b/crystalformer/data/layer_list.csv new file mode 100644 index 0000000..ff64aa9 --- /dev/null +++ b/crystalformer/data/layer_list.csv @@ -0,0 +1,81 @@ +Layer Group,Wyckoff Positions +1,"[['x,y,z']]" +2,"[['x,y,z','-x,-y,-z'],['1/2,1/2,0'],['1/2,0,0'],['0,1/2,0'],['0,0,0']]" +3,"[['x,y,z','-x,-y,z'],['1/2,1/2,z'],['1/2,0,z'],['0,1/2,z'],['0,0,z']]" +4,"[['x,y,z','x,y,-z'],['x,y,0']]" +5,"[['x,y,z','x+1/2,y,-z']]" +6,"[['x,y,z','-x,-y,z','-x,-y,-z','x,y,-z'],['x,y,0','-x,-y,0'],['1/2,1/2,z','1/2,1/2,-z'],['1/2,0,z','1/2,0,-z'],['0,1/2,z','0,1/2,-z'],['0,0,z','0,0,-z'],['1/2,1/2,0'],['0,1/2,0'],['1/2,0,0'],['0,0,0']]" +7,"[['x,y,z','-x+1/2,-y,z','-x,-y,-z','x+1/2,y,-z'],['1/4,1/2,z','3/4,1/2,-z'],['1/4,0,z','3/4,0,-z'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +8,"[['x,y,z','x,-y,-z'],['x,1/2,0'],['x,0,0']]" +9,"[['x,y,z','x+1/2,-y,-z']]" +10,"[['x,y,z','x,-y,-z','x+1/2,y+1/2,z','x+1/2,-y+1/2,-z'],['x,0,0','x+1/2,1/2,0']]" +11,"[['x,y,z','-x,y,z'],['1/2,y,z'],['0,y,z']]" +12,"[['x,y,z','-x,y+1/2,z']]" +13,"[['x,y,z','-x,y,z','x+1/2,y+1/2,z','-x+1/2,y+1/2,z'],['0,y,z','1/2,y+1/2,z']]" +14,"[['x,y,z','x,-y,-z','-x,-y,-z','-x,y,z'],['1/2,y,z','1/2,-y,-z'],['0,y,z','0,-y,-z'],['x,1/2,0','-x,1/2,0'],['x,0,0','-x,0,0'],['1/2,1/2,0'],['0,1/2,0'],['1/2,0,0'],['0,0,0']]" +15,"[['x,y,z','x+1/2,-y,-z','-x,-y,-z','-x+1/2,y,z'],['1/4,y,z','3/4,-y,-z'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +16,"[['x,y,z','x,-y+1/2,-z','-x,-y,-z','-x,y+1/2,z'],['x,1/4,0','-x,3/4,0'],['1/2,0,0','1/2,1/2,0'],['0,0,0','0,1/2,0']]" +17,"[['x,y,z','x+1/2,-y+1/2,-z','-x,-y,-z','-x+1/2,y+1/2,z'],['0,1/2,0','1/2,0,0'],['0,0,0','1/2,1/2,0']]" +18,"[['x,y,z','x,-y,-z','-x,-y,-z','-x,y,z','x+1/2,y+1/2,z','x+1/2,-y+1/2,-z','-x+1/2,-y+1/2,-z','-x+1/2,y+1/2,z'],['0,y,z','0,-y,-z','1/2,y+1/2,z','1/2,-y+1/2,-z'],['x,0,0','-x,0,0','x+1/2,1/2,0','-x+1/2,1/2,0'],['1/4,1/4,0','1/4,3/4,0','3/4,3/4,0','3/4,5/4,0'],['1/2,0,0','1,1/2,0'],['0,0,0','1/2,1/2,0']]" +19,"[['x,y,z','-x,-y,z','-x,y,-z','x,-y,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,1/2,z','0,1/2,-z'],['1/2,0,z','1/2,0,-z'],['0,0,z','0,0,-z'],['1/2,y,0','1/2,-y,0'],['0,y,0','0,-y,0'],['x,1/2,0','-x,1/2,0'],['x,0,0','-x,0,0'],['1/2,1/2,0'],['0,1/2,0'],['1/2,0,0'],['0,0,0']]" +20,"[['x,y,z','x+1/2,-y,-z','-x+1/2,y,-z','-x,-y,z'],['1/4,y,0','3/4,-y,0'],['0,1/2,z','1/2,1/2,-z'],['0,0,z','1/2,0,-z']]" +21,"[['x,y,z','-x,-y,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z'],['0,1/2,z','1/2,0,-z'],['0,0,z','1/2,1/2,-z']]" +22,"[['x,y,z','-x,-y,z','-x,y,-z','x,-y,-z','x+1/2,y+1/2,z','-x+1/2,-y+1/2,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z'],['1/4,1/4,z','3/4,1/4,-z','3/4,3/4,z','5/4,3/4,-z'],['0,1/2,z','0,1/2,-z','1/2,1,z','1/2,1,-z'],['0,0,z','0,0,-z','1/2,1/2,z','1/2,1/2,-z'],['0,y,0','0,-y,0','1/2,y+1/2,0','1/2,-y+1/2,0'],['x,0,0','-x,0,0','x+1/2,1/2,0','-x+1/2,1/2,0'],['0,1/2,0','1/2,1,0'],['0,0,0','1/2,1/2,0']]" +23,"[['x,y,z','-x,-y,z','x,-y,z','-x,y,z'],['1/2,y,z','1/2,-y,z'],['0,y,z','0,-y,z'],['x,1/2,z','-x,1/2,z'],['x,0,z','-x,0,z'],['1/2,1/2,z'],['1/2,0,z'],['0,1/2,z'],['0,0,z']]" +24,"[['x,y,z','-x,-y,z','x+1/2,-y,z','-x+1/2,y,z'],['1/4,y,z','3/4,-y,z'],['0,1/2,z','1/2,1/2,z'],['0,0,z','1/2,0,z']]" +25,"[['x,y,z','-x,-y,z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z'],['0,1/2,z','1/2,0,z'],['0,0,z','1/2,1/2,z']]" +26,"[['x,y,z','-x,-y,z','x,-y,z','-x,y,z','x+1/2,y+1/2,z','-x+1/2,-y+1/2,z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z'],['0,y,z','0,-y,z','1/2,y+1/2,z','1/2,-y+1/2,z'],['x,0,z','-x,0,z','x+1/2,1/2,z','-x+1/2,1/2,z'],['1/4,1/4,z','1/4,3/4,z','3/4,3/4,z','3/4,5/4,z'],['0,1/2,z','1/2,1,z'],['0,0,z','1/2,1/2,z']]" +27,"[['x,y,z','-x,y,-z','-x,y,z','x,y,-z'],['x,y,0','-x,y,0'],['1/2,y,z','1/2,y,-z'],['0,y,z','0,y,-z'],['1/2,y,0'],['0,y,0']]" +28,"[['x,y,z','-x,y+1/2,-z','x,y+1/2,-z','-x,y,z'],['1/2,y,z','1/2,y+1/2,-z'],['0,y,z','0,y+1/2,-z']]" +29,"[['x,y,z','-x,y+1/2,-z','-x,y+1/2,z','x,y,-z'],['x,y,0','-x,y+1/2,0']]" +30,"[['x,y,z','-x,y,-z','x,y+1/2,-z','-x,y+1/2,z'],['1/2,y,0','1/2,y+1/2,0'],['0,y,0','0,y+1/2,0']]" +31,"[['x,y,z','-x,y,-z','x+1/2,y,-z','-x+1/2,y,z'],['1/4,y,z','3/4,y,-z'],['0,y,0','1/2,y,0']]" +32,"[['x,y,z','-x+1/2,y+1/2,-z','x+1/2,y+1/2,-z','-x,y,z'],['0,y,z','1/2,y+1/2,-z']]" +33,"[['x,y,z','-x,y+1/2,-z','x+1/2,y,-z','-x+1/2,y+1/2,z']]" +34,"[['x,y,z','-x,y,-z','-x+1/2,y+1/2,z','x+1/2,y+1/2,-z'],['0,y,0','1/2,y+1/2,0']]" +35,"[['x,y,z','-x,y,-z','-x,y,z','x,y,-z','x+1/2,y+1/2,z','-x+1/2,y+1/2,-z','-x+1/2,y+1/2,z','x+1/2,y+1/2,-z'],['x,y,0','-x,y,0','x+1/2,y+1/2,0','-x+1/2,y+1/2,0'],['0,y,z','0,y,-z','1/2,y+1/2,z','1/2,y+1/2,-z'],['0,y,0','1/2,y+1/2,0']]" +36,"[['x,y,z','-x,y,-z','-x+1/2,y,z','x+1/2,y,-z','x+1/2,y+1/2,z','-x+1/2,y+1/2,-z','-x+1,y+1/2,z','x+1,y+1/2,-z'],['1/4,y,z','3/4,y,-z','3/4,y+1/2,z','5/4,y+1/2,-z'],['0,y,0','1/2,y,0','1/2,y+1/2,0','1,y+1/2,0']]" +37,"[['x,y,z','-x,-y,z','-x,y,-z','x,-y,-z','-x,-y,-z','x,y,-z','x,-y,z','-x,y,z'],['x,y,0','-x,-y,0','-x,y,0','x,-y,0'],['x,1/2,z','-x,1/2,z','-x,1/2,-z','x,1/2,-z'],['x,0,z','-x,0,z','-x,0,-z','x,0,-z'],['1/2,y,z','1/2,-y,z','1/2,y,-z','1/2,-y,-z'],['0,y,z','0,-y,z','0,y,-z','0,-y,-z'],['1/2,1/2,z','1/2,1/2,-z'],['1/2,0,z','1/2,0,-z'],['0,1/2,z','0,1/2,-z'],['0,0,z','0,0,-z'],['1/2,y,0','1/2,-y,0'],['0,y,0','0,-y,0'],['x,1/2,0','-x,1/2,0'],['x,0,0','-x,0,0'],['1/2,1/2,0'],['0,1/2,0'],['1/2,0,0'],['0,0,0']]" +38,"[['x,y,z','x,-y,-z','-x+1/2,-y,z','-x+1/2,y,-z','-x,-y,-z','-x,y,z','x+1/2,y,-z','x+1/2,-y,z'],['0,y,z','0,-y,-z','1/2,-y,z','1/2,y,-z'],['x,1/2,0','-x+1/2,1/2,0','-x,1/2,0','x+1/2,1/2,0'],['x,0,0','-x+1/2,0,0','-x,0,0','x+1/2,0,0'],['1/4,1/2,z','1/4,1/2,-z','3/4,1/2,-z','3/4,1/2,z'],['1/4,0,z','1/4,0,-z','3/4,0,-z','3/4,0,z'],['1/4,y,0','1/4,-y,0','3/4,-y,0','3/4,y,0'],['1/4,1/2,0','3/4,1/2,0'],['1/4,0,0','3/4,0,0'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +39,"[['x,y,z','-x+1/2,-y+1/2,z','-x+1/2,y,-z','x,-y+1/2,-z','-x,-y,-z','x+1/2,y+1/2,-z','x+1/2,-y,z','-x,y+1/2,z'],['1/4,3/4,z','1/4,3/4,-z','3/4,1/4,-z','3/4,1/4,z'],['1/4,1/4,z','1/4,1/4,-z','3/4,3/4,-z','3/4,3/4,z'],['1/4,y,0','1/4,-y+1/2,0','3/4,-y,0','3/4,y+1/2,0'],['x,1/4,0','-x+1/2,1/4,0','-x,3/4,0','x+1/2,3/4,0'],['0,0,0','1/2,1/2,0','1/2,0,0','0,1/2,0'],['3/4,1/4,0','1/4,3/4,0'],['1/4,1/4,0','3/4,3/4,0']]" +40,"[['x,y,z','-x+1/2,y,-z','-x,-y,z','x+1/2,-y,-z','-x,-y,-z','x+1/2,-y,z','x,y,-z','-x+1/2,y,z'],['1/4,y,z','1/4,y,-z','3/4,-y,z','3/4,-y,-z'],['x,y,0','-x+1/2,y,0','-x,-y,0','x+1/2,-y,0'],['0,1/2,z','1/2,1/2,-z','0,1/2,-z','1/2,1/2,z'],['0,0,z','1/2,0,-z','0,0,-z','1/2,0,z'],['1/4,y,0','3/4,-y,0'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +41,"[['x,y,z','-x+1/2,-y,z','-x,y,-z','x+1/2,-y,-z','-x,-y,-z','x+1/2,y,-z','x,-y,z','-x+1/2,y,z'],['1/4,y,z','1/4,-y,z','3/4,y,-z','3/4,-y,-z'],['x,1/2,z','-x+1/2,1/2,z','-x,1/2,-z','x+1/2,1/2,-z'],['x,0,z','-x+1/2,0,z','-x,0,-z','x+1/2,0,-z'],['0,y,0','1/2,-y,0','0,-y,0','1/2,y,0'],['1/4,1/2,z','3/4,1/2,-z'],['1/4,0,z','3/4,0,-z'],['0,1/2,0','1/2,1/2,0'],['0,0,0','1/2,0,0']]" +42,"[['x,y,z','-x+1/2,y+1/2,-z','-x+1/2,-y+1/2,z','x,-y,-z','-x,-y,-z','x+1/2,-y+1/2,z','x+1/2,y+1/2,-z','-x,y,z'],['0,y,z','1/2,y+1/2,-z','1/2,-y+1/2,z','0,-y,-z'],['1/4,1/4,z','1/4,3/4,-z','3/4,3/4,-z','3/4,1/4,z'],['x,0,0','-x+1/2,1/2,0','-x,0,0','x+1/2,1/2,0'],['1/2,0,0','0,1/2,0'],['0,0,0','1/2,1/2,0']]" +43,"[['x,y,z','x,-y+1/2,-z','-x+1/2,-y,z','-x+1/2,y+1/2,-z','-x,-y,-z','-x,y+1/2,z','x+1/2,y,-z','x+1/2,-y+1/2,z'],['x,1/4,0','-x+1/2,3/4,0','-x,3/4,0','x+1/2,1/4,0'],['1/4,0,z','1/4,1/2,-z','3/4,0,-z','3/4,1/2,z'],['0,0,0','0,1/2,0','1/2,0,0','1/2,1/2,0']]" +44,"[['x,y,z','-x,-y,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','-x,-y,-z','x,y,-z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z'],['x,y,0','-x,-y,0','-x+1/2,y+1/2,0','x+1/2,-y+1/2,0'],['0,1/2,z','1/2,0,-z','0,1/2,-z','1/2,0,z'],['0,0,z','1/2,1/2,-z','0,0,-z','1/2,1/2,z'],['0,1/2,0','1/2,0,0'],['0,0,0','1/2,1/2,0']]" +45,"[['x,y,z','-x,y+1/2,-z','x+1/2,-y+1/2,-z','-x+1/2,-y,z','-x,-y,-z','x,-y+1/2,z','-x+1/2,y+1/2,z','x+1/2,y,-z'],['x,1/4,z','-x,3/4,-z','x+1/2,1/4,-z','-x+1/2,3/4,z'],['1/4,0,z','3/4,1/2,-z','3/4,0,-z','1/4,1/2,z'],['0,0,0','0,1/2,0','1/2,1/2,0','1/2,0,0']]" +46,"[['x,y,z','-x+1/2,-y+1/2,z','-x,y+1/2,-z','x+1/2,-y,-z','-x,-y,-z','x+1/2,y+1/2,-z','x,-y+1/2,z','-x+1/2,y,z'],['x,1/4,z','-x+1/2,1/4,z','-x,3/4,-z','x+1/2,3/4,-z'],['1/4,y,z','1/4,-y+1/2,z','3/4,y+1/2,-z','3/4,-y,-z'],['0,0,0','1/2,1/2,0','0,1/2,0','1/2,0,0'],['1/4,3/4,z','3/4,1/4,-z'],['1/4,1/4,z','3/4,3/4,-z']]" +47,"[['x,y,z','-x,-y,z','-x,y,-z','x,-y,-z','-x,-y,-z','x,y,-z','x,-y,z','-x,y,z','x+1/2,y+1/2,z','-x+1/2,-y+1/2,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','-x+1/2,-y+1/2,-z','x+1/2,y+1/2,-z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z'],['x,y,0','-x,-y,0','-x,y,0','x,-y,0','x+1/2,y+1/2,0','-x+1/2,-y+1/2,0','-x+1/2,y+1/2,0','x+1/2,-y+1/2,0'],['x,0,z','-x,0,z','-x,0,-z','x,0,-z','x+1/2,1/2,z','-x+1/2,1/2,z','-x+1/2,1/2,-z','x+1/2,1/2,-z'],['0,y,z','0,-y,z','0,y,-z','0,-y,-z','1/2,y+1/2,z','1/2,-y+1/2,z','1/2,y+1/2,-z','1/2,-y+1/2,-z'],['1/4,1/4,z','3/4,1/4,-z','3/4,3/4,-z','1/4,3/4,z','3/4,3/4,z','5/4,3/4,-z','5/4,5/4,-z','3/4,5/4,z'],['0,1/2,z','0,1/2,-z','1/2,1,z','1/2,1,-z'],['0,0,z','0,0,-z','1/2,1/2,z','1/2,1/2,-z'],['0,y,0','0,-y,0','1/2,y+1/2,0','1/2,-y+1/2,0'],['x,0,0','-x,0,0','x+1/2,1/2,0','-x+1/2,1/2,0'],['1/4,1/4,0','3/4,1/4,0','3/4,3/4,0','5/4,3/4,0'],['1/2,0,0','1,1/2,0'],['0,0,0','1/2,1/2,0']]" +48,"[['x,y,z','-x,-y+1/2,z','-x,y+1/2,-z','x,-y,-z','-x,-y,-z','x,y+1/2,-z','x,-y+1/2,z','-x,y,z','x+1/2,y+1/2,z','-x+1/2,-y+1,z','-x+1/2,y+1,-z','x+1/2,-y+1/2,-z','-x+1/2,-y+1/2,-z','x+1/2,y+1,-z','x+1/2,-y+1,z','-x+1/2,y+1/2,z'],['x,1/4,z','-x,1/4,z','-x,3/4,-z','x,3/4,-z','x+1/2,3/4,z','-x+1/2,3/4,z','-x+1/2,5/4,-z','x+1/2,5/4,-z'],['0,y,z','0,-y+1/2,z','0,y+1/2,-z','0,-y,-z','1/2,y+1/2,z','1/2,-y+1,z','1/2,y+1,-z','1/2,-y+1/2,-z'],['1/4,0,z','3/4,1/2,-z','3/4,0,-z','1/4,1/2,z','3/4,1/2,z','5/4,1,-z','5/4,1/2,-z','3/4,1,z'],['1/4,y,0','3/4,-y+1/2,0','3/4,-y,0','1/4,y+1/2,0','3/4,y+1/2,0','5/4,-y+1,0','5/4,-y+1/2,0','3/4,y+1,0'],['x,0,0','-x,1/2,0','-x,0,0','x,1/2,0','x+1/2,1/2,0','-x+1/2,1,0','-x+1/2,1/2,0','x+1/2,1,0'],['0,1/4,z','0,3/4,-z','1/2,3/4,z','1/2,5/4,-z'],['1/4,1/4,0','3/4,1/4,0','3/4,3/4,0','5/4,3/4,0'],['0,0,0','0,1/2,0','1/2,1/2,0','1/2,1,0'],['1/4,0,0','3/4,0,0','3/4,1/2,0','5/4,1/2,0']]" +49,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z'],['0,1/2,z','1/2,0,z'],['1/2,1/2,z'],['0,0,z']]" +50,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z'],['0,1/2,z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['1/2,1/2,0'],['0,0,0']]" +51,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x,-y,-z','x,y,-z','y,-x,-z','-y,x,-z'],['x,y,0','-x,-y,0','-y,x,0','y,-x,0'],['0,1/2,z','1/2,0,z','0,1/2,-z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['0,1/2,0','1/2,0,0'],['1/2,1/2,0'],['0,0,0']]" +52,"[['x,y,z','-x+1/2,-y+1/2,z','-y+1/2,x,z','y,-x+1/2,z','-x,-y,-z','x+1/2,y+1/2,-z','y+1/2,-x,-z','-y,x+1/2,-z'],['1/4,3/4,z','3/4,1/4,z','3/4,1/4,-z','1/4,3/4,-z'],['0,0,0','1/2,1/2,0','1/2,0,0','0,0,0'],['1/4,1/4,z','3/4,3/4,-z'],['1/4,3/4,0','3/4,1/4,0']]" +53,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x,y,-z','x,-y,-z','y,x,-z','-y,-x,-z'],['x,1/2,0','-x,1/2,0','1/2,x,0','1/2,-x,0'],['x,0,0','-x,0,0','0,x,0','0,-x,0'],['x,x,0','-x,-x,0','-x,x,0','x,-x,0'],['0,1/2,z','1/2,0,z','0,1/2,-z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['1/2,0,0','0,1/2,0'],['1/2,1/2,0'],['0,0,0']]" +54,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','y+1/2,x+1/2,-z','-y+1/2,-x+1/2,-z'],['x,x+1/2,0','-x,-x+1/2,0','-x+1/2,x,0','x+1/2,-x,0'],['0,1/2,z','1/2,0,z','1/2,0,-z','0,1/2,-z'],['0,0,z','1/2,1/2,-z'],['0,1/2,0','1/2,0,0']]" +55,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','x,-y,z','-x,y,z','-y,-x,z','y,x,z'],['x,1/2,z','-x,1/2,z','1/2,x,z','1/2,-x,z'],['x,0,z','-x,0,z','0,x,z','0,-x,z'],['x,x,z','-x,-x,z','-x,x,z','x,-x,z'],['1/2,0,z','0,1/2,z'],['1/2,1/2,z'],['0,0,z']]" +56,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z','-y+1/2,-x+1/2,z','y+1/2,x+1/2,z'],['x,x+1/2,z','-x,-x+1/2,z','-x+1/2,x,z','x+1/2,-x,z'],['1/2,0,z','0,1/2,z'],['0,0,z','1/2,1/2,z']]" +57,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z','-x,y,-z','x,-y,-z','-y,-x,z','y,x,z'],['x,x,z','-x,-x,z','x,-x,-z','-x,x,-z'],['0,1/2,z','1/2,0,-z','0,1/2,-z','1/2,0,z'],['x,1/2,0','-x,1/2,0','1/2,-x,0','1/2,x,0'],['x,0,0','-x,0,0','0,-x,0','0,x,0'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['1/2,0,0','0,1/2,0'],['1/2,1/2,0'],['0,0,0']]" +58,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','-y+1/2,-x+1/2,z','y+1/2,x+1/2,z'],['x,x+1/2,z','-x,-x+1/2,z','x+1/2,-x,-z','-x+1/2,x,-z'],['0,0,z','0,0,-z','1/2,1/2,-z','1/2,1/2,z'],['0,1/2,z','1/2,0,-z'],['0,0,0','1/2,1/2,0']]" +59,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z','x,-y,z','-x,y,z','y,x,-z','-y,-x,-z'],['x,1/2,z','-x,1/2,z','1/2,-x,-z','1/2,x,-z'],['x,0,z','-x,0,z','0,-x,-z','0,x,-z'],['x,x,0','-x,-x,0','x,-x,0','-x,x,0'],['0,1/2,z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['1/2,1/2,0'],['0,0,0']]" +60,"[['x,y,z','-x,-y,z','y,-x,-z','-y,x,-z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z','y+1/2,x+1/2,-z','-y+1/2,-x+1/2,-z'],['x,x+1/2,0','-x,-x+1/2,0','x+1/2,-x,0','-x+1/2,x,0'],['0,1/2,z','1/2,0,-z','1/2,0,z','0,1/2,-z'],['0,0,z','0,0,-z','1/2,1/2,z','1/2,1/2,-z'],['0,1/2,0','1/2,0,0'],['0,0,0','1/2,1/2,0']]" +61,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x,y,-z','x,-y,-z','y,x,-z','-y,-x,-z','-x,-y,-z','x,y,-z','y,-x,-z','-y,x,-z','x,-y,z','-x,y,z','-y,-x,z','y,x,z'],['x,1/2,z','-x,1/2,z','1/2,x,z','1/2,-x,z','-x,1/2,-z','x,1/2,-z','1/2,x,-z','1/2,-x,-z'],['x,0,z','-x,0,z','0,x,z','0,-x,z','-x,0,-z','x,0,-z','0,x,-z','0,-x,-z'],['x,x,z','-x,-x,z','-x,x,z','x,-x,z','-x,x,-z','x,-x,-z','x,x,-z','-x,-x,-z'],['x,y,0','-x,-y,0','-y,x,0','y,-x,0','-x,y,0','x,-y,0','y,x,0','-y,-x,0'],['x,1/2,0','-x,1/2,0','1/2,x,0','1/2,-x,0'],['x,0,0','-x,0,0','0,x,0','0,-x,0'],['x,x,0','-x,-x,0','-x,x,0','x,-x,0'],['0,1/2,z','1/2,0,z','0,1/2,-z','1/2,0,-z'],['1/2,1/2,z','1/2,1/2,-z'],['0,0,z','0,0,-z'],['0,1/2,0','1/2,0,0'],['1/2,1/2,0'],['0,0,0']]" +62,"[['x,y,z','-x+1/2,-y+1/2,z','-y+1/2,x,z','y,-x+1/2,z','-x+1/2,y,-z','x,-y+1/2,-z','y,x,-z','-y+1/2,-x+1/2,-z','-x,-y,-z','x+1/2,y+1/2,-z','y+1/2,-x,-z','-y,x+1/2,-z','x+1/2,-y,z','-x,y+1/2,z','-y,-x,z','y+1/2,x+1/2,z'],['x,-x,z','-x+1/2,x+1/2,z','x+1/2,x,z','-x,-x+1/2,z','-x+1/2,-x,-z','x,x+1/2,-z','-x,x,-z','x+1/2,-x+1/2,-z'],['x,1/4,0','-x+1/2,1/4,0','1/4,x,0','1/4,-x+1/2,0','-x,3/4,0','x+1/2,3/4,0','3/4,-x,0','3/4,x+1/2,0'],['x,x,0','-x+1/2,-x+1/2,0','-x+1/2,x,0','x,-x+1/2,0','-x,-x,0','x+1/2,x+1/2,0','x+1/2,-x,0','-x,x+1/2,0'],['3/4,1/4,z','1/4,3/4,z','3/4,1/4,-z','1/4,3/4,-z'],['1/4,1/4,z','1/4,1/4,-z','3/4,3/4,-z','3/4,3/4,z'],['0,0,0','1/2,1/2,0','1/2,0,0','0,1/2,0'],['3/4,1/4,0','1/4,3/4,0'],['1/4,1/4,0','3/4,3/4,0']]" +63,"[['x,y,z','-x,-y,z','-y,x,z','y,-x,z','-x+1/2,y+1/2,-z','x+1/2,-y+1/2,-z','y+1/2,x+1/2,-z','-y+1/2,-x+1/2,-z','-x,-y,-z','x,y,-z','y,-x,-z','-y,x,-z','x+1/2,-y+1/2,z','-x+1/2,y+1/2,z','-y+1/2,-x+1/2,z','y+1/2,x+1/2,z'],['x,x+1/2,z','-x,-x+1/2,z','-x+1/2,x,z','x+1/2,-x,z','-x+1/2,x,-z','x+1/2,-x,-z','x,x+1/2,-z','-x,-x+1/2,-z'],['x,y,0','-x,-y,0','-y,x,0','y,-x,0','-x+1/2,y+1/2,0','x+1/2,-y+1/2,0','y+1/2,x+1/2,0','-y+1/2,-x+1/2,0'],['x,x+1/2,0','-x,-x+1/2,0','-x+1/2,x,0','x+1/2,-x,0'],['0,1/2,z','1/2,0,z','1/2,0,-z','0,1/2,-z'],['0,0,z','1/2,1/2,-z','0,0,-z','1/2,1/2,z'],['0,1/2,0','1/2,0,0'],['0,0,0','1/2,1/2,0']]" +64,"[['x,y,z','-x+1/2,-y+1/2,z','-y+1/2,x,z','y,-x+1/2,z','-x,y+1/2,-z','x+1/2,-y,-z','y+1/2,x+1/2,-z','-y,-x,-z','-x,-y,-z','x+1/2,y+1/2,-z','y+1/2,-x,-z','-y,x+1/2,-z','x,-y+1/2,z','-x+1/2,y,z','-y+1/2,-x+1/2,z','y,x,z'],['x,x,z','-x+1/2,-x+1/2,z','-x+1/2,x,z','x,-x+1/2,z','-x,x+1/2,-z','x+1/2,-x,-z','x+1/2,x+1/2,-z','-x,-x,-z'],['1/4,y,z','1/4,-y+1/2,z','-y+1/2,1/4,z','y,1/4,z','3/4,y+1/2,-z','3/4,-y,-z','y+1/2,3/4,-z','-y,3/4,-z'],['x,-x,0','-x+1/2,x+1/2,0','x+1/2,x,0','-x,-x+1/2,0','-x,x,0','x+1/2,-x+1/2,0','-x+1/2,-x,0','x,x+1/2,0'],['3/4,1/4,z','1/4,3/4,z','1/4,3/4,-z','3/4,1/4,-z'],['0,0,0','1/2,1/2,0','1/2,0,0','0,1/2,0'],['1/4,1/4,z','3/4,3/4,-z'],['3/4,1/4,0','1/4,3/4,0']]" +65,"[['x,y,z','-y,x-y,z','-x+y,-x,z'],['2/3,1/3,z'],['1/3,2/3,z'],['0,0,z']]" +66,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,-z','y,-x+y,-z','x-y,x,-z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['1/3,2/3,z','2/3,1/3,-z'],['0,0,z','0,0,-z'],['0,0,0']]" +67,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-y,-x,-z','-x+y,y,-z','x,x-y,-z'],['x,-x,0','x,2x,0','-2x,-x,0'],['2/3,1/3,z','2/3,1/3,-z'],['1/3,2/3,z','1/3,2/3,-z'],['0,0,z','0,0,-z'],['2/3,1/3,0'],['1/3,2/3,0'],['0,0,0']]" +68,"[['x,y,z','-y,x-y,z','-x+y,-x,z','y,x,-z','x-y,-y,-z','-x,-x+y,-z'],['x,0,0','0,x,0','-x,-x,0'],['1/3,2/3,z','2/3,1/3,-z'],['0,0,z','0,0,-z'],['0,0,0']]" +69,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-y,-x,z','-x+y,y,z','x,x-y,z'],['x,-x,z','x,2x,z','-2x,-x,z'],['2/3,1/3,z'],['1/3,2/3,z'],['0,0,z']]" +70,"[['x,y,z','-y,x-y,z','-x+y,-x,z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,0,z','0,x,z','-x,-x,z'],['1/3,2/3,z','2/3,1/3,z'],['0,0,z']]" +71,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-y,-x,-z','-x+y,y,-z','x,x-y,-z','-x,-y,-z','y,-x+y,-z','x-y,x,-z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,0,z','0,x,z','-x,-x,z','0,-x,-z','-x,0,-z','x,x,-z'],['x,-x,0','x,2x,0','-2x,-x,0','-x,x,0','-x,-2x,0','2x,x,0'],['1/3,2/3,z','1/3,2/3,-z','2/3,1/3,-z','2/3,1/3,z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" +72,"[['x,y,z','-y,x-y,z','-x+y,-x,z','y,x,-z','x-y,-y,-z','-x,-x+y,-z','-x,-y,-z','y,-x+y,-z','x-y,x,-z','-y,-x,z','-x+y,y,z','x,x-y,z'],['x,-x,z','x,2x,z','-2x,-x,z','-x,x,-z','2x,x,-z','-x,-2x,-z'],['x,0,0','0,x,0','-x,-x,0','-x,0,0','0,-x,0','x,x,0'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['1/3,2/3,z','2/3,1/3,-z'],['0,0,z','0,0,-z'],['0,0,0']]" +73,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z'],['1/2,0,z','0,1/2,z','1/2,1/2,z'],['1/3,2/3,z','2/3,1/3,z'],['0,0,z']]" +74,"[['x,y,z','-y,x-y,z','-x+y,-x,z','x,y,-z','-y,x-y,-z','-x+y,-x,-z'],['x,y,0','-y,x-y,0','-x+y,-x,0'],['2/3,1/3,z','2/3,1/3,-z'],['1/3,2/3,z','1/3,2/3,-z'],['0,0,z','0,0,-z'],['2/3,1/3,0'],['1/3,2/3,0'],['0,0,0']]" +75,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z','-x,-y,-z','y,-x+y,-z','x-y,x,-z','x,y,-z','-y,x-y,-z','-x+y,-x,-z'],['x,y,0','-y,x-y,0','-x+y,-x,0','-x,-y,0','y,-x+y,0','x-y,x,0'],['1/2,0,z','0,1/2,z','1/2,1/2,z','1/2,0,-z','0,1/2,-z','1/2,1/2,-z'],['1/3,2/3,z','2/3,1/3,z','1/3,2/3,-z','2/3,1/3,-z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" +76,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z','y,x,-z','x-y,-y,-z','-x,-x+y,-z','-y,-x,-z','-x+y,y,-z','x,x-y,-z'],['x,-x,0','x,2x,0','-2x,-x,0','-x,x,0','-x,-2x,0','2x,x,0'],['x,0,0','0,x,0','-x,-x,0','-x,0,0','0,-x,0','x,x,0'],['1/2,0,z','0,1/2,z','1/2,1/2,z','0,1/2,-z','1/2,0,-z','1/2,1/2,-z'],['1/3,2/3,z','2/3,1/3,z','2/3,1/3,-z','1/3,2/3,-z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" +77,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z','-y,-x,z','-x+y,y,z','x,x-y,z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,-x,z','x,2x,z','-2x,-x,z','-x,x,z','-x,-2x,z','2x,x,z'],['x,0,z','0,x,z','-x,-x,z','-x,0,z','0,-x,z','x,x,z'],['1/2,0,z','0,1/2,z','1/2,1/2,z'],['1/3,2/3,z','2/3,1/3,z'],['0,0,z']]" +78,"[['x,y,z','-y,x-y,z','-x+y,-x,z','x,y,-z','-y,x-y,-z','-x+y,-x,-z','-y,-x,z','-x+y,y,z','x,x-y,z','-y,-x,-z','-x+y,y,-z','x,x-y,-z'],['x,-x,z','x,2x,z','-2x,-x,z','x,-x,-z','x,2x,-z','-2x,-x,-z'],['x,y,0','-y,x-y,0','-x+y,-x,0','-y,-x,0','-x+y,y,0','x,x-y,0'],['x,-x,0','x,2x,0','-2x,-x,0'],['2/3,1/3,z','2/3,1/3,-z'],['1/3,2/3,z','1/3,2/3,-z'],['0,0,z','0,0,-z'],['2/3,1/3,0'],['1/3,2/3,0'],['0,0,0']]" +79,"[['x,y,z','-y,x-y,z','-x+y,-x,z','x,y,-z','-y,x-y,-z','-x+y,-x,-z','y,x,-z','x-y,-y,-z','-x,-x+y,-z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,y,0','-y,x-y,0','-x+y,-x,0','y,x,0','x-y,-y,0','-x,-x+y,0'],['x,0,z','0,x,z','-x,-x,z','x,0,-z','0,x,-z','-x,-x,-z'],['1/3,2/3,z','1/3,2/3,-z','2/3,1/3,-z','2/3,1/3,z'],['x,0,0','0,x,0','-x,-x,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" +80,"[['x,y,z','-y,x-y,z','-x+y,-x,z','-x,-y,z','y,-x+y,z','x-y,x,z','y,x,-z','x-y,-y,-z','-x,-x+y,-z','-y,-x,-z','-x+y,y,-z','x,x-y,-z','-x,-y,-z','y,-x+y,-z','x-y,x,-z','x,y,-z','-y,x-y,-z','-x+y,-x,-z','-y,-x,z','-x+y,y,z','x,x-y,z','y,x,z','x-y,-y,z','-x,-x+y,z'],['x,y,0','-y,x-y,0','-x+y,-x,0','-x,-y,0','y,-x+y,0','x-y,x,0','y,x,0','x-y,-y,0','-x,-x+y,0','-y,-x,0','-x+y,y,0','x,x-y,0'],['x,2x,z','-2x,-x,z','x,-x,z','-x,-2x,z','2x,x,z','-x,x,z','2x,x,-z','-x,-2x,-z','-x,x,-z','-2x,-x,-z','x,2x,-z','x,-x,-z'],['x,0,z','0,x,z','-x,-x,z','-x,0,z','0,-x,z','x,x,z','0,x,-z','x,0,-z','-x,-x,-z','0,-x,-z','-x,0,-z','x,x,-z'],['x,2x,0','-2x,-x,0','x,-x,0','-x,-2x,0','2x,x,0','-x,x,0'],['x,0,0','0,x,0','-x,-x,0','-x,0,0','0,-x,0','x,x,0'],['1/2,0,z','0,1/2,z','1/2,1/2,z','0,1/2,-z','1/2,0,-z','1/2,1/2,-z'],['1/3,2/3,z','2/3,1/3,z','2/3,1/3,-z','1/3,2/3,-z'],['1/2,0,0','0,1/2,0','1/2,1/2,0'],['0,0,z','0,0,-z'],['1/3,2/3,0','2/3,1/3,0'],['0,0,0']]" diff --git a/crystalformer/data/layer_symbols.csv b/crystalformer/data/layer_symbols.csv new file mode 100644 index 0000000..723b779 --- /dev/null +++ b/crystalformer/data/layer_symbols.csv @@ -0,0 +1,81 @@ +Layer Group,Wyckoff Positions +1,['1a'] +2,"['1a', '1b', '1c', '1d', '2e']" +3,"['1a', '1b', '1c', '1d', '2e']" +4,"['1a', '2b']" +5,['2a'] +6,"['1a', '1b', '1c', '1d', '2e', '2f', '2g', '2h', '2i', '4j']" +7,"['2a', '2b', '2c', '2d', '4e']" +8,"['1a', '1b', '2c']" +9,['2a'] +10,"['2a', '4b']" +11,"['1a', '1b', '2c']" +12,['2a'] +13,"['2a', '4b']" +14,"['1a', '1b', '1c', '1d', '2e', '2f', '2g', '2h', '4i']" +15,"['2a', '2b', '2c', '4d']" +16,"['2a', '2b', '2c', '4d']" +17,"['2a', '2b', '4c']" +18,"['2a', '2b', '4c', '4d', '4e', '8f']" +19,"['1a', '1b', '1c', '1d', '2e', '2f', '2g', '2h', '2i', '2j', '2k', '2l', '4m']" +20,"['2a', '2b', '2c', '4d']" +21,"['2a', '2b', '4c']" +22,"['2a', '2b', '4c', '4d', '4e', '4f', '4g', '8h']" +23,"['1a', '1b', '1c', '1d', '2e', '2f', '2g', '2h', '4i']" +24,"['2a', '2b', '2c', '4d']" +25,"['2a', '2b', '4c']" +26,"['2a', '2b', '4c', '4d', '4e', '8f']" +27,"['1a', '1b', '2c', '2d', '2e', '4f']" +28,"['2a', '2b', '4c']" +29,"['2a', '4b']" +30,"['2a', '2b', '4c']" +31,"['2a', '2b', '4c']" +32,"['2a', '4b']" +33,['4a'] +34,"['2a', '4b']" +35,"['2a', '4b', '4c', '8d']" +36,"['4a', '4b', '8c']" +37,"['1a', '1b', '1c', '1d', '2e', '2f', '2g', '2h', '2i', '2j', '2k', '2l', '4m', '4n', '4o', '4p', '4q', '8r']" +38,"['2a', '2b', '2c', '2d', '4e', '4f', '4g', '4h', '4i', '4j', '8k']" +39,"['2a', '2b', '4c', '4d', '4e', '4f', '4g', '8h']" +40,"['2a', '2b', '2c', '4d', '4e', '4f', '4g', '8h']" +41,"['2a', '2b', '2c', '2d', '4e', '4f', '4g', '4h', '8i']" +42,"['2a', '2b', '4c', '4d', '4e', '8f']" +43,"['4a', '4b', '4c', '8d']" +44,"['2a', '2b', '4c', '4d', '4e', '8f']" +45,"['4a', '4b', '4c', '8d']" +46,"['2a', '2b', '4c', '4d', '4e', '8f']" +47,"['2a', '2b', '4c', '4d', '4e', '4f', '4g', '8h', '8i', '8j', '8k', '16l']" +48,"['4a', '4b', '4c', '4d', '8e', '8f', '8g', '8h', '8i', '16j']" +49,"['1a', '1b', '2c', '4d']" +50,"['1a', '1b', '2c', '2d', '2e', '4f']" +51,"['1a', '1b', '2c', '2d', '2e', '4f', '4g', '8h']" +52,"['2a', '2b', '4c', '4d', '8e']" +53,"['1a', '1b', '2c', '2d', '2e', '4f', '4g', '4h', '4i', '8j']" +54,"['2a', '2b', '4c', '4d', '8e']" +55,"['1a', '1b', '2c', '4d', '4e', '4f', '8g']" +56,"['2a', '2b', '4c', '8d']" +57,"['1a', '1b', '2c', '2d', '2e', '4f', '4g', '4h', '4i', '8j']" +58,"['2a', '2b', '4c', '4d', '8e']" +59,"['1a', '1b', '2c', '2d', '2e', '4f', '4g', '4h', '8i']" +60,"['2a', '2b', '4c', '4d', '4e', '8f']" +61,"['1a', '1b', '2c', '2d', '2e', '4f', '4g', '4h', '4i', '8j', '8k', '8l', '8m', '16n']" +62,"['2a', '2b', '4c', '4d', '4e', '8f', '8g', '8h', '16i']" +63,"['2a', '2b', '4c', '4d', '4e', '8f', '8g', '16h']" +64,"['2a', '2b', '4c', '4d', '8e', '8f', '8g', '16h']" +65,"['1a', '1b', '1c', '3d']" +66,"['1a', '2b', '2c', '3d', '6e']" +67,"['1a', '1b', '1c', '2d', '2e', '2f', '3g', '6h']" +68,"['1a', '2b', '2c', '3d', '6e']" +69,"['1a', '1b', '1c', '3d', '6e']" +70,"['1a', '2b', '3c', '6d']" +71,"['1a', '2b', '2c', '3d', '4e', '6f', '6g', '12h']" +72,"['1a', '2b', '2c', '3d', '6e', '6f', '12g']" +73,"['1a', '2b', '3c', '6d']" +74,"['1a', '1b', '1c', '2d', '2e', '2f', '3g', '6h']" +75,"['1a', '2b', '2c', '3d', '4e', '6f', '6g', '12h']" +76,"['1a', '2b', '2c', '3d', '4e', '6f', '6g', '6h', '12i']" +77,"['1a', '2b', '3c', '6d', '6e', '12f']" +78,"['1a', '1b', '1c', '2d', '2e', '2f', '3g', '6h', '6i', '12j']" +79,"['1a', '2b', '2c', '3d', '4e', '6f', '6g', '12h']" +80,"['1a', '2b', '2c', '3d', '4e', '6f', '6g', '6h', '12i', '12j', '12k', '24l']" diff --git a/crystalformer/extension/experimental.py b/crystalformer/extension/experimental.py index c1790b4..062f02a 100644 --- a/crystalformer/extension/experimental.py +++ b/crystalformer/extension/experimental.py @@ -3,7 +3,6 @@ from functools import partial from crystalformer.src.wyckoff import fc_mask_table -from crystalformer.src.von_mises import sample_von_mises from crystalformer.src.lattice import symmetrize_lattice get_fc_mask = lambda g, w: jnp.logical_and((w>0)[:, None], fc_mask_table[g-1, w]) @@ -64,7 +63,7 @@ def body_fn(j, A): return A @partial(jax.jit, static_argnums=0) - def mcmc(logp_fn, x_init, key, mc_steps, mc_width, temp): + def mcmc(spacegroup, logp_fn, x_init, key, mc_steps, mc_width, temp): """ Markov Chain Monte Carlo sampling algorithm. @@ -141,7 +140,7 @@ def true_func(i, state): A_proposal = jnp.where(A == 0, A, _A) fc_mask = jax.vmap(get_fc_mask, in_axes=(0, 0))(G, W) - _xyz = XYZ[:, i%n_max] + sample_von_mises(key_proposal_XYZ, 0, 1/mc_width**2, XYZ[:, i%n_max].shape) + _xyz = XYZ[:, i%n_max] + spacegroup.sample_von_mises(key_proposal_XYZ, 0, 1/mc_width**2, XYZ[:, i%n_max].shape) _XYZ = XYZ.at[:, i%n_max].set(_xyz) _XYZ -= jnp.floor(_XYZ) # wrap to [0, 1) XYZ_proposal = jnp.where(fc_mask, _XYZ, XYZ) diff --git a/crystalformer/extension/mcmc.py b/crystalformer/extension/mcmc.py index 0fd07a0..657c4e0 100644 --- a/crystalformer/extension/mcmc.py +++ b/crystalformer/extension/mcmc.py @@ -3,7 +3,6 @@ from functools import partial from crystalformer.src.wyckoff import fc_mask_table -from crystalformer.src.von_mises import sample_von_mises from crystalformer.src.lattice import symmetrize_lattice @@ -29,7 +28,7 @@ def body_fn(j, A): return A @partial(jax.jit, static_argnums=0) - def mcmc(logp_fn, x_init, key, mc_steps, mc_width, temp): + def mcmc(spacegroup, logp_fn, x_init, key, mc_steps, mc_width, temp): """ Markov Chain Monte Carlo sampling algorithm. @@ -106,7 +105,7 @@ def true_func(i, state): A_proposal = jnp.where(A == 0, A, _A) fc_mask = jax.vmap(get_fc_mask, in_axes=(0, 0))(G, W) - _xyz = XYZ[:, i%n_max] + sample_von_mises(key_proposal_XYZ, 0, 1/mc_width**2, XYZ[:, i%n_max].shape) + _xyz = XYZ[:, i%n_max] + spacegroup.sample_von_mises(key_proposal_XYZ, 0, 1/mc_width**2, XYZ[:, i%n_max].shape) _XYZ = XYZ.at[:, i%n_max].set(_xyz) _XYZ -= jnp.floor(_XYZ) # wrap to [0, 1) XYZ_proposal = jnp.where(fc_mask, _XYZ, XYZ) @@ -198,7 +197,7 @@ def step(i, state): for i in range(5): key, subkey = jax.random.split(key) - x, acc = mcmc(logp_fn, x_init=x_init, key=subkey, mc_steps=mc_steps, mc_width=mc_width) + x, acc = mcmc(spacegroup, logp_fn, x_init=x_init, key=subkey, mc_steps=mc_steps, mc_width=mc_width) print(i, acc) print("check if the lattice is changed") diff --git a/crystalformer/src/gaussian.py b/crystalformer/src/gaussian.py new file mode 100644 index 0000000..d525b3a --- /dev/null +++ b/crystalformer/src/gaussian.py @@ -0,0 +1,96 @@ +import jax +from jax import jit, lax, random +import jax.numpy as jnp +from functools import partial +from crystalformer.src.von_mises import sample_von_mises + +def gaussian_centered(key, concentration, shape, dtype = jnp.float64): + shape = shape or jnp.shape(concentration) + dtype = jnp.result_type(dtype) + concentration = lax.convert_element_type(concentration, dtype) + concentration = jnp.broadcast_to(concentration, shape) + return _gaussian_centered(key, concentration, shape, dtype) + +@partial(jit, static_argnums = (2, 3)) +def _gaussian_centered(key, concentration, shape, dtype): + # what cutoff? + s_cutoff_map = { + jnp.dtype(jnp.float16): 1.8e-1, + jnp.dtype(jnp.float32): 2e-2, + jnp.dtype(jnp.float64): 1.2e-4, + } + s_cutoff = s_cutoff_map.get(dtype) + + r = 1.0 + jnp.sqrt(1.0 + 4.0 * concentration**2) + rho = (r - jnp.sqrt(2.0 * r)) / (2.0 * concentration) + s_exact = (1.0 + rho**2) / (2.0 * rho) + + s_approximate = 1.0 / concentration + + s = jnp.where(concentration > s_cutoff, s_exact, s_approximate) + + def cond_fn(*args): + i, _, done, _, _ = args[0] + return jnp.bitwise_and(i < 100, jnp.logical_not(jnp.all(done))) + + def body_fn(*args): + i, key, done, _, w = args[0] + uni_ukey, uni_vkey, key = random.split(key, 3) + + u = random.uniform( + key = uni_ukey, + shape = shape, + dtype = concentration.dtype, + minval = -1.0, + maxval = 1.0, + ) + z = jnp.cos(jnp.pi * u) + w = jnp.where(done, w, (1.0 + s * z) / (s + z)) + + y = concentration * (s - w) + v = random.uniform(key = uni_vkey, shape = shape, dtype = concentration.dtype) + + accept = (y * (2.0 - y) >= v) | (jnp.log(y / v) + 1.0 >= y) + + return i + 1, key, accept | done, u, w + + init_done = jnp.zeros(shape, dtype=bool) + init_u = jnp.zeros(shape) + init_w = jnp.zeros(shape) + + _, _, done, u, w = lax.while_loop( + cond_fun=cond_fn, + body_fun=body_fn, + init_val=(jnp.array(0), key, init_done, init_u, init_w), + ) + + return jnp.sign(u) * jnp.arccos(w) + +def gaussian_logpdf(x, loc, concentration): + ''' + concentration = kappa in von mises distribution = 1/variance + concentration = 1/sigma^2 in gaussian distribution + ''' + return -0.5 * (jnp.log(2 * jnp.pi) - jnp.log(concentration) + concentration * (x - loc) * (x - loc)) + + + +if __name__ == '__main__': + key = jax.random.PRNGKey(42) + num_samples = 1000 + loc = jnp.zeros(num_samples) + kappa = jnp.ones(num_samples) + x = sample_gaussian(key, loc, kappa, (num_samples, )) + x_grid = jnp.linspace(-5.0, 5.0, 100) + y = [0 for _ in range(100)] + for i in range(num_samples): + for j in range(100 - 1): + if (x[i] >= x_grid[j]) & (x[i] <= x_grid[j+1]): + y[j] += 1 + break + + import matplotlib.pyplot as plt + + fig, ax = plt.subplots(1, 1) + ax.bar(x_grid, y) + plt.show() \ No newline at end of file diff --git a/crystalformer/src/lattice.py b/crystalformer/src/lattice.py index 9135942..6e9bd1a 100644 --- a/crystalformer/src/lattice.py +++ b/crystalformer/src/lattice.py @@ -1,26 +1,26 @@ import jax import jax.numpy as jnp -def make_lattice_mask(): +def make_lattice_mask_spacegroup(): ''' return mask for independent lattice params ''' # 1-2 - # 3-15 - # 16-74 - # 75-142 - # 143-194 - # 195-230 + # 3-18 + # 19-48 + # 49-64 + # 65-72 + # 73-80 mask = [1, 1, 1, 1, 1, 1] * 2 +\ - [1, 1, 1, 0, 1, 0] * 13+\ - [1, 1, 1, 0, 0, 0] * 59+\ - [1, 0, 1, 0, 0, 0] * 68+\ - [1, 0, 1, 0, 0, 0] * 52+\ - [1, 0, 0, 0, 0, 0] * 36 + [1, 1, 1, 0, 1, 0] * 16+\ + [1, 1, 1, 0, 0, 0] * 30+\ + [1, 0, 1, 0, 0, 0] * 16+\ + [1, 0, 1, 0, 0, 0] * 16 + # [1, 0, 0, 0, 0, 0] * 8 - return jnp.array(mask).reshape(230, 6) + return jnp.array(mask).reshape(80, 6) -def symmetrize_lattice(spacegroup, lattice): +def symmetrize_lattice_spacegroup(g, lattice): ''' place lattice params into lattice according to the space group ''' @@ -28,17 +28,47 @@ def symmetrize_lattice(spacegroup, lattice): a, b, c, alpha, beta, gamma = lattice L = lattice - L = jnp.where(spacegroup <= 2, L, jnp.array([a, b, c, 90., beta, 90.])) - L = jnp.where(spacegroup <= 15, L, jnp.array([a, b, c, 90., 90., 90.])) - L = jnp.where(spacegroup <= 74, L, jnp.array([a, a, c, 90., 90., 90.])) - L = jnp.where(spacegroup <= 142, L, jnp.array([a, a, c, 90., 90., 120.])) - L = jnp.where(spacegroup <= 194, L, jnp.array([a, a, a, 90., 90., 90.])) + L = jnp.where(g <= 2, L, jnp.array([a, b, c, 90., beta, 90.])) + L = jnp.where(g <= 15, L, jnp.array([a, b, c, 90., 90., 90.])) + L = jnp.where(g <= 74, L, jnp.array([a, a, c, 90., 90., 90.])) + L = jnp.where(g <= 142, L, jnp.array([a, a, c, 90., 90., 120.])) + L = jnp.where(g <= 194, L, jnp.array([a, a, a, 90., 90., 90.])) + + return L + +def make_lattice_mask_layergroup(): + # 1-2 + # 3-7 + # 8-18 + # 19-48 + # 49-64 + # 65-72 + # 73-80 + + mask = [1, 1, 1, 1, 1, 1] * 2 +\ + [1, 1, 1, 0, 1, 0] * 16 +\ + [1, 1, 1, 0, 0, 0] * 30 +\ + [1, 0, 1, 0, 0, 0] * 16 +\ + [1, 0, 0, 1, 0, 0] * 8 +\ + [1, 0, 1, 0, 0, 0] * 8 + + return jnp.array(mask).reshape(80, 6) + +def symmetrize_lattice_layergroup(g, lattice): + a, b, c, alpha, beta, gamma = lattice + + L = lattice + L = jnp.where(g <= 2, L, jnp.array([a, b, c, 90., beta, 90.])) + L = jnp.where(g <= 18, L, jnp.array([a, b, c, 90., 90., 90.])) + L = jnp.where(g <= 48, L, jnp.array([a, a, c, 90., 90., 90.])) + L = jnp.where(g <= 64, L, jnp.array([a, a, a, alpha, alpha, alpha])) + L = jnp.where(g <= 72, L, jnp.array([a, a, c, 90., 90., 120.])) return L if __name__ == '__main__': - mask = make_lattice_mask() + mask = make_lattice_mask_layergroup() print (mask) key = jax.random.PRNGKey(42) @@ -46,6 +76,6 @@ def symmetrize_lattice(spacegroup, lattice): lattice = lattice.reshape([1, 6]).repeat(3, axis=0) G = jnp.array([25, 99, 221]) - L = jax.vmap(symmetrize_lattice)(G, lattice) + L = jax.vmap(symmetrize_lattice_layergroup)(G, lattice) print (L) diff --git a/crystalformer/src/loss.py b/crystalformer/src/loss.py index 0afc54a..74fbd32 100644 --- a/crystalformer/src/loss.py +++ b/crystalformer/src/loss.py @@ -3,12 +3,12 @@ import jax.numpy as jnp from functools import partial -from crystalformer.src.von_mises import von_mises_logpdf -from crystalformer.src.lattice import make_lattice_mask -from crystalformer.src.wyckoff import mult_table, fc_mask_table +# from crystalformer.src.von_mises import von_mises_logpdf +# from crystalformer.src.lattice import make_lattice_mask +from crystalformer.src.sym_group import * -def make_loss_fn(n_max, atom_types, wyck_types, Kx, Kl, transformer, lamb_a=1.0, lamb_w=1.0, lamb_l=1.0): +def make_loss_fn(sym_group, n_max, atom_types, wyck_types, Kx, Kl, transformer, lamb_a=1.0, lamb_w=1.0, lamb_l=1.0): """ Args: n_max: maximum number of atoms in the unit cell @@ -27,13 +27,13 @@ def make_loss_fn(n_max, atom_types, wyck_types, Kx, Kl, transformer, lamb_a=1.0, """ coord_types = 3*Kx - lattice_mask = make_lattice_mask() + lattice_mask = sym_group.make_lattice_mask()() - def compute_logp_x(h_x, X, fc_mask_x): + def compute_logp_x(distribution, h_x, X, fc_mask_x): x_logit, loc, kappa = jnp.split(h_x, [Kx, 2*Kx], axis=-1) x_loc = loc.reshape(n_max, Kx) kappa = kappa.reshape(n_max, Kx) - logp_x = jax.vmap(von_mises_logpdf, (None, 1, 1), 1)((X-0.5)*2*jnp.pi, loc, kappa) # (n_max, Kx) + logp_x = jax.vmap(distribution, (None, 1, 1), 1)((X-0.5)*2*jnp.pi, loc, kappa) # (n_max, Kx) logp_x = jax.scipy.special.logsumexp(x_logit + logp_x, axis=1) # (n_max, ) logp_x = jnp.sum(jnp.where(fc_mask_x, logp_x, jnp.zeros_like(logp_x))) @@ -42,6 +42,7 @@ def compute_logp_x(h_x, X, fc_mask_x): @partial(jax.vmap, in_axes=(None, None, 0, 0, 0, 0, 0, None), out_axes=0) # batch def logp_fn(params, key, G, L, XYZ, A, W, is_train): ''' + sym_group: SpaceGroup, LayerGroup, ... G: scalar L: (6,) [a, b, c, alpha, beta, gamma] XYZ: (n_max, 3) @@ -50,7 +51,7 @@ def logp_fn(params, key, G, L, XYZ, A, W, is_train): ''' num_sites = jnp.sum(A!=0) - M = mult_table[G-1, W] # (n_max,) multplicities + M = sym_group.mult_table[G-1, W] # (n_max,) multplicities #num_atoms = jnp.sum(M) h = transformer(params, key, G, XYZ, A, W, M, is_train) # (5*n_max+1, ...) @@ -66,10 +67,10 @@ def logp_fn(params, key, G, L, XYZ, A, W, is_train): X, Y, Z = XYZ[:, 0], XYZ[:, 1], XYZ[:,2] - fc_mask = jnp.logical_and((W>0)[:, None], fc_mask_table[G-1, W]) # (n_max, 3) - logp_x = compute_logp_x(h_x, X, fc_mask[:, 0]) - logp_y = compute_logp_x(h_y, Y, fc_mask[:, 1]) - logp_z = compute_logp_x(h_z, Z, fc_mask[:, 2]) + fc_mask = jnp.logical_and((W>0)[:, None], sym_group.fc_mask_table[G-1, W]) # (n_max, 3) + logp_x = compute_logp_x(sym_group.distribution('x'), h_x, X, fc_mask[:, 0]) + logp_y = compute_logp_x(sym_group.distribution('y'), h_y, Y, fc_mask[:, 1]) + logp_z = compute_logp_x(sym_group.distribution('z'), h_z, Z, fc_mask[:, 2]) logp_xyz = logp_x + logp_y + logp_z @@ -106,13 +107,13 @@ def loss_fn(params, key, G, L, XYZ, A, W, is_train): dropout_rate = 0.1 csv_file = '../data/mini.csv' - G, L, XYZ, A, W = GLXYZAW_from_file(csv_file, atom_types, wyck_types, n_max) + G, L, XYZ, A, W = GLXYZAW_from_file(SpaceGroup(), csv_file, atom_types, wyck_types, n_max) key = jax.random.PRNGKey(42) - params, transformer = make_transformer(key, Nf, Kx, Kl, n_max, 128, 4, 4, 8, 16, 16, atom_types, wyck_types, dropout_rate) + params, transformer = make_transformer(SpaceGroup(), key, Nf, Kx, Kl, n_max, 128, 4, 4, 8, 16, 16, atom_types, wyck_types, dropout_rate) - loss_fn, _ = make_loss_fn(n_max, atom_types, wyck_types, Kx, Kl, transformer) + loss_fn, _ = make_loss_fn(SpaceGroup(), n_max, atom_types, wyck_types, Kx, Kl, transformer) value = jax.jit(loss_fn, static_argnums=7)(params, key, G[:1], L[:1], XYZ[:1], A[:1], W[:1], True) print (value) diff --git a/crystalformer/src/mcmc.py b/crystalformer/src/mcmc.py index 125b5c3..b2c7ba8 100644 --- a/crystalformer/src/mcmc.py +++ b/crystalformer/src/mcmc.py @@ -2,13 +2,12 @@ import jax.numpy as jnp from functools import partial -from crystalformer.src.wyckoff import fc_mask_table -from crystalformer.src.von_mises import sample_von_mises +from crystalformer.src.sym_group import * -get_fc_mask = lambda g, w: jnp.logical_and((w>0)[:, None], fc_mask_table[g-1, w]) +def make_mcmc_step(params, n_max, atom_types, sym_group, atom_mask=None, constraints=None): -def make_mcmc_step(params, n_max, atom_types, atom_mask=None, constraints=None): + get_fc_mask = lambda g, w: jnp.logical_and((w>0)[:, None], sym_group.fc_mask_table[g-1, w]) if atom_mask is None or jnp.all(atom_mask == 0): atom_mask = jnp.ones((n_max, atom_types)) @@ -28,7 +27,7 @@ def body_fn(j, A): return A @partial(jax.jit, static_argnums=0) - def mcmc(logp_fn, x_init, key, mc_steps, mc_width): + def mcmc(spacegroup, logp_fn, x_init, key, mc_steps, mc_width): """ Markov Chain Monte Carlo sampling algorithm. @@ -57,7 +56,7 @@ def true_func(i, state): A_proposal = jnp.where(A == 0, A, _A) fc_mask = jax.vmap(get_fc_mask, in_axes=(0, 0))(G, W) - _xyz = XYZ[:, i%n_max] + sample_von_mises(key_proposal_XYZ, 0, 1/mc_width**2, XYZ[:, i%n_max].shape) + _xyz = XYZ[:, i%n_max] + sym_group.sample_all_dim()(key_proposal_XYZ, 0, 1/mc_width**2, XYZ[:, i%n_max].shape) _XYZ = XYZ.at[:, i%n_max].set(_xyz) _XYZ -= jnp.floor(_XYZ) # wrap to [0, 1) XYZ_proposal = jnp.where(fc_mask, _XYZ, XYZ) @@ -123,13 +122,13 @@ def false_func(i, state): dropout_rate = 0.3 csv_file = '../data/mini.csv' - G, L, XYZ, A, W = GLXYZAW_from_file(csv_file, atom_types, wyck_types, n_max) + G, L, XYZ, A, W = GLXYZAW_from_file(SpaceGroup(), csv_file, atom_types, wyck_types, n_max) key = jax.random.PRNGKey(42) - params, transformer = make_transformer(key, Nf, Kx, Kl, n_max, 128, 4, 4, 8, 16, 16, atom_types, wyck_types, dropout_rate) + params, transformer = make_transformer(SpaceGroup(), key, Nf, Kx, Kl, n_max, 128, 4, 4, 8, 16, 16, atom_types, wyck_types, dropout_rate) - loss_fn, logp_fn = make_loss_fn(n_max, atom_types, wyck_types, Kx, Kl, transformer) + loss_fn, logp_fn = make_loss_fn(SpaceGroup(), n_max, atom_types, wyck_types, Kx, Kl, transformer) # MCMC sampling test mc_steps = 21 @@ -139,11 +138,11 @@ def false_func(i, state): value = jax.jit(logp_fn, static_argnums=7)(params, key, *x_init, False) jnp.set_printoptions(threshold=jnp.inf) - mcmc = make_mcmc_step(params, n_max=n_max, atom_types=atom_types) + mcmc = make_mcmc_step(params, n_max=n_max, atom_types=atom_types, sym_group=SpaceGroup()) for i in range(5): key, subkey = jax.random.split(key) - x, acc = mcmc(logp_fn, x_init=x_init, key=subkey, mc_steps=mc_steps, mc_width=mc_width) + x, acc = mcmc(spacegroup, logp_fn, x_init=x_init, key=subkey, mc_steps=mc_steps, mc_width=mc_width) print(i, acc) print("check if the atom type is changed") diff --git a/crystalformer/src/sample.py b/crystalformer/src/sample.py index ae0fbdb..4b47fc2 100644 --- a/crystalformer/src/sample.py +++ b/crystalformer/src/sample.py @@ -1,30 +1,33 @@ +import sys +sys.path.append('../../crystalformer') + import jax import jax.numpy as jnp from functools import partial -from crystalformer.src.von_mises import sample_von_mises -from crystalformer.src.lattice import symmetrize_lattice -from crystalformer.src.wyckoff import mult_table, symops +from crystalformer.src.sym_group import * +# from crystalformer.src.lattice import symmetrize_lattice +# from crystalformer.src.wyckoff import mult_table -def project_xyz(g, w, x, idx): +def project_xyz(sym_group, g, w, x, idx): ''' apply the randomly sampled Wyckoff symmetry op to sampled fc, which should be (or close to) the first WP ''' - op = symops[g-1, w, idx].reshape(3, 4) + op = sym_group.symops[g-1, w, idx].reshape(3, 4) affine_point = jnp.array([*x, 1]) # (4, ) x = jnp.dot(op, affine_point) # (3, ) x -= jnp.floor(x) return x -@partial(jax.vmap, in_axes=(None, None, None, 0, 0, 0, 0, 0), out_axes=0) # batch -def inference(model, params, g, W, A, X, Y, Z): +@partial(jax.vmap, in_axes=(None, None, None, None, 0, 0, 0, 0, 0), out_axes=0) # batch +def inference(sym_group, model, params, g, W, A, X, Y, Z): XYZ = jnp.concatenate([X[:, None], Y[:, None], Z[:, None] ], axis=-1) - M = mult_table[g-1, W] + M = sym_group.mult_table[g-1, W] return model(params, None, g, XYZ, A, W, M, False) def sample_top_p(key, logits, p, temperature): @@ -48,25 +51,25 @@ def sample_top_p(key, logits, p, temperature): samples = jax.random.categorical(key, logits/temperature, axis=1) return samples -def sample_x(key, h_x, Kx, top_p, temperature, batchsize): +def sample_x(sym_group, axis, key, h_x, Kx, top_p, temperature, batchsize): coord_types = 3*Kx x_logit, loc, kappa = jnp.split(h_x[:, :coord_types], [Kx, 2*Kx], axis=-1) key, key_k, key_x = jax.random.split(key, 3) k = sample_top_p(key_k, x_logit, top_p, temperature) loc = loc.reshape(batchsize, Kx)[jnp.arange(batchsize), k] kappa = kappa.reshape(batchsize, Kx)[jnp.arange(batchsize), k] - x = sample_von_mises(key_x, loc, kappa/temperature, (batchsize,)) + x = sym_group.sample(axis)(key_x, loc, kappa/temperature, (batchsize,)) x = (x+ jnp.pi)/(2.0*jnp.pi) # wrap into [0, 1] return key, x -@partial(jax.jit, static_argnums=(1, 3, 4, 5, 6, 7, 8, 9, 12, 14)) -def sample_crystal(key, transformer, params, n_max, batchsize, atom_types, wyck_types, Kx, Kl, g, w_mask, atom_mask, top_p, temperature, T1, constraints): +@partial(jax.jit, static_argnums=(0, 2, 4, 5, 6, 7, 8, 9, 10, 13, 15)) +def sample_crystal(sym_group, key, transformer, params, n_max, batchsize, atom_types, wyck_types, Kx, Kl, g, w_mask, atom_mask, top_p, temperature, T1, constraints): def body_fn(i, state): key, W, A, X, Y, Z, L = state # (1) W - w_logit = inference(transformer, params, g, W, A, X, Y, Z)[:, 5*i] # (batchsize, output_size) + w_logit = inference(sym_group, transformer, params, g, W, A, X, Y, Z)[:, 5*i] # (batchsize, output_size) w_logit = w_logit[:, :wyck_types] key, subkey = jax.random.split(key) @@ -76,10 +79,12 @@ def body_fn(i, state): W = W.at[:, i].set(w) # (2) A - h_al = inference(transformer, params, g, W, A, X, Y, Z)[:, 5*i+1] # (batchsize, output_size) + h_al = inference(sym_group, transformer, params, g, W, A, X, Y, Z)[:, 5*i+1] # (batchsize, output_size) a_logit = h_al[:, :atom_types] key, subkey = jax.random.split(key) + # import pdb + # pdb.set_trace() a_logit = a_logit + jnp.where(atom_mask[i, :], 1e10, 0.0) # enhance the probability of masked atoms (do not need to normalize since we only use it for sampling, not computing logp) _temp = jax.lax.cond(i==0, true_fun=lambda x: jnp.array(T1, dtype=float), @@ -96,41 +101,41 @@ def body_fn(i, state): L = L.at[:, i].set(lattice_params) # (3) X - h_x = inference(transformer, params, g, W, A, X, Y, Z)[:, 5*i+2] # (batchsize, output_size) - key, x = sample_x(key, h_x, Kx, top_p, temperature, batchsize) + h_x = inference(sym_group, transformer, params, g, W, A, X, Y, Z)[:, 5*i+2] # (batchsize, output_size) + key, x = sample_x(sym_group, 'x', key, h_x, Kx, top_p, temperature, batchsize) # project to the first WP xyz = jnp.concatenate([x[:, None], jnp.zeros((batchsize, 1)), jnp.zeros((batchsize, 1)), ], axis=-1) - xyz = jax.vmap(project_xyz, in_axes=(None, 0, 0, None), out_axes=0)(g, w, xyz, 0) + xyz = jax.vmap(project_xyz, in_axes=(None, None, 0, 0, None), out_axes=0)(sym_group, g, w, xyz, 0) x = xyz[:, 0] X = X.at[:, i].set(x) # (4) Y - h_y = inference(transformer, params, g, W, A, X, Y, Z)[:, 5*i+3] # (batchsize, output_size) - key, y = sample_x(key, h_y, Kx, top_p, temperature, batchsize) + h_y = inference(sym_group, transformer, params, g, W, A, X, Y, Z)[:, 5*i+3] # (batchsize, output_size) + key, y = sample_x(sym_group, 'y', key, h_y, Kx, top_p, temperature, batchsize) # project to the first WP xyz = jnp.concatenate([X[:, i][:, None], y[:, None], jnp.zeros((batchsize, 1)), ], axis=-1) - xyz = jax.vmap(project_xyz, in_axes=(None, 0, 0, None), out_axes=0)(g, w, xyz, 0) + xyz = jax.vmap(project_xyz, in_axes=(None, None, 0, 0, None), out_axes=0)(sym_group, g, w, xyz, 0) y = xyz[:, 1] Y = Y.at[:, i].set(y) # (5) Z - h_z = inference(transformer, params, g, W, A, X, Y, Z)[:, 5*i+4] # (batchsize, output_size) - key, z = sample_x(key, h_z, Kx, top_p, temperature, batchsize) + h_z = inference(sym_group, transformer, params, g, W, A, X, Y, Z)[:, 5*i+4] # (batchsize, output_size) + key, z = sample_x(sym_group, 'z', key, h_z, Kx, top_p, temperature, batchsize) # project to the first WP xyz = jnp.concatenate([X[:, i][:, None], Y[:, i][:, None], z[:, None], ], axis=-1) - xyz = jax.vmap(project_xyz, in_axes=(None, 0, 0, None), out_axes=0)(g, w, xyz, 0) + xyz = jax.vmap(project_xyz, in_axes=(None, None, 0, 0, None), out_axes=0)(sym_group, g, w, xyz, 0) z = xyz[:, 2] Z = Z.at[:, i].set(z) @@ -146,7 +151,7 @@ def body_fn(i, state): key, W, A, X, Y, Z, L = jax.lax.fori_loop(0, n_max, body_fn, (key, W, A, X, Y, Z, L)) - M = mult_table[g-1, W] + M = sym_group.mult_table[g-1, W] num_sites = jnp.sum(A!=0, axis=1) num_atoms = jnp.sum(M, axis=1) @@ -169,7 +174,7 @@ def body_fn(i, state): L = jnp.concatenate([length, angle], axis=-1) #impose space group constraint to lattice params - L = jax.vmap(symmetrize_lattice, (None, 0))(g, L) + L = jax.vmap(sym_group.symmetrize_lattice(), (None, 0))(g, L) XYZ = jnp.concatenate([X[..., None], Y[..., None], @@ -180,13 +185,13 @@ def body_fn(i, state): return XYZ, A, W, M, L -def make_update_lattice(transformer, params, atom_types, Kl, top_p, temperature): +def make_update_lattice(sym_group, transformer, params, atom_types, Kl, top_p, temperature): @jax.jit def update_lattice(key, G, XYZ, A, W): num_sites = jnp.sum(A!=0, axis=1) # (batchsize, ) - M = jax.vmap(lambda g, w: mult_table[g-1, w], in_axes=(0, 0))(G, W) # (batchsize, n_max) + M = jax.vmap(lambda g, w: sym_group.mult_table[g-1, w], in_axes=(0, 0))(G, W) # (batchsize, n_max) #num_atoms = jnp.sum(M) batchsize = XYZ.shape[0] @@ -214,7 +219,7 @@ def update_lattice(key, G, XYZ, A, W): L = jnp.concatenate([length, angle], axis=-1) #impose space group constraint to lattice params - L = jax.vmap(symmetrize_lattice, (0, 0))(G, L) + L = jax.vmap(sym_group.symmetrize_lattice(), (0, 0))(G, L) return L diff --git a/crystalformer/src/spacegroup.py b/crystalformer/src/spacegroup.py new file mode 100644 index 0000000..43b7436 --- /dev/null +++ b/crystalformer/src/spacegroup.py @@ -0,0 +1,24 @@ +from abc import ABC, abstractmethod +from crystalformer.src.von_mises import sample_von_mises + +class SymGroup(ABC): + @abstractmethod + def sample(self): + pass + +class SpaceGroup(SymGroup): + def __init__(self): + pass + + def sample(self, key, loc, concentration, shape): + return sample_von_mises(key, loc, concentration, shape) + +class LayerGroup(SymGroup): + def __init__(self): + pass + + def sample(self, key, loc, concentration, shape): + samples = gaussian_centered(key, concentration, shape) + samples += loc + return samples + diff --git a/crystalformer/src/sym_group.py b/crystalformer/src/sym_group.py new file mode 100644 index 0000000..b74adf9 --- /dev/null +++ b/crystalformer/src/sym_group.py @@ -0,0 +1,117 @@ +import sys +sys.path.append('../../crystalformer') + +from abc import ABC, abstractmethod +import jax.numpy as jnp +from crystalformer.src.von_mises import von_mises_logpdf, sample_von_mises +from crystalformer.src.von_mises import gaussian_logpdf, sample_gaussian +from crystalformer.src.lattice import make_lattice_mask_spacegroup, make_lattice_mask_layergroup +from crystalformer.src.lattice import symmetrize_lattice_spacegroup, symmetrize_lattice_layergroup +from crystalformer.src.wyckoff import get_tables + +class SymGroup(ABC): + + @abstractmethod + def axis_name_assert(self, axis): + pass + + @abstractmethod + def distribution(self, axis): + pass + + @abstractmethod + def sample(self, axis): + pass + + @abstractmethod + def make_lattice_mask(self): + pass + + @abstractmethod + def symmetrize_lattice(self): + pass + +class SpaceGroup(SymGroup): + # sample of x,y,z should all be von mises + def __init__(self): + self.file_path = '../data/wyckoff_list.csv' + self.symops, self.mult_table, self.wmax_table, self.dof0_table, self.fc_mask_table = get_tables(self.file_path) + + def axis_name_assert(self, axis): + assert axis in {'x', 'y', 'z'}, "input error, axis needs to be 'x', 'y', or 'z'." + return None + + def distribution(self, axis): + self.axis_name_assert(axis) + return von_mises_logpdf + + def sample(self, axis): + self.axis_name_assert(axis) + return sample_von_mises + + def sample_all_dim(self): + return sample_von_mises + + def make_lattice_mask(self): + return make_lattice_mask_spacegroup + + def symmetrize_lattice(self): + return symmetrize_lattice_spacegroup + +class LayerGroup(SymGroup): + # sample of x,y should be von mises; sample of z should be gaussian + def __init__(self): + self.file_path = '../data/layer_list.csv' + self.symops, self.mult_table, self.wmax_table, self.dof0_table, self.fc_mask_table = get_tables(self.file_path) + + def axis_name_assert(self, axis): + assert axis in {'x', 'y', 'z'}, "input error, axis needs to be 'x', 'y', or 'z'." + return None + + def distribution(self, axis): + self.axis_name_assert(axis) + + if axis == 'z': + return gaussian_logpdf + else: + return von_mises_logpdf + + def sample(self, axis): + self.axis_name_assert(axis) + + if axis == 'z': + return sample_gaussian + else: + return sample_von_mises + + def sample_all_dim(self): + def sample_xyz(key, loc, concentration, shape): + sample_xy = sample_von_mises(key, loc, concentration, (*shape[0:2], 2)) + sample_z = sample_gaussian(key, loc, concentration, (*shape[0:2], 1)) + return jnp.concatenate((sample_xy, sample_z), axis=2) + return sample_xyz + + def make_lattice_mask(self): + return make_lattice_mask_layergroup + + def symmetrize_lattice(self): + return symmetrize_lattice_layergroup + + + + +if __name__ == '__main__': + from jax import random + group_str = "LayerGroup()" + a = eval(group_str) + print(type(a)) + print(type(a) == type(LayerGroup())) + print(a.mult_table) + # mask = a.make_lattice_mask()() + # print(mask) + # a = LayerGroup() + # print(type(a)) + # a.distribution('x') + # a.sample('x') + # sample = a.sample_all_dim()(random.PRNGKey(42), 0, 1, (1,5,3)) + # print(sample) \ No newline at end of file diff --git a/crystalformer/src/transformer.py b/crystalformer/src/transformer.py index cc1133f..a52afd2 100644 --- a/crystalformer/src/transformer.py +++ b/crystalformer/src/transformer.py @@ -7,9 +7,8 @@ import numpy as np from crystalformer.src.attention import MultiHeadAttention -from crystalformer.src.wyckoff import wmax_table, dof0_table -def make_transformer(key, Nf, Kx, Kl, n_max, h0_size, num_layers, num_heads, key_size, model_size, embed_size, atom_types, wyck_types, dropout_rate, widening_factor=4, sigmamin=1e-3): +def make_transformer(sym_group, key, Nf, Kx, Kl, n_max, h0_size, num_layers, num_heads, key_size, model_size, embed_size, atom_types, wyck_types, dropout_rate, widening_factor=4, sigmamin=1e-3): coord_types = 3*Kx lattice_types = Kl+2*6*Kl @@ -44,7 +43,7 @@ def network(G, XYZ, A, W, M, is_train): n = XYZ.shape[0] X, Y, Z = XYZ[:, 0], XYZ[:, 1], XYZ[:,2] - w_max = wmax_table[G-1] + w_max = sym_group.wmax_table[G-1] initializer = hk.initializers.TruncatedNormal(0.01) g_embeddings = hk.get_parameter('g_embeddings', [230, embed_size], init=initializer)[G-1] @@ -167,7 +166,7 @@ def network(G, XYZ, A, W, M, is_train): # while for Wyckoff points with zero dof it is even stronger W_0 < W_1 w_mask_less_equal = jnp.arange(1, wyck_types).reshape(1, wyck_types-1) < W[:, None] w_mask_less = jnp.arange(1, wyck_types).reshape(1, wyck_types-1) <= W[:, None] - w_mask = jnp.where((dof0_table[G-1, W])[:, None], w_mask_less, w_mask_less_equal) # (n, wyck_types-1) + w_mask = jnp.where((sym_group.dof0_table[G-1, W])[:, None], w_mask_less, w_mask_less_equal) # (n, wyck_types-1) w_mask = jnp.concatenate([jnp.zeros((n, 1)), w_mask], axis=1) # (n, wyck_types) w_logit = w_logit - jnp.where(w_mask, 1e10, 0.0) diff --git a/crystalformer/src/utils.py b/crystalformer/src/utils.py index 9efdd30..f54c2b1 100644 --- a/crystalformer/src/utils.py +++ b/crystalformer/src/utils.py @@ -9,8 +9,12 @@ import multiprocessing import os -from crystalformer.src.wyckoff import mult_table +from ase.io import read +from spglib import get_layergroup +from pyxtal.lattice import Lattice as xLattice + from crystalformer.src.elements import element_list +from crystalformer.src.sym_group import * @jax.vmap def sort_atoms(W, A, X): @@ -124,13 +128,97 @@ def process_one(cif, atom_types, wyck_types, n_max, tol=0.01): return g, l, fc, aa, ww -def GLXYZAW_from_file(csv_file, atom_types, wyck_types, n_max, num_workers=1): +def process_one_c2db(file_path, atom_types, wyck_types, n_max, tol=0.1): + crystal = read(file_path + '/structure.xyz') + la = get_layergroup((crystal.get_cell(), crystal.get_scaled_positions(), crystal.get_atomic_numbers()), symprec=tol) + g = la['number'] + l = la['std_lattice'] + map_ = la['mapping_to_primitive'] + std_map = la['std_mapping_to_primitive'] + std_pos = la['std_positions'] + std_types = la['std_types'] + std_chemical_symbols = np.array([element_list[i] for i in std_types]) + input_wyckoffs = la['wyckoffs'] + input_wyckoffs_num = [letter_to_number(w) for w in input_wyckoffs] + + assert all([type_ < atom_types for type_ in std_types]) + assert all([w < wyck_types for w in input_wyckoffs_num]) + + primitive_equivalent_idx = la['equivalent_atoms'] + + mult_list = [] + aa = [] + atom_species_list = [] + fc = [] + ww = [] + wyckoff_symbol_list = [] + + for idx in set(primitive_equivalent_idx): + full_idx, = np.where(primitive_equivalent_idx == idx) + mult = len(full_idx) + std_idx, = np.where(std_map == map_[idx]) + atom_type = list(set(std_types[std_idx])) + atom_species = list(set(std_chemical_symbols[std_idx])) + positions = std_pos[std_idx] + wyckoff_letter = list(set(np.array(input_wyckoffs)[full_idx])) + wyckoff_num = list(set(np.array(input_wyckoffs_num)[full_idx])) + + assert (len(atom_species) == 1) + assert (len(wyckoff_letter) == 1) + + mult_list.append(mult) + aa.append(atom_type[0]) + atom_species_list.append(atom_species[0]) + fc.append(positions[0]) + wyckoff_symbol = str(mult) + wyckoff_letter[0] + wyckoff_symbol_list.append(wyckoff_symbol) + ww.append(wyckoff_num[0]) + + print ('g, a, m, symbol, x:', g, atom_species[0], mult, wyckoff_num[0], wyckoff_symbol, positions) + + ordered_idx = np.argsort(ww) + ww = np.array(ww)[ordered_idx] + aa = np.array(aa)[ordered_idx] + fc = np.array(fc)[ordered_idx] + wyckoff_symbol_list = np.array(wyckoff_symbol_list)[ordered_idx] + mult_list = np.array(mult_list)[ordered_idx] + atom_species_list = np.array(atom_species_list)[ordered_idx] + + natoms = sum(mult_list) + l_pyxtal = xLattice.from_matrix(l) + abc = np.array([l_pyxtal.a, l_pyxtal.b, l_pyxtal.c]) / natoms**(1./3.) + angles = np.array([l_pyxtal.alpha, l_pyxtal.beta, l_pyxtal.gamma]) + l = np.concatenate([abc, angles]) + + print(wyckoff_symbol_list, mult_list, atom_species_list, natoms) + + num_sites = len(fc) + aa = np.concatenate([aa, + np.full((n_max - num_sites, ), 0)], + axis=0) + + ww = np.concatenate([ww, + np.full((n_max - num_sites, ), 0)], + axis=0) + fc = np.concatenate([fc, + np.full((n_max - num_sites, 3), 1e10)], + axis=0) + + print ('===================================') + + return g, l, fc, aa, ww + + + + +def GLXYZAW_from_file(sym_group, file_path, atom_types, wyck_types, n_max, num_workers=1): """ Read cif strings from csv file and convert them to G, L, XYZ, A, W Note that cif strings must be in the column 'cif' Args: - csv_file: csv file containing cif strings + sym_group: SpaceGroup() or LayerGroup() + file_path: path to the dataset atom_types: number of atom types wyck_types: number of wyckoff types n_max: maximum number of atoms in the unit cell @@ -143,14 +231,29 @@ def GLXYZAW_from_file(csv_file, atom_types, wyck_types, n_max, num_workers=1): A: atom types W: wyckoff letters """ - data = pd.read_csv(csv_file) - cif_strings = data['cif'] - - p = multiprocessing.Pool(num_workers) - partial_process_one = partial(process_one, atom_types=atom_types, wyck_types=wyck_types, n_max=n_max) - results = p.map_async(partial_process_one, cif_strings).get() - p.close() - p.join() + if type(sym_group)==type(SpaceGroup()): + data = pd.read_csv(file_path) + cif_strings = data['cif'] + # print(type(cif_strings)) + + p = multiprocessing.Pool(num_workers) + partial_process_one = partial(process_one, atom_types=atom_types, wyck_types=wyck_types, n_max=n_max) + results = p.map_async(partial_process_one, cif_strings).get() + p.close() + p.join() + elif type(sym_group)==type(LayerGroup()): + paths = os.walk(file_path) + data_list = [] + for path, _, file_list in paths: + for file_name in file_list: + if file_name == 'data.json': + data_list.append(os.path.join(path, file_name).replace('/data.json', '')) + + p = multiprocessing.Pool(num_workers) + partial_process_one_c2db = partial(process_one_c2db, atom_types=atom_types, wyck_types=wyck_types, n_max=n_max) + results = p.map_async(partial_process_one_c2db, data_list).get() + p.close() + p.join() G, L, XYZ, A, W = zip(*results) @@ -205,20 +308,50 @@ def GLXA_to_csv(G, L, X, A, num_worker=1, filename='out_structure.csv'): if __name__=='__main__': - atom_types = 119 - wyck_types = 28 - n_max = 24 + # atom_types = 119 + # wyck_types = 28 + # n_max = 24 - import numpy as np - np.set_printoptions(threshold=np.inf) + # import numpy as np + # from crystalformer.src.sym_group import * + # np.set_printoptions(threshold=np.inf) - #csv_file = '../data/mini.csv' - #csv_file = '/home/wanglei/cdvae/data/carbon_24/val.csv' - #csv_file = '/home/wanglei/cdvae/data/perov_5/val.csv' - csv_file = '/home/wanglei/cdvae/data/mp_20/train.csv' + # #csv_file = '../data/mini.csv' + # #csv_file = '/home/wanglei/cdvae/data/carbon_24/val.csv' + # #csv_file = '/home/wanglei/cdvae/data/perov_5/val.csv' + # csv_file = './mp_20/test_layer_test.csv' - G, L, XYZ, A, W = GLXYZAW_from_file(csv_file, atom_types, wyck_types, n_max) + # G, L, XYZ, A, W = GLXYZAW_from_file(SpaceGroup(), csv_file, atom_types, wyck_types, n_max) + # print (G.shape) + # print (L.shape) + # print (XYZ.shape) + # print (A.shape) + # print (W.shape) + + # print ('L:\n',L) + # print ('XYZ:\n',XYZ) + + + # @jax.vmap + # def lookup(G, W): + # return SpaceGroup().mult_table[G-1, W] # (n_max, ) + # M = lookup(G, W) # (batchsize, n_max) + # print ('N:\n', M.sum(axis=-1)) + atom_types = 119 + wyck_types = 18 + n_max = 27 + csv_file = './c2db' + + # process_one_c2db('./c2db/A/2C/1', atom_types, wyck_types, n_max) + G, L, XYZ, A, W = GLXYZAW_from_file(LayerGroup(), csv_file, atom_types, wyck_types, n_max) + + print (G.shape) + print (L.shape) + print (XYZ.shape) + print (A.shape) + print (W.shape) + print (G.shape) print (L.shape) print (XYZ.shape) @@ -231,6 +364,6 @@ def GLXA_to_csv(G, L, X, A, num_worker=1, filename='out_structure.csv'): @jax.vmap def lookup(G, W): - return mult_table[G-1, W] # (n_max, ) + return LayerGroup().mult_table[G-1, W] # (n_max, ) M = lookup(G, W) # (batchsize, n_max) print ('N:\n', M.sum(axis=-1)) diff --git a/crystalformer/src/von_mises.py b/crystalformer/src/von_mises.py index 8d45b96..d538fbf 100644 --- a/crystalformer/src/von_mises.py +++ b/crystalformer/src/von_mises.py @@ -7,6 +7,22 @@ import jax.numpy as jnp from functools import partial + + + +# ll-edit +def sample_gaussian(key, loc, concentration, shape): + standard_gaussian = random.normal(key, shape=shape) + sample = standard_gaussian / jnp.sqrt(concentration) + loc + + return sample + + + + + + + def sample_von_mises(key, loc, concentration, shape): """Generate sample from von Mises distribution @@ -81,7 +97,10 @@ def body_fn(*args): y = concentration * (s - w) v = random.uniform(key=uni_vkey, shape=shape, dtype=concentration.dtype) - accept = (y * (2.0 - y) >= v) | (jnp.log(y / v) + 1.0 >= y) + accept = (y * (2.0 - y) >= v) | (jnp.log(y / v) + 1.0 >= y) + # y/exp(y-1) >= v, y(2-y) >= v +# y = k*(s*s - 1 )/( s+cos(pi*u) ) + return i + 1, key, accept | done, u, w @@ -104,10 +123,17 @@ def von_mises_logpdf(x, loc, concentration): return -(jnp.log(2 * jnp.pi) + jnp.log(jax.scipy.special.i0e(concentration)) ) + concentration * (jnp.cos((x - loc) % (2 * jnp.pi)) - 1) +def gaussian_logpdf(x, loc, concentration): + ''' + concentration = kappa in von mises distribution = 1/variance + concentration = 1/sigma^2 in gaussian distribution + ''' + return -0.5 * (jnp.log(2 * jnp.pi) - jnp.log(concentration) + concentration * (x - loc) * (x - loc)) + if __name__=='__main__': key = jax.random.PRNGKey(42) loc = jnp.array([-1.0, 1.0, 0.0]) kappa = jnp.array([10.0, 10.0, 100.0]) x = sample_von_mises(key, loc, kappa, (3, )) - print (x) + print(type(x)) diff --git a/crystalformer/src/wyckoff.py b/crystalformer/src/wyckoff.py index b4b43a4..427c897 100644 --- a/crystalformer/src/wyckoff.py +++ b/crystalformer/src/wyckoff.py @@ -4,6 +4,7 @@ import re import jax import jax.numpy as jnp +import sys def from_xyz_str(xyz_str: str): """ @@ -12,9 +13,11 @@ def from_xyz_str(xyz_str: str): Returns: affine operator as a 3x4 array """ + # affine operator = space group = "r'=Ar+b" (rotation+translation) rot_matrix = np.zeros((3, 3)) trans = np.zeros(3) tokens = xyz_str.strip().replace(" ", "").lower().split(",") + # tokens of the form ['x','y','z'], ['-x','-y','z'], ['-2y+1/2','3x+1/2','z-y+1/2'], etc. re_rot = re.compile(r"([+-]?)([\d\.]*)/?([\d\.]*)([x-z])") re_trans = re.compile(r"([+-]?)([\d\.]+)/?([\d\.]*)(?![x-z])") for i, tok in enumerate(tokens): @@ -32,65 +35,89 @@ def from_xyz_str(xyz_str: str): trans[i] = num * factor return np.concatenate( [rot_matrix, trans[:, None]], axis=1) # (3, 4) - -df = pd.read_csv(os.path.join(os.path.dirname(__file__), '../data/wyckoff_list.csv')) -df['Wyckoff Positions'] = df['Wyckoff Positions'].apply(eval) # convert string to list -wyckoff_positions = df['Wyckoff Positions'].tolist() - -symops = np.zeros((230, 28, 576, 3, 4)) # 576 is the least common multiple for all possible mult -mult_table = np.zeros((230, 28), dtype=int) # mult_table[g-1, w] = multiplicity , 28 because we had pad 0 -wmax_table = np.zeros((230,), dtype=int) # wmax_table[g-1] = number of possible wyckoff letters for g -dof0_table = np.ones((230, 28), dtype=bool) # dof0_table[g-1, w] = True for those wyckoff points with dof = 0 (no continuous dof) -fc_mask_table = np.zeros((230, 28, 3), dtype=bool) # fc_mask_table[g-1, w] = True for continuous fc - -def build_g_code(): - #use general wyckoff position as the code for space groups - xyz_table = [] - g_table = [] - for g in range(230): - wp0 = wyckoff_positions[g][0] - g_table.append([]) - for xyz in wp0: - if xyz not in xyz_table: - xyz_table.append(xyz) - g_table[-1].append(xyz_table.index(xyz)) - assert len(g_table[-1]) == len(set(g_table[-1])) - - g_code = [] - for g in range(230): - g_code.append( [1 if i in g_table[g] else 0 for i in range(len(xyz_table))] ) - del xyz_table - del g_table - g_code = jnp.array(g_code) - return g_code - -for g in range(230): - wyckoffs = [] - for x in wyckoff_positions[g]: - wyckoffs.append([]) - for y in x: - wyckoffs[-1].append(from_xyz_str(y)) - wyckoffs = wyckoffs[::-1] # a-z,A - - mult = [len(w) for w in wyckoffs] - mult_table[g, 1:len(mult)+1] = mult - wmax_table[g] = len(mult) - - # print (g+1, [len(w) for w in wyckoffs]) - for w, wyckoff in enumerate(wyckoffs): - wyckoff = np.array(wyckoff) - repeats = symops.shape[2] // wyckoff.shape[0] - symops[g, w+1, :, :, :] = np.tile(wyckoff, (repeats, 1, 1)) - dof0_table[g, w+1] = np.linalg.matrix_rank(wyckoff[0, :3, :3]) == 0 - fc_mask_table[g, w+1] = jnp.abs(wyckoff[0, :3, :3]).sum(axis=1)!=0 - -symops = jnp.array(symops) -mult_table = jnp.array(mult_table) -wmax_table = jnp.array(wmax_table) -dof0_table = jnp.array(dof0_table) -fc_mask_table = jnp.array(fc_mask_table) - -def symmetrize_atoms(g, w, x): +# ll-edit + +def group_num(wyckoff_list): + return len(wyckoff_list) + +def max_wyckoff_letter(wyckoff_list): + return max([len(w) for w in wyckoff_list]) + +from math import lcm +def lcm_multiplicity(wyckoff_list): + mult = [] + for g in wyckoff_list: + for w in g: + mult.append(len(w)) + + return lcm(*mult) + +# def build_g_code(): +# #use general wyckoff position as the code for space groups +# xyz_table = [] +# g_table = [] +# for g in range(g_num): +# wp0 = wyckoff_positions[g][0] +# g_table.append([]) +# for xyz in wp0: +# if xyz not in xyz_table: +# xyz_table.append(xyz) +# g_table[-1].append(xyz_table.index(xyz)) +# assert len(g_table[-1]) == len(set(g_table[-1])) + +# g_code = [] +# for g in range(g_num): +# g_code.append( [1 if i in g_table[g] else 0 for i in range(len(xyz_table))] ) +# del xyz_table +# del g_table +# g_code = jnp.array(g_code) +# return g_code + +def get_tables(file_path): + df = pd.read_csv(os.path.join(os.path.dirname(__file__), file_path)) + df['Wyckoff Positions'] = df['Wyckoff Positions'].apply(eval) # convert string to list + wyckoff_positions = df['Wyckoff Positions'].tolist() + + g_num = group_num(wyckoff_positions) + max_wl = max_wyckoff_letter(wyckoff_positions) + lcm_w = lcm_multiplicity(wyckoff_positions) + # ll-edit + + symops = np.zeros((g_num, max_wl+1, lcm_w, 3, 4)) # 48 is the least common multiple for all possible mult + mult_table = np.zeros((g_num, max_wl+1), dtype=int) # mult_table[g-1, w] = multiplicity , 19 because we had pad 0 + wmax_table = np.zeros((g_num,), dtype=int) # wmax_table[g-1] = number of possible wyckoff letters for g + dof0_table = np.ones((g_num, max_wl+1), dtype=bool) # dof0_table[g-1, w] = True for those wyckoff points with dof = 0 (no continuous dof) + fc_mask_table = np.zeros((g_num, max_wl+1, 3), dtype=bool) # fc_mask_table[g-1, w] = True for continuous fc + + for g in range(g_num): + wyckoffs = [] + for x in wyckoff_positions[g]: + wyckoffs.append([]) + for y in x: + wyckoffs[-1].append(from_xyz_str(y)) + wyckoffs = wyckoffs[::-1] # a-z,A + + mult = [len(w) for w in wyckoffs] + mult_table[g, 1:len(mult)+1] = mult + wmax_table[g] = len(mult) + + # print (g+1, [len(w) for w in wyckoffs]) + for w, wyckoff in enumerate(wyckoffs): + wyckoff = np.array(wyckoff) + repeats = symops.shape[2] // wyckoff.shape[0] + symops[g, w+1, :, :, :] = np.tile(wyckoff, (repeats, 1, 1)) + dof0_table[g, w+1] = np.linalg.matrix_rank(wyckoff[0, :3, :3]) == 0 + fc_mask_table[g, w+1] = jnp.abs(wyckoff[0, :3, :3]).sum(axis=1)!=0 + + symops = jnp.array(symops) + mult_table = jnp.array(mult_table) + wmax_table = jnp.array(wmax_table) + dof0_table = jnp.array(dof0_table) + fc_mask_table = jnp.array(fc_mask_table) + + return symops, mult_table, wmax_table, dof0_table, fc_mask_table + +def symmetrize_atoms(sym_group, g, w, x): ''' symmetrize atoms via, apply all sg symmetry op, finding the generator, and lastly apply symops we need to do that because the sampled atom might not be at the first WP @@ -103,9 +130,9 @@ def symmetrize_atoms(g, w, x): ''' # (1) apply all space group symmetry op to the x - w_max = wmax_table[g-1].item() - m_max = mult_table[g-1, w_max].item() - ops = symops[g-1, w_max, :m_max] # (m_max, 3, 4) + w_max = sym_group.wmax_table[g-1].item() + m_max = sym_group.mult_table[g-1, w_max].item() + ops = sym_group.symops[g-1, w_max, :m_max] # (m_max, 3, 4) affine_point = jnp.array([*x, 1]) # (4, ) coords = ops@affine_point # (m_max, 3) coords -= jnp.floor(coords) @@ -114,62 +141,65 @@ def symmetrize_atoms(g, w, x): # here we solve it in a jit friendly way by looking for the minimal distance solution for the lhs and rhs #https://github.com/qzhu2017/PyXtal/blob/82e7d0eac1965c2713179eeda26a60cace06afc8/pyxtal/wyckoff_site.py#L115 def dist_to_op0x(coord): - diff = jnp.dot(symops[g-1, w, 0], jnp.array([*coord, 1])) - coord + diff = jnp.dot(sym_group.symops[g-1, w, 0], jnp.array([*coord, 1])) - coord diff -= jnp.rint(diff) return jnp.sum(diff**2) loc = jnp.argmin(jax.vmap(dist_to_op0x)(coords)) x = coords[loc].reshape(3,) # (3) lastly, apply the given symmetry op to x - m = mult_table[g-1, w] - ops = symops[g-1, w, :m] # (m, 3, 4) + m = sym_group.mult_table[g-1, w] + ops = sym_group.symops[g-1, w, :m] # (m, 3, 4) affine_point = jnp.array([*x, 1]) # (4, ) xs = ops@affine_point # (m, 3) xs -= jnp.floor(xs) # wrap back to 0-1 return xs if __name__=='__main__': - print (symops.shape) - print (symops.size*symops.dtype.itemsize//(1024*1024)) + from crystalformer.src.sym_group import * + + sym_group = SpaceGroup() + print (sym_group.symops.shape) + print (sym_group.symops.size*sym_group.symops.dtype.itemsize//(1024*1024)) - import numpy as np - np.set_printoptions(threshold=np.inf) + # import numpy as np + # np.set_printoptions(threshold=np.inf) - print (symops[166-1,3, :6]) - op = symops[166-1, 3, 0] - print (op) + # print (symops[166-1,3, :6]) + # op = symops[166-1, 3, 0] + # print (op) - w_max = wmax_table[225-1] - m_max = mult_table[225-1, w_max] - print ('w_max, m_max', w_max, m_max) + # w_max = wmax_table[225-1] + # m_max = mult_table[225-1, w_max] + # print ('w_max, m_max', w_max, m_max) - print (fc_mask_table[225-1, 6]) - sys.exit(0) + # print (fc_mask_table[225-1, 6]) + # # sys.exit(0) - print ('mult_table') - print (mult_table[25-1]) # space group id -> multiplicity table - print (mult_table[42-1]) - print (mult_table[47-1]) - print (mult_table[99-1]) - print (mult_table[123-1]) - print (mult_table[221-1]) - print (mult_table[166-1]) - - print ('dof0_table') - print (dof0_table[25-1]) - print (dof0_table[42-1]) - print (dof0_table[47-1]) - print (dof0_table[225-1]) - print (dof0_table[166-1]) + # print ('mult_table') + # print (mult_table[25-1]) # space group id -> multiplicity table + # print (mult_table[42-1]) + # print (mult_table[47-1]) + # print (mult_table[99-1]) + # print (mult_table[123-1]) + # print (mult_table[221-1]) + # print (mult_table[166-1]) + + # print ('dof0_table') + # print (dof0_table[25-1]) + # print (dof0_table[42-1]) + # print (dof0_table[47-1]) + # print (dof0_table[225-1]) + # print (dof0_table[166-1]) - print ('wmax_table') - print (wmax_table[47-1]) - print (wmax_table[123-1]) - print (wmax_table[166-1]) + # print ('wmax_table') + # print (wmax_table[47-1]) + # print (wmax_table[123-1]) + # print (wmax_table[166-1]) - print ('wmax_table', wmax_table) + # print ('wmax_table', wmax_table) - atom_types = 119 - aw_max = wmax_table*(atom_types-1) # the maximum value of aw - print ( (aw_max-1)%(atom_types-1)+1 ) # = 118 - print ( (aw_max-1)//(atom_types-1)+1 ) # = wmax + # atom_types = 119 + # aw_max = wmax_table*(atom_types-1) # the maximum value of aw + # print ( (aw_max-1)%(atom_types-1)+1 ) # = 118 + # print ( (aw_max-1)//(atom_types-1)+1 ) # = wmax diff --git a/err.txt b/err.txt new file mode 100644 index 0000000..5f58dbe --- /dev/null +++ b/err.txt @@ -0,0 +1,421 @@ +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['hall_number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['international']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['hall_number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['hall_number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['international']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['international']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['hall_number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['international']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 4 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 4 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['hall_number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['international']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['hall_number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['international']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['hall_number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 8 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['hall_number']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['international']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['international']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 5 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface ({self.__class__.__name__}.{key}) instead + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 4 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 2 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 8 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 4 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 4 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 12 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 8 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 12 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 8 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 4 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 8 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 6 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 12 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 12 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 12 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 10 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 4 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 8 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 16 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 2 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 16 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 12 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 8 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 7 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 6 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 16 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 12 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 12 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 24 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 2 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 8 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 2 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 4 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 16 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 6 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 3 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 24 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 2 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 16 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 24 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 1 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 2 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 10 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 24 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 3 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 20 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 1 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 1 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 3 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 1 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 10 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 2 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 30 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 2 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 24 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 6 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 6 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 16 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 24 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 10 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 6 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 16 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 24 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 5 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 6 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 5 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/core/periodic_table.py:138: UserWarning: No Pauling electronegativity for He. Setting to NaN. This has no physical meaning, and is mainly done to avoid errors caused by the code expecting a float. + warnings.warn( +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 20 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 24 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 28 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 1 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 3 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 5 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 16 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 20 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 6 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 10 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 1 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 10 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 1 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 1 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 18 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +spglib: ssm_get_exact_positions failed. +spglib: get_bravais_exact_positions_and_lattice failed. +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 17 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 7 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 3 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 32 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 10 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 3 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 7 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 18 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 18 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 7 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 14 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 28 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 10 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 40 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 14 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 7 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 14 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 32 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 5 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 20 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 20 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 20 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 26 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 3 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 18 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 20 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 7 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 30 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 18 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 14 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/pymatgen/io/cif.py:1229: UserWarning: Issues encountered while parsing CIF: 11 fractional coordinates rounded to ideal values to avoid issues with finite precision. + warnings.warn("Issues encountered while parsing CIF: " + "\n".join(self.warnings)) +Traceback (most recent call last): + File "/Users/longli/pycode/CrystalFormer/CrystalFormer/./main.py", line 95, in + train_data = GLXYZAW_from_file(args.train_path, args.atom_types, args.wyck_types, args.n_max, args.num_io_process) + File "/Users/longli/pycode/CrystalFormer/CrystalFormer/crystalformer/src/utils.py", line 151, in GLXYZAW_from_file + results = p.map_async(partial_process_one, cif_strings).get() + File "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/multiprocessing/pool.py", line 768, in get + self.wait(timeout) + File "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/multiprocessing/pool.py", line 765, in wait + self._event.wait(timeout) + File "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/threading.py", line 607, in wait + signaled = self._cond.wait(timeout) + File "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/threading.py", line 320, in wait + waiter.acquire() +KeyboardInterrupt +Exception ignored in: +Traceback (most recent call last): + File "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/jax/_src/lib/__init__.py", line 97, in _xla_gc_callback + xla_client._xla.collect_garbage() +KeyboardInterrupt: diff --git a/main.py b/main.py index 2cdb0b3..8dba58d 100644 --- a/main.py +++ b/main.py @@ -14,316 +14,330 @@ from crystalformer.src.sample import sample_crystal, make_update_lattice from crystalformer.src.loss import make_loss_fn import crystalformer.src.checkpoint as checkpoint -from crystalformer.src.wyckoff import mult_table +# from crystalformer.src.wyckoff import mult_table from crystalformer.src.mcmc import make_mcmc_step +from crystalformer.src.sym_group import * import argparse -parser = argparse.ArgumentParser(description='') - -group = parser.add_argument_group('training parameters') -group.add_argument('--epochs', type=int, default=10000, help='') -group.add_argument('--batchsize', type=int, default=100, help='') -group.add_argument('--lr', type=float, default=1e-4, help='learning rate') -group.add_argument('--lr_decay', type=float, default=0.0, help='lr decay') -group.add_argument('--weight_decay', type=float, default=0.0, help='weight decay') -group.add_argument('--clip_grad', type=float, default=1.0, help='clip gradient') -group.add_argument("--optimizer", type=str, default="adam", choices=["none", "adam", "adamw"], help="optimizer type") - -group.add_argument("--folder", default="../data/", help="the folder to save data") -group.add_argument("--restore_path", default=None, help="checkpoint path or file") - -group = parser.add_argument_group('dataset') -group.add_argument('--train_path', default='/home/wanglei/cdvae/data/mp_20/train.csv', help='') -group.add_argument('--valid_path', default='/home/wanglei/cdvae/data/mp_20/val.csv', help='') -group.add_argument('--test_path', default='/home/wanglei/cdvae/data/mp_20/test.csv', help='') - -group = parser.add_argument_group('transformer parameters') -group.add_argument('--Nf', type=int, default=5, help='number of frequencies for fc') -group.add_argument('--Kx', type=int, default=16, help='number of modes in x') -group.add_argument('--Kl', type=int, default=4, help='number of modes in lattice') -group.add_argument('--h0_size', type=int, default=256, help='hidden layer dimension for the first atom, 0 means we simply use a table for first aw_logit') -group.add_argument('--transformer_layers', type=int, default=16, help='The number of layers in transformer') -group.add_argument('--num_heads', type=int, default=16, help='The number of heads') -group.add_argument('--key_size', type=int, default=64, help='The key size') -group.add_argument('--model_size', type=int, default=64, help='The model size') -group.add_argument('--embed_size', type=int, default=32, help='The enbedding size') -group.add_argument('--dropout_rate', type=float, default=0.5, help='The dropout rate') - -group = parser.add_argument_group('loss parameters') -group.add_argument("--lamb_a", type=float, default=1.0, help="weight for the a part relative to fc") -group.add_argument("--lamb_w", type=float, default=1.0, help="weight for the w part relative to fc") -group.add_argument("--lamb_l", type=float, default=1.0, help="weight for the lattice part relative to fc") - -group = parser.add_argument_group('physics parameters') -group.add_argument('--n_max', type=int, default=21, help='The maximum number of atoms in the cell') -group.add_argument('--atom_types', type=int, default=119, help='Atom types including the padded atoms') -group.add_argument('--wyck_types', type=int, default=28, help='Number of possible multiplicites including 0') - -group = parser.add_argument_group('sampling parameters') -group.add_argument('--seed', type=int, default=None, help='random seed to sample') -group.add_argument('--spacegroup', type=int, help='The space group id to be sampled (1-230)') -group.add_argument('--wyckoff', type=str, default=None, nargs='+', help='The Wyckoff positions to be sampled, e.g. a, b') -group.add_argument('--elements', type=str, default=None, nargs='+', help='name of the chemical elemenets, e.g. Bi, Ti, O') -group.add_argument('--remove_radioactive', action='store_true', help='remove radioactive elements and noble gas') -group.add_argument('--top_p', type=float, default=1.0, help='1.0 means un-modified logits, smaller value of p give give less diverse samples') -group.add_argument('--temperature', type=float, default=1.0, help='temperature used for sampling') -group.add_argument('--T1', type=float, default=None, help='temperature used for sampling the first atom type') -group.add_argument('--num_io_process', type=int, default=40, help='number of process used in multiprocessing io') -group.add_argument('--num_samples', type=int, default=1000, help='number of test samples') -group.add_argument('--output_filename', type=str, default='output.csv', help='outfile to save sampled structures') - -group = parser.add_argument_group('MCMC parameters') -group.add_argument('--mcmc', action='store_true', help='use MCMC to sample') -group.add_argument('--nsweeps', type=int, default=10, help='number of sweeps') -group.add_argument('--mc_width', type=float, default=0.1, help='width of MCMC step') - -args = parser.parse_args() - -key = jax.random.PRNGKey(42) - -num_cpu = multiprocessing.cpu_count() -print('number of available cpu: ', num_cpu) -if args.num_io_process > num_cpu: - print('num_io_process should not exceed number of available cpu, reset to ', num_cpu) - args.num_io_process = num_cpu - - -################### Data ############################# -if args.optimizer != "none": - train_data = GLXYZAW_from_file(args.train_path, args.atom_types, args.wyck_types, args.n_max, args.num_io_process) - valid_data = GLXYZAW_from_file(args.valid_path, args.atom_types, args.wyck_types, args.n_max, args.num_io_process) -else: - assert (args.spacegroup is not None) # for inference we need to specify space group - test_data = GLXYZAW_from_file(args.test_path, args.atom_types, args.wyck_types, args.n_max, args.num_io_process) + +def main(): + # print(mult_table.shape) - # jnp.set_printoptions(threshold=jnp.inf) # print full array - constraints = jnp.arange(0, args.n_max, 1) - - if args.elements is not None: - # judge that if the input elements is a json file - if args.elements[0].endswith('.json'): - import json - with open(args.elements[0], 'r') as f: - _data = json.load(f) - atoms_list = _data["atom_mask"] - _constraints = _data["constraints"] - print(_constraints) - - for old_val, new_val in _constraints: - constraints = jnp.where(constraints == new_val, constraints[old_val], constraints) # update constraints - print("constraints", constraints) - - assert len(atoms_list) == len(args.wyckoff) - print ('sampling structure formed by these elements:', atoms_list) - atom_mask = [] - for elements in atoms_list: - idx = [element_dict[e] for e in elements] - atom_mask_ = [1] + [1 if a in idx else 0 for a in range(1, args.atom_types)] - atom_mask.append(atom_mask_) - - # padding 0 until the atom_mask shape is (args.n_max, args.atom_types) - atom_mask = jnp.array(atom_mask) - atom_mask = jnp.pad(atom_mask, ((0, args.n_max-atom_mask.shape[0]), (0, 0)), mode='constant') - print(atom_mask) + parser = argparse.ArgumentParser(description='') + + group = parser.add_argument_group('training parameters') + group.add_argument('--epochs', type=int, default=10000, help='') + group.add_argument('--batchsize', type=int, default=100, help='') + group.add_argument('--lr', type=float, default=1e-4, help='learning rate') + group.add_argument('--lr_decay', type=float, default=0.0, help='lr decay') + group.add_argument('--weight_decay', type=float, default=0.0, help='weight decay') + group.add_argument('--clip_grad', type=float, default=1.0, help='clip gradient') + group.add_argument("--optimizer", type=str, default="adam", choices=["none", "adam", "adamw"], help="optimizer type") + + group.add_argument("--folder", default="../data/", help="the folder to save data") + group.add_argument("--restore_path", default=None, help="checkpoint path or file") + + group = parser.add_argument_group('dataset') + group.add_argument('--train_path', default='/home/wanglei/cdvae/data/mp_20/train.csv', help='') + group.add_argument('--valid_path', default='/home/wanglei/cdvae/data/mp_20/val.csv', help='') + group.add_argument('--test_path', default='/home/wanglei/cdvae/data/mp_20/test.csv', help='') + + group = parser.add_argument_group('transformer parameters') + group.add_argument('--Nf', type=int, default=5, help='number of frequencies for fc') + group.add_argument('--Kx', type=int, default=16, help='number of modes in x') + group.add_argument('--Kl', type=int, default=4, help='number of modes in lattice') + group.add_argument('--h0_size', type=int, default=256, help='hidden layer dimension for the first atom, 0 means we simply use a table for first aw_logit') + group.add_argument('--transformer_layers', type=int, default=16, help='The number of layers in transformer') + group.add_argument('--num_heads', type=int, default=16, help='The number of heads') + group.add_argument('--key_size', type=int, default=64, help='The key size') + group.add_argument('--model_size', type=int, default=64, help='The model size') + group.add_argument('--embed_size', type=int, default=32, help='The enbedding size') + group.add_argument('--dropout_rate', type=float, default=0.5, help='The dropout rate') + + group = parser.add_argument_group('loss parameters') + group.add_argument("--lamb_a", type=float, default=1.0, help="weight for the a part relative to fc") + group.add_argument("--lamb_w", type=float, default=1.0, help="weight for the w part relative to fc") + group.add_argument("--lamb_l", type=float, default=1.0, help="weight for the lattice part relative to fc") + + group = parser.add_argument_group('physics parameters') + group.add_argument('--n_max', type=int, default=21, help='The maximum number of atoms in the cell') + group.add_argument('--atom_types', type=int, default=119, help='Atom types including the padded atoms') + group.add_argument('--wyck_types', type=int, default=28, help='Number of possible multiplicites including 0') + + group = parser.add_argument_group('sampling parameters') + group.add_argument('--seed', type=int, default=None, help='random seed to sample') + group.add_argument('--spacegroup', type=int, help='The space group id to be sampled (1-230)') + group.add_argument('--wyckoff', type=str, default=None, nargs='+', help='The Wyckoff positions to be sampled, e.g. a, b') + group.add_argument('--elements', type=str, default=None, nargs='+', help='name of the chemical elemenets, e.g. Bi, Ti, O') + group.add_argument('--remove_radioactive', action='store_true', help='remove radioactive elements and noble gas') + group.add_argument('--top_p', type=float, default=1.0, help='1.0 means un-modified logits, smaller value of p give give less diverse samples') + group.add_argument('--temperature', type=float, default=1.0, help='temperature used for sampling') + group.add_argument('--T1', type=float, default=None, help='temperature used for sampling the first atom type') + group.add_argument('--num_io_process', type=int, default=40, help='number of process used in multiprocessing io') + group.add_argument('--num_samples', type=int, default=1000, help='number of test samples') + group.add_argument('--output_filename', type=str, default='output.csv', help='outfile to save sampled structures') + + group = parser.add_argument_group('MCMC parameters') + group.add_argument('--mcmc', action='store_true', help='use MCMC to sample') + group.add_argument('--nsweeps', type=int, default=10, help='number of sweeps') + group.add_argument('--mc_width', type=float, default=0.1, help='width of MCMC step') + + group = parser.add_argument_group("Symmetry group type") + group.add_argument('--sym_group', type=str, default="SpaceGroup", help='type of symmetry group, can be "SpaceGroup" or "LayerGroup".') + + args = parser.parse_args() + + assert args.sym_group in {"SpaceGroup", "LayerGroup"}, 'input error, --sym_group can only be "SpaceGroup()" or "LayerGroup()".' + sym_group = eval(args.sym_group + "()") + + key = jax.random.PRNGKey(42) + + num_cpu = multiprocessing.cpu_count() + print('number of available cpu: ', num_cpu) + if args.num_io_process > num_cpu: + print('num_io_process should not exceed number of available cpu, reset to ', num_cpu) + args.num_io_process = num_cpu + + + ################### Data ############################# + if args.optimizer != "none": + train_data = GLXYZAW_from_file(sym_group, args.train_path, args.atom_types, args.wyck_types, args.n_max, args.num_io_process) + valid_data = GLXYZAW_from_file(sym_group, args.valid_path, args.atom_types, args.wyck_types, args.n_max, args.num_io_process) + else: + assert (args.spacegroup is not None) # for inference we need to specify space group + test_data = GLXYZAW_from_file(sym_group, args.test_path, args.atom_types, args.wyck_types, args.n_max, args.num_io_process) + + # jnp.set_printoptions(threshold=jnp.inf) # print full array + constraints = jnp.arange(0, args.n_max, 1) + + if args.elements is not None: + # judge that if the input elements is a json file + if args.elements[0].endswith('.json'): + import json + with open(args.elements[0], 'r') as f: + _data = json.load(f) + atoms_list = _data["atom_mask"] + _constraints = _data["constraints"] + print(_constraints) + + for old_val, new_val in _constraints: + constraints = jnp.where(constraints == new_val, constraints[old_val], constraints) # update constraints + print("constraints", constraints) + + assert len(atoms_list) == len(args.wyckoff) + print ('sampling structure formed by these elements:', atoms_list) + atom_mask = [] + for elements in atoms_list: + idx = [element_dict[e] for e in elements] + atom_mask_ = [1] + [1 if a in idx else 0 for a in range(1, args.atom_types)] + atom_mask.append(atom_mask_) + + # padding 0 until the atom_mask shape is (args.n_max, args.atom_types) + atom_mask = jnp.array(atom_mask) + atom_mask = jnp.pad(atom_mask, ((0, args.n_max-atom_mask.shape[0]), (0, 0)), mode='constant') + print(atom_mask) + else: + idx = [element_dict[e] for e in args.elements] + atom_mask = [1] + [1 if a in idx else 0 for a in range(1, args.atom_types)] + atom_mask = jnp.array(atom_mask) + atom_mask = jnp.stack([atom_mask] * args.n_max, axis=0) + print ('sampling structure formed by these elements:', args.elements) + print (atom_mask) + + else: + if args.remove_radioactive: + from crystalformer.src.elements import radioactive_elements_dict, noble_gas_dict + # remove radioactive elements and noble gas + atom_mask = [1] + [1 if i not in radioactive_elements_dict.values() and i not in noble_gas_dict.values() else 0 for i in range(1, args.atom_types)] + atom_mask = jnp.array(atom_mask) + atom_mask = jnp.stack([atom_mask] * args.n_max, axis=0) + print('sampling structure formed by non-radioactive elements and non-noble gas') + print(atom_mask) + + else: + atom_mask = jnp.zeros((args.atom_types), dtype=int) # we will do nothing to a_logit in sampling + atom_mask = jnp.stack([atom_mask] * args.n_max, axis=0) + print(atom_mask) + # print(f'there is total {jnp.sum(atom_mask)-1} elements') + print(atom_mask.shape) + + if args.wyckoff is not None: + idx = [letter_to_number(w) for w in args.wyckoff] + # padding 0 until the length is args.n_max + w_mask = idx + [0]*(args.n_max -len(idx)) + # w_mask = [1 if w in idx else 0 for w in range(1, args.wyck_types+1)] + w_mask = jnp.array(w_mask, dtype=int) + print ('sampling structure formed by these Wyckoff positions:', args.wyckoff) + print (w_mask) else: - idx = [element_dict[e] for e in args.elements] - atom_mask = [1] + [1 if a in idx else 0 for a in range(1, args.atom_types)] - atom_mask = jnp.array(atom_mask) - atom_mask = jnp.stack([atom_mask] * args.n_max, axis=0) - print ('sampling structure formed by these elements:', args.elements) - print (atom_mask) + w_mask = None + + ################### Model ############################# + params, transformer = make_transformer(sym_group, key, args.Nf, args.Kx, args.Kl, args.n_max, + args.h0_size, + args.transformer_layers, args.num_heads, + args.key_size, args.model_size, args.embed_size, + args.atom_types, args.wyck_types, + args.dropout_rate) + transformer_name = 'Nf_%d_Kx_%d_Kl_%d_h0_%d_l_%d_H_%d_k_%d_m_%d_e_%d_drop_%g'%(args.Nf, args.Kx, args.Kl, args.h0_size, args.transformer_layers, args.num_heads, args.key_size, args.model_size, args.embed_size, args.dropout_rate) + + print ("# of transformer params", ravel_pytree(params)[0].size) + + ################### Train ############################# + + loss_fn, logp_fn = make_loss_fn(sym_group, args.n_max, args.atom_types, args.wyck_types, args.Kx, args.Kl, transformer, args.lamb_a, args.lamb_w, args.lamb_l) + + print("\n========== Prepare logs ==========") + if args.optimizer != "none" or args.restore_path is None: + output_path = args.folder + args.optimizer+"_bs_%d_lr_%g_decay_%g_clip_%g" % (args.batchsize, args.lr, args.lr_decay, args.clip_grad) \ + + '_A_%g_W_%g_N_%g'%(args.atom_types, args.wyck_types, args.n_max) \ + + ("_wd_%g"%(args.weight_decay) if args.optimizer == "adamw" else "") \ + + ('_a_%g_w_%g_l_%g'%(args.lamb_a, args.lamb_w, args.lamb_l)) \ + + "_" + transformer_name + os.makedirs(output_path, exist_ok=True) + print("Create directory for output: %s" % output_path) else: - if args.remove_radioactive: - from crystalformer.src.elements import radioactive_elements_dict, noble_gas_dict - # remove radioactive elements and noble gas - atom_mask = [1] + [1 if i not in radioactive_elements_dict.values() and i not in noble_gas_dict.values() else 0 for i in range(1, args.atom_types)] - atom_mask = jnp.array(atom_mask) - atom_mask = jnp.stack([atom_mask] * args.n_max, axis=0) - print('sampling structure formed by non-radioactive elements and non-noble gas') - print(atom_mask) - - else: - atom_mask = jnp.zeros((args.atom_types), dtype=int) # we will do nothing to a_logit in sampling - atom_mask = jnp.stack([atom_mask] * args.n_max, axis=0) - print(atom_mask) - # print(f'there is total {jnp.sum(atom_mask)-1} elements') - print(atom_mask.shape) - - if args.wyckoff is not None: - idx = [letter_to_number(w) for w in args.wyckoff] - # padding 0 until the length is args.n_max - w_mask = idx + [0]*(args.n_max -len(idx)) - # w_mask = [1 if w in idx else 0 for w in range(1, args.wyck_types+1)] - w_mask = jnp.array(w_mask, dtype=int) - print ('sampling structure formed by these Wyckoff positions:', args.wyckoff) - print (w_mask) + output_path = os.path.dirname(args.restore_path) + print("Will output samples to: %s" % output_path) + + + print("\n========== Load checkpoint==========") + ckpt_filename, epoch_finished = checkpoint.find_ckpt_filename(args.restore_path or output_path) + if ckpt_filename is not None: + print("Load checkpoint file: %s, epoch finished: %g" %(ckpt_filename, epoch_finished)) + ckpt = checkpoint.load_data(ckpt_filename) + params = ckpt["params"] else: - w_mask = None - -################### Model ############################# -params, transformer = make_transformer(key, args.Nf, args.Kx, args.Kl, args.n_max, - args.h0_size, - args.transformer_layers, args.num_heads, - args.key_size, args.model_size, args.embed_size, - args.atom_types, args.wyck_types, - args.dropout_rate) -transformer_name = 'Nf_%d_Kx_%d_Kl_%d_h0_%d_l_%d_H_%d_k_%d_m_%d_e_%d_drop_%g'%(args.Nf, args.Kx, args.Kl, args.h0_size, args.transformer_layers, args.num_heads, args.key_size, args.model_size, args.embed_size, args.dropout_rate) - -print ("# of transformer params", ravel_pytree(params)[0].size) - -################### Train ############################# - -loss_fn, logp_fn = make_loss_fn(args.n_max, args.atom_types, args.wyck_types, args.Kx, args.Kl, transformer, args.lamb_a, args.lamb_w, args.lamb_l) - -print("\n========== Prepare logs ==========") -if args.optimizer != "none" or args.restore_path is None: - output_path = args.folder + args.optimizer+"_bs_%d_lr_%g_decay_%g_clip_%g" % (args.batchsize, args.lr, args.lr_decay, args.clip_grad) \ - + '_A_%g_W_%g_N_%g'%(args.atom_types, args.wyck_types, args.n_max) \ - + ("_wd_%g"%(args.weight_decay) if args.optimizer == "adamw" else "") \ - + ('_a_%g_w_%g_l_%g'%(args.lamb_a, args.lamb_w, args.lamb_l)) \ - + "_" + transformer_name - - os.makedirs(output_path, exist_ok=True) - print("Create directory for output: %s" % output_path) -else: - output_path = os.path.dirname(args.restore_path) - print("Will output samples to: %s" % output_path) - - -print("\n========== Load checkpoint==========") -ckpt_filename, epoch_finished = checkpoint.find_ckpt_filename(args.restore_path or output_path) -if ckpt_filename is not None: - print("Load checkpoint file: %s, epoch finished: %g" %(ckpt_filename, epoch_finished)) - ckpt = checkpoint.load_data(ckpt_filename) - params = ckpt["params"] -else: - print("No checkpoint file found. Start from scratch.") - -if args.optimizer != "none": - - schedule = lambda t: args.lr/(1+args.lr_decay*t) - - if args.optimizer == "adam": - optimizer = optax.chain(optax.clip_by_global_norm(args.clip_grad), - optax.scale_by_adam(), - optax.scale_by_schedule(schedule), - optax.scale(-1.)) - elif args.optimizer == 'adamw': - optimizer = optax.chain(optax.clip(args.clip_grad), - optax.adamw(learning_rate=schedule, weight_decay=args.weight_decay) - ) - - opt_state = optimizer.init(params) - try: - opt_state.update(ckpt["opt_state"]) - except: - print ("failed to update opt_state from checkpoint") - pass - - print("\n========== Start training ==========") - params, opt_state = train(key, optimizer, opt_state, loss_fn, params, epoch_finished, args.epochs, args.batchsize, train_data, valid_data, output_path) - -else: - pass - - print("\n========== Calculate the loss of test dataset ==========") - import numpy as np - np.set_printoptions(threshold=np.inf) - - test_G, test_L, test_XYZ, test_A, test_W = test_data - print (test_G.shape, test_L.shape, test_XYZ.shape, test_A.shape, test_W.shape) - test_loss = 0 - num_samples = len(test_L) - num_batches = math.ceil(num_samples / args.batchsize) - for batch_idx in range(num_batches): - start_idx = batch_idx * args.batchsize - end_idx = min(start_idx + args.batchsize, num_samples) - G, L, XYZ, A, W = test_G[start_idx:end_idx], \ - test_L[start_idx:end_idx], \ - test_XYZ[start_idx:end_idx], \ - test_A[start_idx:end_idx], \ - test_W[start_idx:end_idx] - loss, _ = jax.jit(loss_fn, static_argnums=7)(params, key, G, L, XYZ, A, W, False) - test_loss += loss - test_loss = test_loss / num_batches - print ("evaluating loss on test data:" , test_loss) - - print("\n========== Start sampling ==========") - jax.config.update("jax_enable_x64", True) # to get off compilation warning, and to prevent sample nan lattice - #FYI, the error was [Compiling module extracted] Very slow compile? If you want to file a bug, run with envvar XLA_FLAGS=--xla_dump_to=/tmp/foo and attach the results. - - if args.seed is not None: - key = jax.random.PRNGKey(args.seed) # reset key for sampling if seed is provided + print("No checkpoint file found. Start from scratch.") + + if args.optimizer != "none": + + schedule = lambda t: args.lr/(1+args.lr_decay*t) + + if args.optimizer == "adam": + optimizer = optax.chain(optax.clip_by_global_norm(args.clip_grad), + optax.scale_by_adam(), + optax.scale_by_schedule(schedule), + optax.scale(-1.)) + elif args.optimizer == 'adamw': + optimizer = optax.chain(optax.clip(args.clip_grad), + optax.adamw(learning_rate=schedule, weight_decay=args.weight_decay) + ) + + opt_state = optimizer.init(params) + try: + opt_state.update(ckpt["opt_state"]) + except: + print ("failed to update opt_state from checkpoint") + pass - if args.T1 is not None: - T1 = args.T1 - else: - T1 = args.temperature - - mc_steps = args.nsweeps * args.n_max - print("mc_steps", mc_steps) - mcmc = make_mcmc_step(params, n_max=args.n_max, atom_types=args.atom_types, atom_mask=atom_mask, constraints=constraints) - update_lattice = make_update_lattice(transformer, params, args.atom_types, args.Kl, args.top_p, args.temperature) - - num_batches = math.ceil(args.num_samples / args.batchsize) - name, extension = args.output_filename.rsplit('.', 1) - filename = os.path.join(output_path, - f"{name}_{args.spacegroup}.{extension}") - for batch_idx in range(num_batches): - start_idx = batch_idx * args.batchsize - end_idx = min(start_idx + args.batchsize, args.num_samples) - n_sample = end_idx - start_idx - key, subkey = jax.random.split(key) - XYZ, A, W, M, L = sample_crystal(subkey, transformer, params, args.n_max, n_sample, args.atom_types, args.wyck_types, args.Kx, args.Kl, args.spacegroup, w_mask, atom_mask, args.top_p, args.temperature, T1, constraints) - - G = args.spacegroup * jnp.ones((n_sample), dtype=int) - if args.mcmc: - x = (G, L, XYZ, A, W) - key, subkey = jax.random.split(key) - x, acc = mcmc(logp_fn, x_init=x, key=subkey, mc_steps=mc_steps, mc_width=args.mc_width) - print("acc", acc) + print("\n========== Start training ==========") + params, opt_state = train(key, optimizer, opt_state, loss_fn, params, epoch_finished, args.epochs, args.batchsize, train_data, valid_data, output_path) - G, L, XYZ, A, W = x - key, subkey = jax.random.split(key) - L = update_lattice(subkey, G, XYZ, A, W) + else: + pass + + print("\n========== Calculate the loss of test dataset ==========") + import numpy as np + np.set_printoptions(threshold=np.inf) + + test_G, test_L, test_XYZ, test_A, test_W = test_data + print (test_G.shape, test_L.shape, test_XYZ.shape, test_A.shape, test_W.shape) + test_loss = 0 + num_samples = len(test_L) + num_batches = math.ceil(num_samples / args.batchsize) + for batch_idx in range(num_batches): + start_idx = batch_idx * args.batchsize + end_idx = min(start_idx + args.batchsize, num_samples) + G, L, XYZ, A, W = test_G[start_idx:end_idx], \ + test_L[start_idx:end_idx], \ + test_XYZ[start_idx:end_idx], \ + test_A[start_idx:end_idx], \ + test_W[start_idx:end_idx] + loss, _ = jax.jit(loss_fn, static_argnums=7)(params, key, G, L, XYZ, A, W, False) + test_loss += loss + test_loss = test_loss / num_batches + print ("evaluating loss on test data:" , test_loss) + + print("\n========== Start sampling ==========") + jax.config.update("jax_enable_x64", True) # to get off compilation warning, and to prevent sample nan lattice + #FYI, the error was [Compiling module extracted] Very slow compile? If you want to file a bug, run with envvar XLA_FLAGS=--xla_dump_to=/tmp/foo and attach the results. + + if args.seed is not None: + key = jax.random.PRNGKey(args.seed) # reset key for sampling if seed is provided - print ("XYZ:\n", XYZ) # fractional coordinate - print ("A:\n", A) # element type - print ("W:\n", W) # Wyckoff positions - print ("M:\n", M) # multiplicity - print ("N:\n", M.sum(axis=-1)) # total number of atoms - print ("L:\n", L) # lattice - for a in A: - print([element_list[i] for i in a]) - - # output L, X, A, W, M, AW to csv file - # output logp_w, logp_xyz, logp_a, logp_l to csv file - import pandas as pd - data = pd.DataFrame() - data['L'] = np.array(L).tolist() - data['X'] = np.array(XYZ).tolist() - data['A'] = np.array(A).tolist() - data['W'] = np.array(W).tolist() - data['M'] = np.array(M).tolist() - - num_atoms = jnp.sum(M, axis=1) - length, angle = jnp.split(L, 2, axis=-1) - length = length/num_atoms[:, None]**(1/3) - angle = angle * (jnp.pi / 180) # to rad - L = jnp.concatenate([length, angle], axis=-1) - - # G = args.spacegroup * jnp.ones((n_sample), dtype=int) - logp_w, logp_xyz, logp_a, logp_l = jax.jit(logp_fn, static_argnums=7)(params, key, G, L, XYZ, A, W, False) - - data['logp_w'] = np.array(logp_w).tolist() - data['logp_xyz'] = np.array(logp_xyz).tolist() - data['logp_a'] = np.array(logp_a).tolist() - data['logp_l'] = np.array(logp_l).tolist() - data['logp'] = np.array(logp_xyz + args.lamb_w*logp_w + args.lamb_a*logp_a + args.lamb_l*logp_l).tolist() - - data = data.sort_values(by='logp', ascending=False) # sort by logp - header = False if os.path.exists(filename) else True - data.to_csv(filename, mode='a', index=False, header=header) - - print ("Wrote samples to %s"%filename) + if args.T1 is not None: + T1 = args.T1 + else: + T1 = args.temperature + + mc_steps = args.nsweeps * args.n_max + print("mc_steps", mc_steps) + mcmc = make_mcmc_step(params, n_max=args.n_max, atom_types=args.atom_types, sym_group=LayerGroup(), atom_mask=atom_mask, constraints=constraints) + update_lattice = make_update_lattice(sym_group, transformer, params, args.atom_types, args.Kl, args.top_p, args.temperature) + + num_batches = math.ceil(args.num_samples / args.batchsize) + name, extension = args.output_filename.rsplit('.', 1) + filename = os.path.join(output_path, + f"{name}_{args.spacegroup}.{extension}") + for batch_idx in range(num_batches): + start_idx = batch_idx * args.batchsize + end_idx = min(start_idx + args.batchsize, args.num_samples) + n_sample = end_idx - start_idx + key, subkey = jax.random.split(key) + XYZ, A, W, M, L = sample_crystal(sym_group, subkey, transformer, params, args.n_max, n_sample, args.atom_types, args.wyck_types, args.Kx, args.Kl, args.spacegroup, w_mask, atom_mask, args.top_p, args.temperature, T1, constraints) + + G = args.spacegroup * jnp.ones((n_sample), dtype=int) + if args.mcmc: + x = (G, L, XYZ, A, W) + key, subkey = jax.random.split(key) + x, acc = mcmc(logp_fn, x_init=x, key=subkey, mc_steps=mc_steps, mc_width=args.mc_width) + print("acc", acc) + + G, L, XYZ, A, W = x + key, subkey = jax.random.split(key) + L = update_lattice(subkey, G, XYZ, A, W) + + print ("XYZ:\n", XYZ) # fractional coordinate + print ("A:\n", A) # element type + print ("W:\n", W) # Wyckoff positions + print ("M:\n", M) # multiplicity + print ("N:\n", M.sum(axis=-1)) # total number of atoms + print ("L:\n", L) # lattice + for a in A: + print([element_list[i] for i in a]) + + # output L, X, A, W, M, AW to csv file + # output logp_w, logp_xyz, logp_a, logp_l to csv file + import pandas as pd + data = pd.DataFrame() + data['L'] = np.array(L).tolist() + data['X'] = np.array(XYZ).tolist() + data['A'] = np.array(A).tolist() + data['W'] = np.array(W).tolist() + data['M'] = np.array(M).tolist() + + num_atoms = jnp.sum(M, axis=1) + length, angle = jnp.split(L, 2, axis=-1) + length = length/num_atoms[:, None]**(1/3) + angle = angle * (jnp.pi / 180) # to rad + L = jnp.concatenate([length, angle], axis=-1) + + # G = args.spacegroup * jnp.ones((n_sample), dtype=int) + logp_w, logp_xyz, logp_a, logp_l = jax.jit(logp_fn, static_argnums=7)(params, key, G, L, XYZ, A, W, False) + + data['logp_w'] = np.array(logp_w).tolist() + data['logp_xyz'] = np.array(logp_xyz).tolist() + data['logp_a'] = np.array(logp_a).tolist() + data['logp_l'] = np.array(logp_l).tolist() + data['logp'] = np.array(logp_xyz + args.lamb_w*logp_w + args.lamb_a*logp_a + args.lamb_l*logp_l).tolist() + + data = data.sort_values(by='logp', ascending=False) # sort by logp + header = False if os.path.exists(filename) else True + data.to_csv(filename, mode='a', index=False, header=header) + + print ("Wrote samples to %s"%filename) + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/mp_20/test_copy.csv b/mp_20/test_copy.csv new file mode 100644 index 0000000..11e6575 --- /dev/null +++ b/mp_20/test_copy.csv @@ -0,0 +1,36 @@ +,material_id,formation_energy_per_atom,band_gap,pretty_formula,e_above_hull,elements,cif,spacegroup.number +6000,mp-10009,-0.5750923537499997,0.8979999999999997,GaTe,0.0,"['Ga', 'Te']","# generated using pymatgen +data_GaTe +_symmetry_space_group_name_H-M 'P 1' +_cell_length_a 4.13459945 +_cell_length_b 4.13459945 +_cell_length_c 18.42557000 +_cell_angle_alpha 90.00000000 +_cell_angle_beta 90.00000000 +_cell_angle_gamma 119.99999121 +_symmetry_Int_Tables_number 1 +_chemical_formula_structural GaTe +_chemical_formula_sum 'Ga4 Te4' +_cell_volume 272.78374478 +_cell_formula_units_Z 4 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' +loop_ + _atom_site_type_symbol + _atom_site_label + _atom_site_symmetry_multiplicity + _atom_site_fract_x + _atom_site_fract_y + _atom_site_fract_z + _atom_site_occupancy + Ga Ga0 1 0.33333300 0.66666700 0.18295900 1 + Ga Ga1 1 0.66666700 0.33333300 0.68295900 1 + Ga Ga2 1 0.66666700 0.33333300 0.81704100 1 + Ga Ga3 1 0.33333300 0.66666700 0.31704100 1 + Te Te4 1 0.33333300 0.66666700 0.88620400 1 + Te Te5 1 0.66666700 0.33333300 0.38620400 1 + Te Te6 1 0.66666700 0.33333300 0.11379600 1 + Te Te7 1 0.33333300 0.66666700 0.61379600 1 +",194 \ No newline at end of file diff --git a/mp_20/test_layer_test.csv b/mp_20/test_layer_test.csv new file mode 100644 index 0000000..ea038bc --- /dev/null +++ b/mp_20/test_layer_test.csv @@ -0,0 +1,36 @@ +,material_id,formation_energy_per_atom,band_gap,pretty_formula,e_above_hull,elements,cif,spacegroup.number +6000,mp-10009,-0.5750923537499997,0.8979999999999997,GaTe,0.0,"['Ga', 'Te']","# generated using pymatgen +data_GaTe +_symmetry_space_group_name_H-M 'P 1' +_cell_length_a 4.13459945 +_cell_length_b 4.13459945 +_cell_length_c 18.42557000 +_cell_angle_alpha 90.00000000 +_cell_angle_beta 90.00000000 +_cell_angle_gamma 119.99999121 +_symmetry_Int_Tables_number 1 +_chemical_formula_structural GaTe +_chemical_formula_sum 'Ga4 Te4' +_cell_volume 272.78374478 +_cell_formula_units_Z 4 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' +loop_ + _atom_site_type_symbol + _atom_site_label + _atom_site_symmetry_multiplicity + _atom_site_fract_x + _atom_site_fract_y + _atom_site_fract_z + _atom_site_occupancy + Ga Ga0 1 0.33333300 0.66666700 0.18295900 1 + Ga Ga1 1 0.66666700 0.33333300 0.68295900 1 + Ga Ga2 1 0.66666700 0.33333300 0.81704100 1 + Ga Ga3 1 0.33333300 0.66666700 0.31704100 1 + Te Te4 1 0.33333300 0.66666700 0.88620400 1 + Te Te5 1 0.66666700 0.33333300 0.38620400 1 + Te Te6 1 0.66666700 0.33333300 0.11379600 1 + Te Te7 1 0.33333300 0.66666700 0.61379600 1 +",19 \ No newline at end of file diff --git a/mp_20/train_copy.csv b/mp_20/train_copy.csv new file mode 100644 index 0000000..3891ae8 --- /dev/null +++ b/mp_20/train_copy.csv @@ -0,0 +1,40 @@ +,material_id,formation_energy_per_atom,band_gap,pretty_formula,e_above_hull,elements,cif,spacegroup.number +37228,mp-1221227,-1.637460082715517,0.2132999999999998,Na3MnCoNiO6,0.0430011104166663,"['Co', 'Mn', 'Na', 'Ni', 'O']","# generated using pymatgen +data_Na3MnCoNiO6 +_symmetry_space_group_name_H-M 'P 1' +_cell_length_a 7.97762755 +_cell_length_b 7.97762755 +_cell_length_c 5.63711369 +_cell_angle_alpha 72.48857871 +_cell_angle_beta 72.48857871 +_cell_angle_gamma 21.88936910 +_symmetry_Int_Tables_number 1 +_chemical_formula_structural Na3MnCoNiO6 +_chemical_formula_sum 'Na3 Mn1 Co1 Ni1 O6' +_cell_volume 127.31533261 +_cell_formula_units_Z 1 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' +loop_ + _atom_site_type_symbol + _atom_site_label + _atom_site_symmetry_multiplicity + _atom_site_fract_x + _atom_site_fract_y + _atom_site_fract_z + _atom_site_occupancy + Na Na0 1 0.33348900 0.33348900 0.00178500 1 + Na Na1 1 0.99987700 0.99987700 0.99972500 1 + Na Na2 1 0.66797500 0.66797500 0.99566200 1 + Mn Mn3 1 0.50017700 0.50017700 0.50073300 1 + Co Co4 1 0.82626400 0.82626400 0.49349200 1 + Ni Ni5 1 0.16703600 0.16703600 0.50580000 1 + O O6 1 0.92768300 0.92768300 0.69008100 1 + O O7 1 0.58132100 0.58132100 0.69828000 1 + O O8 1 0.25880500 0.25880500 0.71081800 1 + O O9 1 0.07075400 0.07075400 0.30547000 1 + O O10 1 0.75122900 0.75122900 0.29142500 1 + O O11 1 0.41538900 0.41538900 0.30672800 1 +",8 \ No newline at end of file diff --git a/mp_20/train_layer_test.csv b/mp_20/train_layer_test.csv new file mode 100644 index 0000000..3891ae8 --- /dev/null +++ b/mp_20/train_layer_test.csv @@ -0,0 +1,40 @@ +,material_id,formation_energy_per_atom,band_gap,pretty_formula,e_above_hull,elements,cif,spacegroup.number +37228,mp-1221227,-1.637460082715517,0.2132999999999998,Na3MnCoNiO6,0.0430011104166663,"['Co', 'Mn', 'Na', 'Ni', 'O']","# generated using pymatgen +data_Na3MnCoNiO6 +_symmetry_space_group_name_H-M 'P 1' +_cell_length_a 7.97762755 +_cell_length_b 7.97762755 +_cell_length_c 5.63711369 +_cell_angle_alpha 72.48857871 +_cell_angle_beta 72.48857871 +_cell_angle_gamma 21.88936910 +_symmetry_Int_Tables_number 1 +_chemical_formula_structural Na3MnCoNiO6 +_chemical_formula_sum 'Na3 Mn1 Co1 Ni1 O6' +_cell_volume 127.31533261 +_cell_formula_units_Z 1 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' +loop_ + _atom_site_type_symbol + _atom_site_label + _atom_site_symmetry_multiplicity + _atom_site_fract_x + _atom_site_fract_y + _atom_site_fract_z + _atom_site_occupancy + Na Na0 1 0.33348900 0.33348900 0.00178500 1 + Na Na1 1 0.99987700 0.99987700 0.99972500 1 + Na Na2 1 0.66797500 0.66797500 0.99566200 1 + Mn Mn3 1 0.50017700 0.50017700 0.50073300 1 + Co Co4 1 0.82626400 0.82626400 0.49349200 1 + Ni Ni5 1 0.16703600 0.16703600 0.50580000 1 + O O6 1 0.92768300 0.92768300 0.69008100 1 + O O7 1 0.58132100 0.58132100 0.69828000 1 + O O8 1 0.25880500 0.25880500 0.71081800 1 + O O9 1 0.07075400 0.07075400 0.30547000 1 + O O10 1 0.75122900 0.75122900 0.29142500 1 + O O11 1 0.41538900 0.41538900 0.30672800 1 +",8 \ No newline at end of file diff --git a/mp_20/val_copy.csv b/mp_20/val_copy.csv new file mode 100644 index 0000000..387afa2 --- /dev/null +++ b/mp_20/val_copy.csv @@ -0,0 +1,32 @@ +,material_id,formation_energy_per_atom,band_gap,pretty_formula,e_above_hull,elements,cif,spacegroup.number +65,mp-865981,-0.4363681541666666,0.0,TmMgHg2,0.0,"['Hg', 'Mg', 'Tm']","# generated using pymatgen +data_TmMgHg2 +_symmetry_space_group_name_H-M 'P 1' +_cell_length_a 5.04880040 +_cell_length_b 5.04880040 +_cell_length_c 5.04880040 +_cell_angle_alpha 60.00000000 +_cell_angle_beta 60.00000000 +_cell_angle_gamma 60.00000000 +_symmetry_Int_Tables_number 1 +_chemical_formula_structural TmMgHg2 +_chemical_formula_sum 'Tm1 Mg1 Hg2' +_cell_volume 91.00172128 +_cell_formula_units_Z 1 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' +loop_ + _atom_site_type_symbol + _atom_site_label + _atom_site_symmetry_multiplicity + _atom_site_fract_x + _atom_site_fract_y + _atom_site_fract_z + _atom_site_occupancy + Tm Tm0 1 0.00000000 0.00000000 0.00000000 1 + Mg Mg1 1 0.50000000 0.50000000 0.50000000 1 + Hg Hg2 1 0.25000000 0.25000000 0.25000000 1 + Hg Hg3 1 0.75000000 0.75000000 0.75000000 1 +",225 \ No newline at end of file diff --git a/mp_20/val_layer_test.csv b/mp_20/val_layer_test.csv new file mode 100644 index 0000000..7762a98 --- /dev/null +++ b/mp_20/val_layer_test.csv @@ -0,0 +1,32 @@ +,material_id,formation_energy_per_atom,band_gap,pretty_formula,e_above_hull,elements,cif,spacegroup.number +65,mp-865981,-0.4363681541666666,0.0,TmMgHg2,0.0,"['Hg', 'Mg', 'Tm']","# generated using pymatgen +data_TmMgHg2 +_symmetry_space_group_name_H-M 'P 1' +_cell_length_a 5.04880040 +_cell_length_b 5.04880040 +_cell_length_c 5.04880040 +_cell_angle_alpha 60.00000000 +_cell_angle_beta 60.00000000 +_cell_angle_gamma 60.00000000 +_symmetry_Int_Tables_number 1 +_chemical_formula_structural TmMgHg2 +_chemical_formula_sum 'Tm1 Mg1 Hg2' +_cell_volume 91.00172128 +_cell_formula_units_Z 1 +loop_ + _symmetry_equiv_pos_site_id + _symmetry_equiv_pos_as_xyz + 1 'x, y, z' +loop_ + _atom_site_type_symbol + _atom_site_label + _atom_site_symmetry_multiplicity + _atom_site_fract_x + _atom_site_fract_y + _atom_site_fract_z + _atom_site_occupancy + Tm Tm0 1 0.00000000 0.00000000 0.00000000 1 + Mg Mg1 1 0.50000000 0.50000000 0.50000000 1 + Hg Hg2 1 0.25000000 0.25000000 0.25000000 1 + Hg Hg3 1 0.75000000 0.75000000 0.75000000 1 +",25 \ No newline at end of file diff --git a/runcode.sh b/runcode.sh new file mode 100755 index 0000000..b53c61d --- /dev/null +++ b/runcode.sh @@ -0,0 +1,13 @@ +#!/bin/zsh +conda init +conda activate crystalformer +python ./main.py --folder ./data/ --train_path ./mp_20/train_layer_test.csv --valid_path ./mp_20/val_layer_test.csv --epochs 200 +python ./main.py --optimizer none --test_path ./mp_20/test_layer_test.csv --restore_path ./data/adam_bs_100_lr_0.0001_decay_0_clip_1_A_119_W_28_N_21_a_1_w_1_l_1_Nf_5_Kx_16_Kl_4_h0_256_l_16_H_16_k_64_m_64_e_32_drop_0.5/epoch_000100.pkl --spacegroup 65 --num_samples 10 --batchsize 200 --temperature 1.0 --elements C + + + +python ./main.py --folder ./data/ --train_path ./c2db --valid_path ./c2db --sym_group LayerGroup --epochs 200 + +python ./main.py --optimizer none --test_path ./mp_20/test_layer_test.csv --restore_path ./data/test/epoch_000100.pkl --spacegroup 61 --num_samples 10 --batchsize 200 --temperature 1.0 --elements H O + +python ./scripts/awl2struct_2d.py --output_path ./data/test/ --label 65 \ No newline at end of file diff --git a/scripts/awl2struct.py b/scripts/awl2struct.py index ead153a..2a9f102 100644 --- a/scripts/awl2struct.py +++ b/scripts/awl2struct.py @@ -9,11 +9,13 @@ import argparse from pymatgen.core import Structure, Lattice -from wyckoff import wmax_table, mult_table, symops +from crystalformer.src.sym_group import SpaceGroup -symops = np.array(symops) -mult_table = np.array(mult_table) -wmax_table = np.array(wmax_table) +sym_group = SpaceGroup() + +symops = np.array(sym_group.symops) +mult_table = np.array(sym_group.mult_table) +wmax_table = np.array(sym_group.wmax_table) def symmetrize_atoms(g, w, x): diff --git a/scripts/awl2struct_2d.py b/scripts/awl2struct_2d.py new file mode 100644 index 0000000..4ce59b5 --- /dev/null +++ b/scripts/awl2struct_2d.py @@ -0,0 +1,140 @@ +import sys +sys.path.append('./src/') + +import pandas as pd +import numpy as np +from ast import literal_eval +import multiprocessing +import itertools +import argparse + +from pymatgen.core import Structure, Lattice +from pymatgen.io.cif import CifWriter +from crystalformer.src.sym_group import LayerGroup + +sym_group = LayerGroup() + +symops = np.array(sym_group.symops) +mult_table = np.array(sym_group.mult_table) +wmax_table = np.array(sym_group.wmax_table) + + +def symmetrize_atoms(g, w, x): + ''' + symmetrize atoms via, apply all sg symmetry op, finding the generator, and lastly apply symops + we need to do that because the sampled atom might not be at the first WP + Args: + g: int + w: int + x: (3,) + Returns: + xs: (m, 3) symmetrize atom positions + ''' + + # (1) apply all space group symmetry op to the x + w_max = wmax_table[g-1].item() + m_max = mult_table[g-1, w_max].item() + ops = symops[g-1, w_max, :m_max] # (m_max, 3, 4) + affine_point = np.array([*x, 1]) # (4, ) + coords = ops@affine_point # (m_max, 3) + coords -= np.floor(coords) + + # (2) search for the generator which satisfies op0(x) = x , i.e. the first Wyckoff position + # here we solve it in a jit friendly way by looking for the minimal distance solution for the lhs and rhs + #https://github.com/qzhu2017/PyXtal/blob/82e7d0eac1965c2713179eeda26a60cace06afc8/pyxtal/wyckoff_site.py#L115 + def dist_to_op0x(coord): + diff = np.dot(symops[g-1, w, 0], np.array([*coord, 1])) - coord + diff -= np.rint(diff) + return np.sum(diff**2) + # loc = np.argmin(jax.vmap(dist_to_op0x)(coords)) + loc = np.argmin([dist_to_op0x(coord) for coord in coords]) + x = coords[loc].reshape(3,) + + # (3) lastly, apply the given symmetry op to x + m = mult_table[g-1, w] + ops = symops[g-1, w, :m] # (m, 3, 4) + affine_point = np.array([*x, 1]) # (4, ) + xs = ops@affine_point # (m, 3) + xs -= np.floor(xs) # wrap back to 0-1 + return xs + +def get_struct_from_lawx(G, L, A, W, X): + """ + Get the pymatgen.Structure object from the input data + + Args: + G: space group number + L: lattice parameters + A: element number list + W: wyckoff letter list + X: fractional coordinates list + + Returns: + struct: pymatgen.Structure object + """ + A = A[np.nonzero(A)] + X = X[np.nonzero(A)] + W = W[np.nonzero(A)] + + + xs_list = [symmetrize_atoms(G, w, x) for w, x in zip(W, X)] + as_list = [[A[idx] for _ in range(len(xs))] for idx, xs in enumerate(xs_list)] + A_list = list(itertools.chain.from_iterable(as_list)) + X_list = list(itertools.chain.from_iterable(xs_list)) + X_list += np.array([[0., 0., 0.5] for _ in range(len(X_list))]) + X_list -= np.floor(X_list) + lattice = Lattice.from_parameters(*L) + struct = Structure(lattice, A_list, X_list) + return struct + +def main(args): + input_path = args.output_path + f'output_{args.label}.csv' + origin_data = pd.read_csv(input_path) + L,X,A,W = origin_data['L'],origin_data['X'],origin_data['A'],origin_data['W'] + L = L.apply(lambda x: literal_eval(x)) + X = X.apply(lambda x: literal_eval(x)) + A = A.apply(lambda x: literal_eval(x)) + W = W.apply(lambda x: literal_eval(x)) + # M = M.apply(lambda x: literal_eval(x)) + + # convert array of list to numpy ndarray + L = np.array(L.tolist()) + X = np.array(X.tolist()) + A = np.array(A.tolist()) + W = np.array(W.tolist()) + print(L.shape,X.shape,A.shape,W.shape) + + ### Multiprocessing. Use it if only run on CPU + p = multiprocessing.Pool(args.num_io_process) + G = np.array([int(args.label) for _ in range(len(L))]) + structures = p.starmap_async(get_struct_from_lawx, zip(G, L, A, W, X)).get() + p.close() + p.join() + + output_path = args.output_path + f'output_{args.label}_struct.csv' + + # data = pd.DataFrame() + # data['cif'] = structures + # data.to_csv(output_path, mode='a', index=False, header=True) + i = 0 + for structure in structures: + cif_writer = CifWriter(structure) + cif_writer.write_file(args.output_path + f'output_{args.label}_{i}.cif') + i += 1 + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='') + parser.add_argument('--output_path', default='./', help='filepath of the output and input file') + parser.add_argument('--label', default='194', help='output file label') + parser.add_argument('--num_io_process', type=int, default=40, help='number of process used in multiprocessing io') + args = parser.parse_args() + main(args) + + # xs = symmetrize_atoms(61, 4, [ 0., 0., -0.04737133]) + # print(xs) + # L = [3.829, 3.829, 40.172, 90.0, 90.0, 90.0] + # A = [28, 8, 38, 17, 38, 8] + # W = [4, 6, 5, 4, 2, 1] + # X = [[ 0., 0., -0.04737133], [0., 0.5, 0.05508901], [0.5, 0.5, 0.09639814], [0., 0., -0.12889217], [0.5, 0.5, 0.], [0., 0., 0.]] + # structure = get_struct_from_lawx(61, np.array(L), np.array(A), np.array(W), np.array(X)) + # print(structure) \ No newline at end of file diff --git a/scripts/reverse.ipynb b/scripts/reverse.ipynb new file mode 100644 index 0000000..6467cae --- /dev/null +++ b/scripts/reverse.ipynb @@ -0,0 +1,184 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "from ase import Atoms\n", + "from ase.io import read\n", + "from pymatgen.io.ase import AseAtomsAdaptor\n", + "from pymatgen.core.structure import Structure\n", + "from pymatgen.analysis.structure_matcher import StructureMatcher\n", + "\n", + "from crystalformer.src.utils import GLXYZAW_from_file, process_one_c2db\n", + "from crystalformer.src.sym_group import *\n", + "from scripts.awl2struct_2d import get_struct_from_lawx" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Atoms(symbols='Na2Ag2Te2', pbc=[True, True, False], cell=[[6.342571832115988, -0.02109938351186394, 0.0], [3.1848233047101258, 3.1707109131629374, 0.0], [7.180383814621623e-18, 6.24677123134013e-22, 19.79188492]], initial_magmoms=..., calculator=SinglePointCalculator(...))" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# error_list = [368, 377, 395, 427, 436, 452, 453, 463, 474, 492, 508, 515, 527, 530, 533, 541, 543, 545, 555, 563, 582, 585, 592, 599, 601, 608, 620, 625, 634, 641, 656, 668, 672, 676, 685, 688, 691, 693, 704, 706, 715, 719, 726, 729, 743, 758, 800, 801, 808, 809, 822, 826, 842, 846, 853, 855, 864, 884, 888, 891, 898, 900, 904, 906, 916, 923, 928, 930, 936, 937, 943, 958, 962, 986, 1007, 1010, 1012, 1020, 1023, 1026, 1040, 1045, 1059, 1065, 1067, 1082, 1089, 1103, 1105, 1112, 1116, 1137, 1162, 1180, 1193, 1210, 1226, 1252, 1253, 1305, 1317, 1329, 1352, 1377, 1558, 1655, 1668, 2134, 2175, 2184, 2186, 2213, 2233, 2286, 2305, 2326, 2348, 2373, 2402, 2413, 2430, 2447, 2467, 2491, 2572, 2648, 3030, 3031, 3032, 3033, 3035, 3036, 3037, 3038, 3040, 3042, 3043, 3310, 3319, 3323, 4592, 4593, 4594]\n", + "\n", + "csv_file = '/Users/longli/Downloads/c2db_stab/368'\n", + "atom_types = 119\n", + "mult_types = 18\n", + "n_max = 27\n", + "\n", + "crystal = read(csv_file + '/structure.xyz')" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Na', 'Na', 'Ag', 'Ag', 'Te', 'Te']\n", + "[ 6.34260693 4.49405242 19.79188492 90. 90. 45.06337668]\n", + "[[0.07695026 0.34028335 0.62014867]\n", + " [0.57695027 0.34028335 0.37985134]\n", + " [0.57695208 0.84025542 0.49999322]\n", + " [0.07695208 0.84025541 0.50000678]\n", + " [0.57697937 0.34020381 0.59686936]\n", + " [0.07697937 0.3402038 0.40313063]]\n", + "[[ 1.57180491 1.07731653 12.27391107]\n", + " [ 4.74309089 1.06676684 7.51797405]\n", + " [ 6.33542505 2.65203369 9.89580826]\n", + " [ 3.1641391 2.66258335 9.89607666]\n", + " [ 4.74302208 1.06651401 11.8131697 ]\n", + " [ 1.57173617 1.0770637 7.97871503]]\n" + ] + } + ], + "source": [ + "print(crystal.get_chemical_symbols())\n", + "print(crystal.cell.cellpar())\n", + "print(crystal.get_scaled_positions())\n", + "print(crystal.get_positions())" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['number']) is deprecated.Use attribute interface (SpglibDataset.number) instead\n", + " warnings.warn(\n", + "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_lattice']) is deprecated.Use attribute interface (SpglibDataset.std_lattice) instead\n", + " warnings.warn(\n", + "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['mapping_to_primitive']) is deprecated.Use attribute interface (SpglibDataset.mapping_to_primitive) instead\n", + " warnings.warn(\n", + "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_mapping_to_primitive']) is deprecated.Use attribute interface (SpglibDataset.std_mapping_to_primitive) instead\n", + " warnings.warn(\n", + "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_positions']) is deprecated.Use attribute interface (SpglibDataset.std_positions) instead\n", + " warnings.warn(\n", + "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['std_types']) is deprecated.Use attribute interface (SpglibDataset.std_types) instead\n", + " warnings.warn(\n", + "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['wyckoffs']) is deprecated.Use attribute interface (SpglibDataset.wyckoffs) instead\n", + " warnings.warn(\n", + "/Users/longli/miniconda3/envs/crystalformer/lib/python3.10/site-packages/spglib/spglib.py:115: DeprecationWarning: dict interface (SpglibDataset['equivalent_atoms']) is deprecated.Use attribute interface (SpglibDataset.equivalent_atoms) instead\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "g, a, m, symbol, x: 64 Na 2 2 2b [[0. 0. 0.12014866]]\n", + "g, a, m, symbol, x: 64 Ag 2 1 2a [[0.5 0. 0. ]]\n", + "g, a, m, symbol, x: 64 Te 2 2 2b [[0.5 0.5 0.09686936]]\n", + "['2a' '2b' '2b'] [2 2 2] ['Ag' 'Na' 'Te'] 6\n", + "===================================\n" + ] + }, + { + "data": { + "text/plain": [ + "Structure Summary\n", + "Lattice\n", + " abc : 7.41607332229615 7.41607332229615 32.675682067871094\n", + " angles : 90.00000250447796 90.00000250447796 90.00000250447816\n", + " volume : 1797.1018520373148\n", + " A : 7.416073322296143 0.0 -3.2416684803138196e-07\n", + " B : -3.241668873550938e-07 7.4160733222961355 -3.2416684803138196e-07\n", + " C : 0.0 0.0 32.675682067871094\n", + " pbc : True True True\n", + "PeriodicSite: Ag (5.562, 1.854, 16.34) [0.75, 0.25, 0.5]\n", + "PeriodicSite: Ag (1.854, 5.562, 16.34) [0.25, 0.75, 0.5]\n", + "PeriodicSite: Na (1.854, 1.854, 20.26) [0.25, 0.25, 0.6201]\n", + "PeriodicSite: Na (5.562, 5.562, 12.41) [0.75, 0.75, 0.3799]\n", + "PeriodicSite: Te (1.854, 1.854, 19.5) [0.25, 0.25, 0.5969]\n", + "PeriodicSite: Te (5.562, 5.562, 13.17) [0.75, 0.75, 0.4031]" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sym_group = LayerGroup()\n", + "\n", + "G, L, X, A, W = GLXYZAW_from_file(sym_group, csv_file, atom_types, mult_types, n_max)\n", + "g = G[0]\n", + "l = np.array(L[0])\n", + "x = np.array(X[0])\n", + "a = np.array(A[0])\n", + "w = np.array(W[0])\n", + "\n", + "l[3:] = l[3:] * (180 / np.pi)\n", + "l[:3] = l[:3] * (len(a))**(1./3.)\n", + " \n", + "struct_converted = get_struct_from_lawx(g, l, a, w, x)\n", + "struct_converted" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "crystalformer", + "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.10.15" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tests/test_fc_mask.py b/tests/test_fc_mask.py index 7385cde..8aae948 100644 --- a/tests/test_fc_mask.py +++ b/tests/test_fc_mask.py @@ -3,6 +3,10 @@ import os import numpy as np import jax.numpy as jnp +from crystalformer.src.sym_group import * + +sym_group = SpaceGroup() + df = pd.read_csv(os.path.join(datadir, 'wyckoff_list.csv')) df['Wyckoff Positions'] = df['Wyckoff Positions'].apply(eval) # convert string to list @@ -34,14 +38,14 @@ def convert_to_binary_list(s): from config import * def test_fc_mask(): - from crystalformer.src.wyckoff import symops, wmax_table - from crystalformer.src.wyckoff import fc_mask_table as fc_mask_table_test + # from crystalformer.src.wyckoff import symops, wmax_table + # from crystalformer.src.wyckoff import fc_mask_table as fc_mask_table_test for g in range(1, 231): - for w in range(1, wmax_table[g]+1): - op = symops[g-1, w, 0] # 0 since we conly consider the first wyckoff point in the equivalent class when building fc_mask_table + for w in range(1, sym_group.wmax_table[g]+1): + op = sym_group.symops[g-1, w, 0] # 0 since we conly consider the first wyckoff point in the equivalent class when building fc_mask_table fc_mask = (op[:3, :3].sum(axis=1)!=0) assert jnp.allclose(fc_mask, fc_mask_table[g-1, w]) - assert jnp.allclose(fc_mask, fc_mask_table_test[g-1, w]) + assert jnp.allclose(fc_mask, sym_group.fc_mask_table[g-1, w]) test_fc_mask() diff --git a/tests/test_fc_mask_layer.py b/tests/test_fc_mask_layer.py new file mode 100644 index 0000000..e23fbe8 --- /dev/null +++ b/tests/test_fc_mask_layer.py @@ -0,0 +1,51 @@ +from config import * +import pandas as pd +import os +import numpy as np +import jax.numpy as jnp +from crystalformer.src.sym_group import * + +sym_group = LayerGroup() + + +df = pd.read_csv(os.path.join(datadir, 'layer_list.csv')) +df['Wyckoff Positions'] = df['Wyckoff Positions'].apply(eval) # convert string to list +wyckoff_positions = df['Wyckoff Positions'].tolist() + +def convert_to_binary_list(s): + """ + Converts a list of strings into a list of binary lists based on the presence of 'x', 'y', or 'z'. + """ + components = s.split(',') + #TODO a better translation can be xxx->100 but not 111 + return [1 if any(char in comp for char in ['x', 'y', 'z']) else 0 for comp in components] + +fc_mask_list = [] +for g, wp_list in enumerate(wyckoff_positions): + sub_list = [] + for wp in wp_list[::-1]: + sub_list.append(convert_to_binary_list(wp[0])) + fc_mask_list.append(sub_list) + +max_len = max(len(sub_list) for sub_list in fc_mask_list) + +fc_mask_table = np.zeros((len(fc_mask_list), max_len+1, 3), dtype=int) # (230, 28, 3) +for i, sub_list in enumerate(fc_mask_list): + for j, l in enumerate(sub_list): + fc_mask_table[i, j+1, : ] = l # we have added a padding of W=0 +fc_mask_table = jnp.array(fc_mask_table) # 1 in the fc_mask_table select those active fractional coordinate + +from config import * + +def test_fc_mask(): + # from crystalformer.src.wyckoff import symops, wmax_table + # from crystalformer.src.wyckoff import fc_mask_table as fc_mask_table_test + + for g in range(1, 231): + for w in range(1, sym_group.wmax_table[g]+1): + op = sym_group.symops[g-1, w, 0] # 0 since we conly consider the first wyckoff point in the equivalent class when building fc_mask_table + fc_mask = (op[:3, :3].sum(axis=1)!=0) + assert jnp.allclose(fc_mask, fc_mask_table[g-1, w]) + assert jnp.allclose(fc_mask, sym_group.fc_mask_table[g-1, w]) + +test_fc_mask() diff --git a/tests/test_lattice.py b/tests/test_lattice.py index b1eecf3..a246abb 100644 --- a/tests/test_lattice.py +++ b/tests/test_lattice.py @@ -1,6 +1,16 @@ from config import * +<<<<<<< HEAD +import sys +sys.path.append('../crystalformer') + from crystalformer.src.lattice import symmetrize_lattice, make_lattice_mask +======= +# from crystalformer.src.lattice import symmetrize_lattice, make_lattice_mask +from crystalformer.src.sym_group import * + +sym_group = SpaceGroup() +>>>>>>> main def test_symmetrize_lattice(): key = jax.random.PRNGKey(42) @@ -9,7 +19,7 @@ def test_symmetrize_lattice(): L = jax.random.uniform(key, (6,)) L = L.reshape([1, 6]).repeat(230, axis=0) - lattice = jax.jit(jax.vmap(symmetrize_lattice))(G, L) + lattice = jax.jit(jax.vmap(sym_group.symmetrize_lattice()))(G, L) print (lattice) a, b, c, alpha, beta, gamma = lattice[99-1] @@ -32,7 +42,7 @@ def make_spacegroup_mask(spacegroup): mask = jnp.where(spacegroup <= 194, mask, jnp.array([1, 0, 0, 0, 0, 0])) return mask - mask = make_lattice_mask() + mask = sym_group.make_lattice_mask()() for g in range(1, 231): assert jnp.allclose(mask[g-1] , make_spacegroup_mask(g)) diff --git a/tests/test_lattice_layer.py b/tests/test_lattice_layer.py new file mode 100644 index 0000000..21fd1dd --- /dev/null +++ b/tests/test_lattice_layer.py @@ -0,0 +1,45 @@ +from config import * + +# from crystalformer.src.lattice import symmetrize_lattice, make_lattice_mask +from crystalformer.src.sym_group import * + +sym_group = LayerGroup() + +def test_symmetrize_lattice(): + key = jax.random.PRNGKey(42) + + G = jnp.arange(80) + 1 + L = jax.random.uniform(key, (6,)) + L = L.reshape([1, 6]).repeat(80, axis=0) + + lattice = jax.jit(jax.vmap(sym_group.symmetrize_lattice()))(G, L) + print (lattice) + + a, b, c, alpha, beta, gamma = lattice[49-1] + assert (alpha==beta==gamma==90) + assert (a==b) + +def test_make_mask(): + + def make_spacegroup_mask(spacegroup): + ''' + return mask for independent lattice params + ''' + + mask = jnp.array([1, 1, 1, 1, 1, 1]) + + mask = jnp.where(spacegroup <= 2, mask, jnp.array([1, 1, 1, 0, 1, 0])) + mask = jnp.where(spacegroup <= 18, mask, jnp.array([1, 1, 1, 0, 0, 0])) + mask = jnp.where(spacegroup <= 48, mask, jnp.array([1, 0, 1, 0, 0, 0])) + mask = jnp.where(spacegroup <= 64, mask, jnp.array([1, 0, 0, 1, 0, 0])) + mask = jnp.where(spacegroup <= 72, mask, jnp.array([1, 0, 1, 0, 0, 0])) + return mask + + mask = sym_group.make_lattice_mask()() + + for g in range(1, 81): + assert jnp.allclose(mask[g-1] , make_spacegroup_mask(g)) + +test_symmetrize_lattice() +test_make_mask() + diff --git a/tests/test_sampling.py b/tests/test_sampling.py index 55ab52d..90983c7 100644 --- a/tests/test_sampling.py +++ b/tests/test_sampling.py @@ -1,8 +1,10 @@ from config import * -from crystalformer.src.wyckoff import symops +from crystalformer.src.sym_group import * +symops = SpaceGroup().symops +wmax_table = SpaceGroup().wmax_table +mult_table = SpaceGroup().mult_table def test_symops(): - from crystalformer.src.wyckoff import wmax_table, mult_table def project_x(g, w, x, idx): ''' One wants to project randomly sampled fc to the nearest Wyckoff point @@ -45,29 +47,29 @@ def dist_to_op0x(coord): y = project_x(g, w, x, idx) assert jnp.allclose(y, jnp.array([0.123, 0.123, 0.75])) - x = jnp.array([0.123, 0.123, 0.25]) - y = project_x(g, w, x, idx) - assert jnp.allclose(y, jnp.array([0.877, 0.877, 0.75])) + # x = jnp.array([0.123, 0.123, 0.25]) + # y = project_x(g, w, x, idx) + # assert jnp.allclose(y, jnp.array([0.877, 0.877, 0.75])) - g = 225 - w = jnp.array(5) - x = jnp.array([0., 0., 0.7334]) + # g = 225 + # w = jnp.array(5) + # x = jnp.array([0., 0., 0.7334]) - idx = jnp.array(0) - y = project_x(g, w, x, idx) - assert jnp.allclose(y, jnp.array([0.7334, 0., 0.])) + # idx = jnp.array(0) + # y = project_x(g, w, x, idx) + # assert jnp.allclose(y, jnp.array([0.7334, 0., 0.])) - idx = jnp.array(3) - y = project_x(g, w, x, idx) - assert jnp.allclose(y, jnp.array([0., 1.0-0.7334, 0.])) + # idx = jnp.array(3) + # y = project_x(g, w, x, idx) + # assert jnp.allclose(y, jnp.array([0., 1.0-0.7334, 0.])) - g = 166 - w = jnp.array(8) - x = jnp.array([0.1, 0.2, 0.3]) + # g = 166 + # w = jnp.array(8) + # x = jnp.array([0.1, 0.2, 0.3]) - idx = jnp.array(5) - y = project_x(g, w, x, idx) - assert jnp.allclose(y, jnp.array([1-0.1, 1-0.2, 1-0.3])) + # idx = jnp.array(5) + # y = project_x(g, w, x, idx) + # assert jnp.allclose(y, jnp.array([1-0.1, 1-0.2, 1-0.3])) def test_sample_top_p(): from crystalformer.src.sample import sample_top_p @@ -81,5 +83,5 @@ def test_sample_top_p(): k = jax.jit(sample_top_p, static_argnums=2)(key, logits, p, temperature) print (k) -test_sample_top_p() +# test_sample_top_p() test_symops() diff --git a/tests/test_sampling_layer.py b/tests/test_sampling_layer.py new file mode 100644 index 0000000..2e65269 --- /dev/null +++ b/tests/test_sampling_layer.py @@ -0,0 +1,87 @@ +from config import * +from crystalformer.src.sym_group import * +symops = LayerGroup().symops +wmax_table = LayerGroup().wmax_table +mult_table = LayerGroup().mult_table + +def test_symops(): + def project_x(g, w, x, idx): + ''' + One wants to project randomly sampled fc to the nearest Wyckoff point + Alternately, we randomly select a Wyckoff point, and then project fc to that point + To achieve that, we do the following 3 steps + ''' + w_max = wmax_table[g-1].item() + m_max = mult_table[g-1, w_max].item() + + # (1) apply all space group symmetry op to the fc to get x + ops = symops[g-1, w_max, :m_max] # (m_max, 3, 4) + affine_point = jnp.array([*x, 1]) # (4, ) + coords = ops@affine_point # (m_max, 3) + coords -= jnp.floor(coords) + + # (2) search for the generator which satisfies op0(x) = x , i.e. the first Wyckoff position + # here we solve it in a jit friendly way by looking for the minimal distance solution for the lhs and rhs + #https://github.com/qzhu2017/PyXtal/blob/82e7d0eac1965c2713179eeda26a60cace06afc8/pyxtal/wyckoff_site.py#L115 + def dist_to_op0x(coord): + diff = jnp.dot(symops[g-1, w, 0], jnp.array([*coord, 1])) - coord + diff -= jnp.floor(diff) + return jnp.sum(diff**2) + loc = jnp.argmin(jax.vmap(dist_to_op0x)(coords)) + x = coords[loc].reshape(3,) + + # (3) lastly, apply the given randomly sampled Wyckoff symmetry op to x + op = symops[g-1, w, idx].reshape(3, 4) + affine_point = jnp.array([*x, 1]) # (4, ) + x = jnp.dot(op, affine_point) # (3, ) + x -= jnp.floor(x) + return x + + # these two tests shows that depending on the z coordinate (which is supposed to be rationals) + # the WP can be recoginized differently, resulting different x + # this motivate that we either predict idx in [1, m], or we predict all fc once there is a continuous dof + g = 67 + w = jnp.array(7) + idx = jnp.array(0) + x = jnp.array([0.123, 0.877, 0.0]) + y = project_x(g, w, x, idx) + assert jnp.allclose(y, jnp.array([0.123, 0.877, 0.0])) + + # x = jnp.array([0.123, 0.123, 0.25]) + # y = project_x(g, w, x, idx) + # assert jnp.allclose(y, jnp.array([0.877, 0.877, 0.75])) + + # g = 25 + # w = jnp.array(5) + # x = jnp.array([0., 0., 0.7334]) + + # idx = jnp.array(0) + # y = project_x(g, w, x, idx) + # assert jnp.allclose(y, jnp.array([0.7334, 0., 0.])) + + # idx = jnp.array(3) + # y = project_x(g, w, x, idx) + # assert jnp.allclose(y, jnp.array([0., 1.0-0.7334, 0.])) + + # g = 66 + # w = jnp.array(8) + # x = jnp.array([0.1, 0.2, 0.3]) + + # idx = jnp.array(5) + # y = project_x(g, w, x, idx) + # assert jnp.allclose(y, jnp.array([1-0.1, 1-0.2, 1-0.3])) + +def test_sample_top_p(): + from crystalformer.src.sample import sample_top_p + key = jax.random.PRNGKey(42) + logits = jnp.array([[1.0, 1.0, 2.0, 2.0, 3.0], + [-1.0, 1.0, 4.0, 1.0, 0.0] + ] + ) + p = 0.8 + temperature = 1.0 + k = jax.jit(sample_top_p, static_argnums=2)(key, logits, p, temperature) + print (k) + +test_sample_top_p() +test_symops() diff --git a/tests/test_transformer.py b/tests/test_transformer.py index 02aebbd..ed6930c 100644 --- a/tests/test_transformer.py +++ b/tests/test_transformer.py @@ -1,8 +1,8 @@ from config import * from crystalformer.src.utils import GLXYZAW_from_file -from crystalformer.src.wyckoff import mult_table from crystalformer.src.transformer import make_transformer +from crystalformer.src.sym_group import * def test_autoregressive(): atom_types = 119 @@ -13,18 +13,19 @@ def test_autoregressive(): Kl = 8 dim = 3 dropout_rate = 0.0 + sym_group = SpaceGroup() csv_file = os.path.join(datadir, '../../data/mini.csv') - G, L, X, A, W = GLXYZAW_from_file(csv_file, atom_types, wyck_types, n_max, dim) + G, L, X, A, W = GLXYZAW_from_file(sym_group, csv_file, atom_types, wyck_types, n_max, dim) @jax.vmap def lookup(G, W): - return mult_table[G-1, W] # (n_max, ) + return sym_group.mult_table[G-1, W] # (n_max, ) M = lookup(G, W) # (batchsize, n_max) num_sites = jnp.sum(A!=0, axis=1) key = jax.random.PRNGKey(42) - params, transformer = make_transformer(key, Nf, Kx, Kl, n_max, dim, 128, 4, 4, 8, 16,atom_types, wyck_types, dropout_rate) + params, transformer = make_transformer(sym_group, key, Nf, Kx, Kl, n_max, dim, 128, 4, 4, 8, 16,atom_types, wyck_types, dropout_rate) def test_fn(X, M): output = transformer(params, None, G[0], X, A[0], W[0], M, False) @@ -70,4 +71,5 @@ def test_perm(): print (W) assert jnp.allclose(W, W[idx]) -test_autoregressive() +if __name__ == '__main__': + test_autoregressive() diff --git a/tests/test_transformer_layer.py b/tests/test_transformer_layer.py new file mode 100644 index 0000000..31dc8de --- /dev/null +++ b/tests/test_transformer_layer.py @@ -0,0 +1,75 @@ +from config import * + +from crystalformer.src.utils import GLXYZAW_from_file +from crystalformer.src.transformer import make_transformer +from crystalformer.src.sym_group import * + +def test_autoregressive(): + atom_types = 119 + wyck_types = 19 + Nf = 8 + n_max = 21 + Kx = 16 + Kl = 8 + dim = 3 + dropout_rate = 0.0 + sym_group = LayerGroup() + + csv_file = './c2db' + G, L, X, A, W = GLXYZAW_from_file(sym_group, csv_file, atom_types, wyck_types, n_max, dim) + + @jax.vmap + def lookup(G, W): + return sym_group.mult_table[G-1, W] # (n_max, ) + M = lookup(G, W) # (batchsize, n_max) + num_sites = jnp.sum(A!=0, axis=1) + + key = jax.random.PRNGKey(42) + params, transformer = make_transformer(sym_group, key, Nf, Kx, Kl, n_max, dim, 128, 4, 4, 8, 16,atom_types, wyck_types, dropout_rate) + + def test_fn(X, M): + output = transformer(params, None, G[0], X, A[0], W[0], M, False) + print (output.shape) + return output.sum(axis=-1) + + jac_x = jax.jacfwd(test_fn, argnums=0)(X[0], M[0]) + jac_m = jax.jacfwd(test_fn, argnums=1)(X[0], M[0].astype(jnp.float32))[:, :, None] + + print(jac_x.shape, jac_m.shape) + + def print_dependencey(jac): + dependencey = jnp.linalg.norm(jac, axis=-1) + for row in (dependencey != 0.).astype(int): + print(" ".join(str(val) for val in row)) + + print ("jac_a_x") + print_dependencey(jac_x[::2]) + print ("jac_x_x") + print_dependencey(jac_x[1::2]) + print ("jac_a_a") + print_dependencey(jac_m[::2]) + print ("jac_x_a") + print_dependencey(jac_m[1::2]) + + +def test_perm(): + + key = jax.random.PRNGKey(42) + + #W = jnp.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0]) + W = jnp.array([1,2, 2, 2, 5, 0,0, 0]) + n = len(W) + key = jax.random.PRNGKey(42) + + temp = jnp.where(W>0, W, 9999) + idx_perm = jax.random.permutation(key, jnp.arange(n)) + temp = temp[idx_perm] + idx_sort = jnp.argsort(temp) + idx = idx_perm[idx_sort] + + print (idx) + print (W) + assert jnp.allclose(W, W[idx]) + +if __name__ == '__main__': + test_autoregressive() diff --git a/tests/test_utils.py b/tests/test_utils.py index d42238e..eb5a0f2 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,10 @@ from config import * from crystalformer.src.utils import GLXYZAW_from_file -from crystalformer.src.wyckoff import mult_table +from crystalformer.src.sym_group import * + +sym_group = SpaceGroup() +mult_table = sym_group.mult_table def calc_n(G, W): @jax.vmap @@ -19,7 +22,7 @@ def test_utils(): dim = 3 csv_file = os.path.join(datadir, '../../data/mini.csv') - G, L, X, A, W = GLXYZAW_from_file(csv_file, atom_types, mult_types, n_max, dim) + G, L, X, A, W = GLXYZAW_from_file(sym_group, csv_file, atom_types, mult_types, n_max, dim) assert G.ndim == 1 assert L.ndim == 2 diff --git a/tests/test_utils_layer.py b/tests/test_utils_layer.py new file mode 100644 index 0000000..d29af72 --- /dev/null +++ b/tests/test_utils_layer.py @@ -0,0 +1,72 @@ +from config import * + +from ase import Atoms +from ase.io import read +from pymatgen.io.ase import AseAtomsAdaptor +from pymatgen.core.structure import Structure +from pymatgen.analysis.structure_matcher import StructureMatcher + +from crystalformer.src.utils import GLXYZAW_from_file, process_one_c2db +from crystalformer.src.sym_group import * +from scripts.awl2struct_2d import get_struct_from_lawx + +sym_group = LayerGroup() +mult_table = sym_group.mult_table + +# def calc_n(G, W): +# @jax.vmap +# def lookup(G, W): +# return mult_table[G-1, W] # (n_max, ) +# M = lookup(G, W) # (batchsize, n_max) +# N = M.sum(axis=-1) +# return N + +def test_utils(csv_file): + + atom_types = 119 + mult_types = 18 + n_max = 27 + + paths = os.walk(csv_file) + data_list = [] + for path, _, file_list in paths: + for file_name in file_list: + if file_name == 'data.json': + data_list.append(os.path.join(path, file_name).replace('/data.json', '')) + + + + # G, L, X, A, W = process_one_c2db(csv_file, atom_types, mult_types, n_max) + G, L, X, A, W = GLXYZAW_from_file(sym_group, csv_file, atom_types, mult_types, n_max, num_workers=128) + + error_list = [] + + for i in range(len(data_list)): + crystal = read(data_list[i] + '/structure.xyz') + ase_adaptor = AseAtomsAdaptor() + struct = ase_adaptor.get_structure(crystal) + + g = G[i] + l = np.array(L[i]) + x = np.array(X[i]) + a = np.array(A[i]) + w = np.array(W[i]) + + M = mult_table[g-1, w] + num_atoms = np.sum(M, axis=-1) + l[3:] = l[3:] * (180 / np.pi) + l[:3] = l[:3] * (num_atoms)**(1./3.) + + struct_converted = get_struct_from_lawx(g, l, a, w, x) + + matcher = StructureMatcher(primitive_cell=False, attempt_supercell=True) + isMatch = matcher.fit(struct, struct_converted) + + if not isMatch: + error_list.append(data_list[i]) + + return error_list + +path = '/home/longlizheng/pycode/CrystalFormer_layer/c2db_stab' +result = test_utils(path) +print(result) \ No newline at end of file diff --git a/tests/test_wyckoff.py b/tests/test_wyckoff.py index 541b7b4..61710de 100644 --- a/tests/test_wyckoff.py +++ b/tests/test_wyckoff.py @@ -231,15 +231,18 @@ ] from config import * +from crystalformer.src.sym_group import * + +sym_group = SpaceGroup() + def test_mult_table(): - from crystalformer.src.wyckoff import mult_table def nonzero_part(arr): nonzero_indices = jnp.nonzero(arr) return arr[nonzero_indices] def match(g): - jnp.allclose( nonzero_part(mult_table[g-1]) , jnp.array(wyckoff_list[g-1])) + jnp.allclose( nonzero_part(sym_group.mult_table[g-1]) , jnp.array(wyckoff_list[g-1])) match(25) match(47) @@ -276,12 +279,11 @@ def test_wyckoff(): mult_table = jnp.array(mult_table) wmax_table = jnp.array(wmax_table) - import crystalformer.src.wyckoff as wyckoff - assert jnp.allclose(mult_table, wyckoff.mult_table) - assert jnp.allclose(wmax_table, wyckoff.wmax_table) + assert jnp.allclose(mult_table, sym_group.mult_table) + assert jnp.allclose(wmax_table, sym_group.wmax_table) def test_symmetrize_atoms(): - from crystalformer.src.wyckoff import symmetrize_atoms, mult_table, wmax_table, symops + from crystalformer.src.wyckoff import symmetrize_atoms from pymatgen.symmetry.groups import SpaceGroup #https://github.com/materialsproject/pymatgen/blob/1e347c42c01a4e926e15b910cca8964c1a0cc826/pymatgen/symmetry/groups.py#L547 @@ -318,9 +320,9 @@ def symmetrize_atoms_deduplication(g, w, x): xs: (m, 3) symmetrized atom positions ''' # (1) apply all space group symmetry ops to x - w_max = wmax_table[g-1].item() - m_max = mult_table[g-1, w_max].item() - ops = symops[g-1, w_max, :m_max] # (m_max, 3, 4) + w_max = sym_group.wmax_table[g-1].item() + m_max = sym_group.mult_table[g-1, w_max].item() + ops = sym_group.symops[g-1, w_max, :m_max] # (m_max, 3, 4) affine_point = jnp.array([*x, 1]) # (4, ) coords = ops@affine_point # (m_max, 3) @@ -331,13 +333,13 @@ def symmetrize_atoms_deduplication(g, w, x): if not in_array_list(orbit, pp): orbit.append(pp) orbit -= np.floor(orbit) # wrap back to 0-1 - assert (orbit.shape[0] == mult_table[g-1, w]) # double check that the orbit has the right length + assert (orbit.shape[0] == sym_group.mult_table[g-1, w]) # double check that the orbit has the right length return orbit def symmetrize_atoms_pmg(g, w, x): sg = SpaceGroup.from_int_number(g) xs = sg.get_orbit(x) - m = mult_table[g-1, w] + m = sym_group.mult_table[g-1, w] assert (len(xs) == m) # double check that the orbit has the right length return np.array(xs) @@ -351,7 +353,7 @@ def allclose_up_to_permutation(xs, xs_pmg): g = 166 w = jnp.array(3) x = jnp.array([0., 0., 0.5619]) - xs = symmetrize_atoms(g, w, x) + xs = symmetrize_atoms(sym_group, g, w, x) print ('xs:\n', xs) assert allclose_up_to_permutation(xs, symmetrize_atoms_pmg(g, w, x)) assert allclose_up_to_permutation(xs, symmetrize_atoms_deduplication(g, w, x)) @@ -359,7 +361,7 @@ def allclose_up_to_permutation(xs, xs_pmg): g = 225 w = jnp.array(5) x = jnp.array([0., 0., 0.7334]) - xs = symmetrize_atoms(g, w, x) + xs = symmetrize_atoms(sym_group, g, w, x) print ('xs:\n', xs) assert allclose_up_to_permutation(xs, symmetrize_atoms_pmg(g, w, x)) assert allclose_up_to_permutation(xs, symmetrize_atoms_deduplication(g, w, x)) @@ -367,7 +369,7 @@ def allclose_up_to_permutation(xs, xs_pmg): g = 225 w = jnp.array(8) x = jnp.array([0.0, 0.23, 0.23]) - xs = symmetrize_atoms(g, w, x) + xs = symmetrize_atoms(sym_group, g, w, x) print ('xs:\n', xs) assert allclose_up_to_permutation(xs, symmetrize_atoms_pmg(g, w, x)) assert allclose_up_to_permutation(xs, symmetrize_atoms_deduplication(g, w, x)) diff --git a/tests/test_wyckoff_layer.py b/tests/test_wyckoff_layer.py new file mode 100644 index 0000000..9ae3b15 --- /dev/null +++ b/tests/test_wyckoff_layer.py @@ -0,0 +1,169 @@ +wyckoff_list = [[1], [1, 1, 1, 1, 2], [1, 1, 1, 1, 2], [1, 2], [2], [1, 1, 1, 1, 2, 2, 2, 2, 2, 4], [2, 2, 2, 2, 4], [1, 1, 2], [2], [2, 4], [1, 1, 2], [2], [2, 4], [1, 1, 1, 1, 2, 2, 2, 2, 4], [2, 2, 2, 4], [2, 2, 2, 4], [2, 2, 4], [2, 2, 4, 4, 4, 8], [1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4], [2, 2, 2, 4], [2, 2, 4], [2, 2, 4, 4, 4, 4, 4, 8], [1, 1, 1, 1, 2, 2, 2, 2, 4], [2, 2, 2, 4], [2, 2, 4], [2, 2, 4, 4, 4, 8], [1, 1, 2, 2, 2, 4], [2, 2, 4], [2, 4], [2, 2, 4], [2, 2, 4], [2, 4], [4], [2, 4], [2, 4, 4, 8], [4, 4, 8], [1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 8], [2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 8], [2, 2, 4, 4, 4, 4, 4, 8], [2, 2, 2, 4, 4, 4, 4, 8], [2, 2, 2, 2, 4, 4, 4, 4, 8], [2, 2, 4, 4, 4, 8], [4, 4, 4, 8], [2, 2, 4, 4, 4, 8], [4, 4, 4, 8], [2, 2, 4, 4, 4, 8], [2, 2, 4, 4, 4, 4, 4, 8, 8, 8, 8, 16], [4, 4, 4, 4, 8, 8, 8, 8, 8, 16], [1, 1, 2, 4], [1, 1, 2, 2, 2, 4], [1, 1, 2, 2, 2, 4, 4, 8], [2, 2, 4, 4, 8], [1, 1, 2, 2, 2, 4, 4, 4, 4, 8], [2, 2, 4, 4, 8], [1, 1, 2, 4, 4, 4, 8], [2, 2, 4, 8], [1, 1, 2, 2, 2, 4, 4, 4, 4, 8], [2, 2, 4, 4, 8], [1, 1, 2, 2, 2, 4, 4, 4, 8], [2, 2, 4, 4, 4, 8], [1, 1, 2, 2, 2, 4, 4, 4, 4, 8, 8, 8, 8, 16], [2, 2, 4, 4, 4, 8, 8, 8, 16], [2, 2, 4, 4, 4, 8, 8, 16], [2, 2, 4, 4, 8, 8, 8, 16], [1, 1, 1, 3], [1, 2, 2, 3, 6], [1, 1, 1, 2, 2, 2, 3, 6], [1, 2, 2, 3, 6], [1, 1, 1, 3, 6], [1, 2, 3, 6], [1, 2, 2, 3, 4, 6, 6, 12], [1, 2, 2, 3, 6, 6, 12], [1, 2, 3, 6], [1, 1, 1, 2, 2, 2, 3, 6], [1, 2, 2, 3, 4, 6, 6, 12], [1, 2, 2, 3, 4, 6, 6, 6, 12], [1, 2, 3, 6, 6, 12], [1, 1, 1, 2, 2, 2, 3, 6, 6, 12], [1, 2, 2, 3, 4, 6, 6, 12], [1, 2, 2, 3, 4, 6, 6, 6, 12, 12, 12, 24]] + + +# symbols = [] + +# for ws in wyckoff_list: +# ws_symbols = [] +# for i in range(len(ws)): +# ws_symbols.append(f'{ws[i]}{chr(i+97)}') +# symbols.append(f"{ws_symbols}") + + +# # print(symbols) + +# import pandas as pd +# # import numpy as np + +# # data = np.array([[i for i in range(1, 1 + len(symbols))], symbols]) +# df = pd.DataFrame(data={'Layer Group': [i for i in range(1, 1 + len(symbols))], 'Wyckoff Positions': symbols}) +# df.to_csv('layer_symbols.csv', index=False) + + + +from config import * +from crystalformer.src.sym_group import * + +sym_group = LayerGroup() + +def test_mult_table(): + + def nonzero_part(arr): + nonzero_indices = jnp.nonzero(arr) + return arr[nonzero_indices] + + def match(g): + jnp.allclose( nonzero_part(sym_group.mult_table[g-1]) , jnp.array(wyckoff_list[g-1])) + + match(25) + match(47) + # match(99) + # match(123) + # match(221) + +def test_wyckoff(): + import pandas as pd + import os + + df = pd.read_csv(os.path.join(datadir, 'layer_symbols.csv')) + df['Wyckoff Positions'] = df['Wyckoff Positions'].apply(eval) # convert string to list + + wyckoff_symbols = df['Wyckoff Positions'].tolist() + + import numpy as np + import jax.numpy as jnp + + wyckoff_list = [] + wyckoff_dict = [] + for ws in wyckoff_symbols: + wyckoff_list.append( [0] +[0 if w == "" else int(''.join(filter(str.isdigit, w))) for w in ws] ) + + ws = [""] + ws + wyckoff_dict.append( {value: index for index, value in enumerate(ws)} ) + + max_len = max(len(sublist) for sublist in wyckoff_list) + mult_table = np.zeros((len(wyckoff_list), max_len), dtype=int) # mult_table[g-1, w] = multiplicity + wmax_table = np.zeros((len(wyckoff_list),), dtype=int) # wmax_table[g-1] = number of wyckoff letters + for i, sublist in enumerate(wyckoff_list): + mult_table[i, :len(sublist)] = sublist + wmax_table[i] = len(sublist)-1 + mult_table = jnp.array(mult_table) + wmax_table = jnp.array(wmax_table) + + assert jnp.allclose(mult_table, sym_group.mult_table) + assert jnp.allclose(wmax_table, sym_group.wmax_table) + +# def test_symmetrize_atoms(): +# from crystalformer.src.wyckoff import symmetrize_atoms +# from pymatgen.symmetry.groups import SpaceGroup + +# #https://github.com/materialsproject/pymatgen/blob/1e347c42c01a4e926e15b910cca8964c1a0cc826/pymatgen/symmetry/groups.py#L547 +# def in_array_list(array_list: list[np.ndarray], arr: np.ndarray, tol: float = 1e-5) -> bool: +# """Extremely efficient nd-array comparison using numpy's broadcasting. This +# function checks if a particular array a, is present in a list of arrays. +# It works for arrays of any size, e.g., even matrix searches. + +# Args: +# array_list ([array]): A list of arrays to compare to. +# arr (array): The test array for comparison. +# tol (float): The tolerance. Defaults to 1e-5. If 0, an exact match is done. + +# Returns: +# (bool) +# """ +# if len(array_list) == 0: +# return False +# axes = tuple(range(1, arr.ndim + 1)) +# if not tol: +# return any(np.all(array_list == arr[None, :], axes)) +# return any(np.sum(np.abs(array_list - arr[None, :]), axes) < tol) + +# def symmetrize_atoms_deduplication(g, w, x): +# ''' +# symmetrize atoms via deduplication +# this implements the same method as pmg get_orbit function, see +# #https://github.com/materialsproject/pymatgen/blob/1e347c42c01a4e926e15b910cca8964c1a0cc826/pymatgen/symmetry/groups.py#L328 +# Args: +# g: int +# w: int +# x: (3,) +# Returns: +# xs: (m, 3) symmetrized atom positions +# ''' +# # (1) apply all space group symmetry ops to x +# w_max = sym_group.wmax_table[g-1].item() +# m_max = sym_group.mult_table[g-1, w_max].item() +# ops = sym_group.symops[g-1, w_max, :m_max] # (m_max, 3, 4) +# affine_point = jnp.array([*x, 1]) # (4, ) +# coords = ops@affine_point # (m_max, 3) + +# # (2) deduplication to select the orbit +# orbit: list[np.ndarray] = [] +# for pp in coords: +# pp = np.mod(np.round(pp, decimals=10), 1) # round and mod to avoid duplication +# if not in_array_list(orbit, pp): +# orbit.append(pp) +# orbit -= np.floor(orbit) # wrap back to 0-1 +# assert (orbit.shape[0] == sym_group.mult_table[g-1, w]) # double check that the orbit has the right length +# return orbit + +# def symmetrize_atoms_pmg(g, w, x): +# sg = SpaceGroup.from_int_number(g) +# xs = sg.get_orbit(x) +# m = sym_group.mult_table[g-1, w] +# assert (len(xs) == m) # double check that the orbit has the right length +# return np.array(xs) + +# def allclose_up_to_permutation(xs, xs_pmg): +# # Sort each array lexicographically by rows +# sorted_xs = xs[np.lexsort(np.rot90(xs))] +# sorted_xs_pmg = xs_pmg[np.lexsort(np.rot90(xs_pmg))] +# # Check if the sorted arrays are equal +# return np.allclose(sorted_xs, sorted_xs_pmg) + +# g = 166 +# w = jnp.array(3) +# x = jnp.array([0., 0., 0.5619]) +# xs = symmetrize_atoms(sym_group, g, w, x) +# print ('xs:\n', xs) +# assert allclose_up_to_permutation(xs, symmetrize_atoms_pmg(g, w, x)) +# assert allclose_up_to_permutation(xs, symmetrize_atoms_deduplication(g, w, x)) + +# g = 225 +# w = jnp.array(5) +# x = jnp.array([0., 0., 0.7334]) +# xs = symmetrize_atoms(sym_group, g, w, x) +# print ('xs:\n', xs) +# assert allclose_up_to_permutation(xs, symmetrize_atoms_pmg(g, w, x)) +# assert allclose_up_to_permutation(xs, symmetrize_atoms_deduplication(g, w, x)) + +# g = 225 +# w = jnp.array(8) +# x = jnp.array([0.0, 0.23, 0.23]) +# xs = symmetrize_atoms(sym_group, g, w, x) +# print ('xs:\n', xs) +# assert allclose_up_to_permutation(xs, symmetrize_atoms_pmg(g, w, x)) +# assert allclose_up_to_permutation(xs, symmetrize_atoms_deduplication(g, w, x)) + +# test_symmetrize_atoms() +test_wyckoff() \ No newline at end of file diff --git a/try.ipynb b/try.ipynb new file mode 100644 index 0000000..3850d06 --- /dev/null +++ b/try.ipynb @@ -0,0 +1,377 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'epochs': 10000, 'batchsize': 100, 'lr': 0.0001, 'lr_decay': 0.0, 'weight_decay': 0.0, 'clip_grad': 1.0, 'optimizer': 'adam', 'folder': './', 'restore_path': None, 'training_name': '${folder}${optimizer}_bs_${batchsize}_lr_${lr}_decay_${lr_decay}_clip_${clip_grad}', 'train_path': '/data/zdcao/crystal_gpt/dataset/mp_20/train.csv', 'valid_path': '/data/zdcao/crystal_gpt/dataset/mp_20/val.csv', 'test_path': '/data/zdcao/crystal_gpt/dataset/mp_20/test.csv', 'Nf': 5, 'Kx': 16, 'Kl': 4, 'h0_size': 256, 'transformer_layers': 16, 'num_heads': 16, 'key_size': 64, 'model_size': 64, 'embed_size': 32, 'dropout_rate': 0.5, 'transformer_name': 'Nf_${Nf}_Kx_${Kx}_Kl_${Kl}_h0_${h0_size}_l_${transformer_layers}_H_${num_heads}_k_${key_size}_m_${model_size}_e_${embed_size}_drop_${dropout_rate}', 'lamb_a': 1.0, 'lamb_w': 1.0, 'lamb_l': 1.0, 'loss_name': 'a_${lamb_a}_w_${lamb_w}_l_${lamb_l}', 'n_max': 21, 'atom_types': 119, 'wyck_types': 28, 'physics_name': 'A_${atom_types}_W_${wyck_types}_N_${n_max}', 'spacegroup': None, 'elements': None, 'top_p': 1.0, 'temperature': 1.0, 'num_io_process': 40, 'num_samples': 1000, 'use_foriloop': True, 'output_filename': 'output.csv'}\n", + "\n", + "========== Load checkpoint==========\n", + "No checkpoint file found. Start from scratch.\n", + "# of transformer params 461159\n" + ] + } + ], + "source": [ + "import sys\n", + "sys.path.append('./crystalformer/src/')\n", + "\n", + "import jax\n", + "import jax.numpy as jnp\n", + "from jax.flatten_util import ravel_pytree\n", + "from hydra import initialize, compose\n", + "\n", + "\n", + "import checkpoint\n", + "from transformer import make_transformer\n", + "\n", + "with initialize(version_base=None, config_path=\"./model\"):\n", + " args = compose(config_name=\"config\")\n", + " print(args)\n", + "\n", + "key = jax.random.PRNGKey(42)\n", + "params, transformer = make_transformer(key, args.Nf, args.Kx, args.Kl, args.n_max,\n", + " args.h0_size,\n", + " 4, 8,\n", + " 32, args.model_size, args.embed_size,\n", + " args.atom_types, args.wyck_types,\n", + " 0.3)\n", + "\n", + "\n", + "print(\"\\n========== Load checkpoint==========\")\n", + "restore_path = \"./share/\"\n", + "ckpt_filename, epoch_finished = checkpoint.find_ckpt_filename(restore_path)\n", + "if ckpt_filename is not None:\n", + " print(\"Load checkpoint file: %s, epoch finished: %g\" %(ckpt_filename, epoch_finished))\n", + " ckpt = checkpoint.load_data(ckpt_filename)\n", + " params = ckpt[\"params\"]\n", + "else:\n", + " print(\"No checkpoint file found. Start from scratch.\")\n", + "\n", + "print (\"# of transformer params\", ravel_pytree(params)[0].size)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "import numpy as np\n", + "from pymatgen.core import Structure, Lattice\n", + "from time import time\n", + "from pymatgen.io.ase import AseAtomsAdaptor\n", + "from ase.visualize import view\n", + "\n", + "from sample import sample_crystal\n", + "from elements import element_dict, element_list\n", + "from scripts.awl2struct import get_struct_from_lawx\n", + "\n", + "jax.config.update(\"jax_enable_x64\", True) # to get off compilation warning, and to prevent sample nan lattice\n", + "\n", + "\n", + "def generate_and_visualize(spacegroup, elements, temperature, seed):\n", + "\n", + " print(f\"Generating with spacegroup={spacegroup}, elements={elements}, temperature={temperature}\")\n", + " \n", + " top_p = 1\n", + " n_sample = 1\n", + " elements = elements.split()\n", + " if elements is not None:\n", + " idx = [element_dict[e] for e in elements]\n", + " atom_mask = [1] + [1 if a in idx else 0 for a in range(1, args.atom_types)]\n", + " atom_mask = jnp.array(atom_mask)\n", + " # print ('sampling structure formed by these elements:', elements)\n", + " # print (atom_mask)\n", + " # print(\"@\")\n", + " else:\n", + " atom_mask = jnp.zeros((args.atom_types), dtype=int) # we will do nothing to a_logit in sampling\n", + " print (atom_mask)\n", + " \n", + " # fix\n", + " atom_mask = jnp.repeat(atom_mask.reshape(1, -1), args.n_max, axis=0)\n", + " key = jax.random.PRNGKey(seed)\n", + " key, subkey = jax.random.split(key)\n", + " start_time = time()\n", + "# import pdb\n", + "# pdb.set_trace()\n", + " constraints = jnp.arange(0, args.n_max, 1)\n", + " XYZ, A, W, M, L = sample_crystal(subkey, transformer, params, args.n_max, n_sample, args.atom_types, args.wyck_types, args.Kx, args.Kl, spacegroup, None, atom_mask, top_p, temperature, temperature, constraints)\n", + " end_time = time()\n", + " print(\"executation time:\", end_time - start_time)\n", + " \n", + " XYZ = np.array(XYZ)\n", + " A = np.array(A)\n", + " W = np.array(W)\n", + " L = np.array(L)\n", + " print(W, L)\n", + " \n", + " G = np.array([spacegroup for i in range(len(L))])\n", + " \n", + " structures = [get_struct_from_lawx(g, l, a, w, xyz) for g, l, a, w, xyz in zip(G, L, A, W, XYZ)]\n", + " structures = [Structure.from_dict(_) for _ in structures]\n", + " \n", + " \n", + " atoms_list = [AseAtomsAdaptor().get_atoms(struct) for struct in structures]\n", + " return view(atoms_list[0], viewer='ngl')\n", + " # return \n", + " # return structures" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Generating with spacegroup=70, elements=C, temperature=0.5\n", + "executation time: 0.015363216400146484\n", + "[[3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]] [[-8.38335365e-01 -8.38335365e-01 -6.07996439e-02 9.00000000e+01\n", + " 9.00000000e+01 1.20000000e+02]]\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "dcdd61af33a14add83389c8f0d2c0b6c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(NGLWidget(), VBox(children=(Dropdown(description='Show', options=('All', 'C'), value='All'), Dr…" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "# ============= params to control the generation =============\n", + "spacegroup = 70 # 设置生成的晶体的空间群,范围为1-230\n", + "elements = \"C\" # 限制生成晶体所包含的元素种类,每个元素需要用空格隔开,比如 \"Ba Ti O\"\n", + "temperature = 0.5 # 控制transformer生成的温度,温度越高生成的novelty越高,推荐值为 0.5到1.5\n", + "seed = 42 # 随机种子\n", + "\n", + "# =============== generate and visualization =================\n", + "generate_and_visualize(spacegroup, elements, temperature, seed)\n", + "# structures = generate_and_visualize(spacegroup, elements, temperature, seed)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": true, + "jupyter": { + "outputs_hidden": true + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[Structure Summary\n", + " Lattice\n", + " abc : 1.9728497519367452 1.9728497519367452 1.9728497519367452\n", + " angles : 90.0 90.0 90.0\n", + " volume : 7.678599825635881\n", + " A : -1.9728497519367452 0.0 -1.2080220669539923e-16\n", + " B : 1.2080220669539923e-16 -1.9728497519367452 -1.2080220669539923e-16\n", + " C : 0.0 0.0 -1.9728497519367452\n", + " pbc : True True True\n", + " PeriodicSite: C (-1.611, 0.0, -1.001) [0.8164, 0.0, 0.5073]\n", + " PeriodicSite: C (9.863e-17, -1.611, -1.001) [0.0, 0.8164, 0.5073]\n", + " PeriodicSite: C (-0.3621, -0.3621, -1.001) [0.1836, 0.1836, 0.5073]\n", + " PeriodicSite: C (-0.3621, 0.0, -1.001) [0.1836, 0.0, 0.5073]\n", + " PeriodicSite: C (2.217e-17, -0.3621, -1.001) [0.0, 0.1836, 0.5073]\n", + " PeriodicSite: C (-1.611, -1.611, -1.001) [0.8164, 0.8164, 0.5073]\n", + " PeriodicSite: C (9.863e-17, -1.611, -0.972) [0.0, 0.8164, 0.4927]\n", + " PeriodicSite: C (-1.611, 0.0, -0.972) [0.8164, 0.0, 0.4927]\n", + " PeriodicSite: C (-0.3621, -0.3621, -0.972) [0.1836, 0.1836, 0.4927]\n", + " PeriodicSite: C (2.217e-17, -0.3621, -0.972) [0.0, 0.1836, 0.4927]\n", + " PeriodicSite: C (-0.3621, 0.0, -0.972) [0.1836, 0.0, 0.4927]\n", + " PeriodicSite: C (-1.611, -1.611, -0.972) [0.8164, 0.8164, 0.4927]\n", + " PeriodicSite: C (-1.023, 0.0, -0.1123) [0.5186, 0.0, 0.05695]\n", + " PeriodicSite: C (6.265e-17, -1.023, -0.1123) [0.0, 0.5186, 0.05695]\n", + " PeriodicSite: C (-0.9497, -0.9497, -0.1123) [0.4814, 0.4814, 0.05695]\n", + " PeriodicSite: C (-0.9497, 0.0, -0.1123) [0.4814, 0.0, 0.05695]\n", + " PeriodicSite: C (5.815e-17, -0.9497, -0.1123) [0.0, 0.4814, 0.05695]\n", + " PeriodicSite: C (-1.023, -1.023, -0.1123) [0.5186, 0.5186, 0.05695]\n", + " PeriodicSite: C (6.265e-17, -1.023, -1.861) [0.0, 0.5186, 0.9431]\n", + " PeriodicSite: C (-1.023, 0.0, -1.861) [0.5186, 0.0, 0.9431]\n", + " PeriodicSite: C (-0.9497, -0.9497, -1.861) [0.4814, 0.4814, 0.9431]\n", + " PeriodicSite: C (5.815e-17, -0.9497, -1.861) [0.0, 0.4814, 0.9431]\n", + " PeriodicSite: C (-0.9497, 0.0, -1.861) [0.4814, 0.0, 0.9431]\n", + " PeriodicSite: C (-1.023, -1.023, -1.861) [0.5186, 0.5186, 0.9431]\n", + " PeriodicSite: C (-1.47, -0.7232, -1.343e-16) [0.7449, 0.3666, 0.0]\n", + " PeriodicSite: C (-1.25, -0.7465, -1.222e-16) [0.6334, 0.3784, 0.0]\n", + " PeriodicSite: C (-1.226, -0.5032, -1.059e-16) [0.6216, 0.2551, 0.0]\n", + " PeriodicSite: C (-0.5032, -1.25, -1.073e-16) [0.2551, 0.6334, 0.0]\n", + " PeriodicSite: C (-0.7232, -1.226, -1.194e-16) [0.3666, 0.6216, 0.0]\n", + " PeriodicSite: C (-0.7465, -1.47, -1.357e-16) [0.3784, 0.7449, 0.0]\n", + " PeriodicSite: C (-0.7232, -1.47, -1.343e-16) [0.3666, 0.7449, 0.0]\n", + " PeriodicSite: C (-0.7465, -1.25, -1.222e-16) [0.3784, 0.6334, 0.0]\n", + " PeriodicSite: C (-0.5032, -1.226, -1.059e-16) [0.2551, 0.6216, 0.0]\n", + " PeriodicSite: C (-1.25, -0.5032, -1.073e-16) [0.6334, 0.2551, 0.0]\n", + " PeriodicSite: C (-1.226, -0.7232, -1.194e-16) [0.6216, 0.3666, 0.0]\n", + " PeriodicSite: C (-1.47, -0.7465, -1.357e-16) [0.7449, 0.3784, 0.0]]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "structures" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "pymatgen.core.structure.Structure" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(structures[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0.81643739, 0. , 0.50729405],\n", + " [0. , 0.81643739, 0.50729405],\n", + " [0.18356261, 0.18356261, 0.50729405],\n", + " [0.18356261, 0. , 0.50729405],\n", + " [0. , 0.18356261, 0.50729405],\n", + " [0.81643739, 0.81643739, 0.50729405],\n", + " [0. , 0.81643739, 0.49270595],\n", + " [0.81643739, 0. , 0.49270595],\n", + " [0.18356261, 0.18356261, 0.49270595],\n", + " [0. , 0.18356261, 0.49270595],\n", + " [0.18356261, 0. , 0.49270595],\n", + " [0.81643739, 0.81643739, 0.49270595],\n", + " [0.518634 , 0. , 0.05694763],\n", + " [0. , 0.518634 , 0.05694763],\n", + " [0.481366 , 0.481366 , 0.05694763],\n", + " [0.481366 , 0. , 0.05694763],\n", + " [0. , 0.481366 , 0.05694763],\n", + " [0.518634 , 0.518634 , 0.05694763],\n", + " [0. , 0.518634 , 0.94305237],\n", + " [0.518634 , 0. , 0.94305237],\n", + " [0.481366 , 0.481366 , 0.94305237],\n", + " [0. , 0.481366 , 0.94305237],\n", + " [0.481366 , 0. , 0.94305237],\n", + " [0.518634 , 0.518634 , 0.94305237],\n", + " [0.74494652, 0.36655847, 0. ],\n", + " [0.63344153, 0.37838805, 0. ],\n", + " [0.62161195, 0.25505348, 0. ],\n", + " [0.25505348, 0.63344153, 0. ],\n", + " [0.36655847, 0.62161195, 0. ],\n", + " [0.37838805, 0.74494652, 0. ],\n", + " [0.36655847, 0.74494652, 0. ],\n", + " [0.37838805, 0.63344153, 0. ],\n", + " [0.25505348, 0.62161195, 0. ],\n", + " [0.63344153, 0.25505348, 0. ],\n", + " [0.62161195, 0.36655847, 0. ],\n", + " [0.74494652, 0.37838805, 0. ]])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "abc = structures[0].lattice.abc\n", + "pos = structures[0].frac_coords\n", + "pos" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "fig = plt.figure()\n", + "ax = fig.add_subplot(111)\n", + "x = pos[:,0]*abc[0]\n", + "y = pos[:,1]*abc[1]\n", + "# x = np.array([x[2],x[1],x[2],x[0],x[2]+abc[0]])\n", + "# y = np.array([y[2]+abc[1],y[1],y[2],y[0],y[2]])\n", + "for i in range(3):\n", + " for j in range(3):\n", + " ax.scatter(x+i*abc[0],y+j*abc[1])\n", + " # ax.plot(x+i*abc[0],y+j*abc[1])\n", + " # ax.plot()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "crystalformer", + "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.10.15" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/try.py b/try.py new file mode 100644 index 0000000..ede316f --- /dev/null +++ b/try.py @@ -0,0 +1,108 @@ +import sys +sys.path.append('./crystalformer/src/') + +import jax +import jax.numpy as jnp +from jax.flatten_util import ravel_pytree +from hydra import initialize, compose + + +import checkpoint +from transformer import make_transformer + +with initialize(version_base=None, config_path="./model"): + args = compose(config_name="config") + print(args) + +key = jax.random.PRNGKey(42) +params, transformer = make_transformer(key, args.Nf, args.Kx, args.Kl, args.n_max, + args.h0_size, + 4, 8, + 32, args.model_size, args.embed_size, + args.atom_types, args.wyck_types, + 0.3) + + +print("\n========== Load checkpoint==========") +restore_path = "./share/" +ckpt_filename, epoch_finished = checkpoint.find_ckpt_filename(restore_path) +if ckpt_filename is not None: + print("Load checkpoint file: %s, epoch finished: %g" %(ckpt_filename, epoch_finished)) + ckpt = checkpoint.load_data(ckpt_filename) + params = ckpt["params"] +else: + print("No checkpoint file found. Start from scratch.") + +print ("# of transformer params", ravel_pytree(params)[0].size) + + + +import numpy as np +from pymatgen.core import Structure, Lattice +from time import time +from pymatgen.io.ase import AseAtomsAdaptor +from ase.visualize import view + +from sym_group import SpaceGroup +from sample import sample_crystal +from elements import element_dict, element_list +from scripts.awl2struct import get_struct_from_lawx + +jax.config.update("jax_enable_x64", True) # to get off compilation warning, and to prevent sample nan lattice + + +def generate_and_visualize(spacegroup, elements, temperature, seed): + + print(f"Generating with spacegroup={spacegroup}, elements={elements}, temperature={temperature}") + + top_p = 1 + n_sample = 1 + elements = elements.split() + if elements is not None: + idx = [element_dict[e] for e in elements] + atom_mask = [1] + [1 if a in idx else 0 for a in range(1, args.atom_types)] + atom_mask = jnp.array(atom_mask) + # print ('sampling structure formed by these elements:', elements) + # print (atom_mask) + # print("@") + else: + atom_mask = jnp.zeros((args.atom_types), dtype=int) # we will do nothing to a_logit in sampling + print (atom_mask) + + # fix + atom_mask = jnp.repeat(atom_mask.reshape(1, -1), args.n_max, axis=0) + key = jax.random.PRNGKey(seed) + key, subkey = jax.random.split(key) + start_time = time() +# import pdb +# pdb.set_trace() + constraints = jnp.arange(0, args.n_max, 1) + XYZ, A, W, M, L = sample_crystal(SpaceGroup(), subkey, transformer, params, args.n_max, n_sample, args.atom_types, args.wyck_types, args.Kx, args.Kl, spacegroup, None, atom_mask, top_p, temperature, temperature, constraints) + end_time = time() + print("executation time:", end_time - start_time) + + XYZ = np.array(XYZ) + A = np.array(A) + W = np.array(W) + L = np.array(L) + + G = np.array([spacegroup for i in range(len(L))]) + + structures = [get_struct_from_lawx(g, l, a, w, xyz) for g, l, a, w, xyz in zip(G, L, A, W, XYZ)] + structures = [Structure.from_dict(_) for _ in structures] + + + atoms_list = [AseAtomsAdaptor().get_atoms(struct) for struct in structures] + return view(atoms_list[0], viewer='ngl') + + + + +# ============= params to control the generation ============= +spacegroup = 2 # 设置生成的晶体的空间群,范围为1-230 +elements = "Ba Ti O" # 限制生成晶体所包含的元素种类,每个元素需要用空格隔开,比如 "Ba Ti O" +temperature = 1.0 # 控制transformer生成的温度,温度越高生成的novelty越高,推荐值为 0.5到1.5 +seed = 42 # 随机种子 + +# =============== generate and visualization ================= +generate_and_visualize(spacegroup, elements, temperature, seed) \ No newline at end of file