|
20 | 20 | "The following happens in the script below:\n", |
21 | 21 | "\n", |
22 | 22 | "1. Install the required packages\n", |
23 | | - "1. The files are extracted from `user_uploads` folder assuming their extensions represent the format - e.g. `SiO2.poscar`.\n", |
| 23 | + "1. The files are extracted from `uploads` folder assuming their extensions represent the format - e.g. `SiO2.poscar`, `Ni.pwi`.\n", |
24 | 24 | "1. Structural information is read from files into ASE Atoms objects.\n", |
25 | 25 | "1. ASE Atoms objects are converted to `poscar` format \n", |
26 | 26 | "1. `poscar` structures are converted to ESSE\n", |
27 | | - "1. The results are passed to the outside runtime" |
| 27 | + "1. The results are visualized and passed to the outside runtime" |
28 | 28 | ] |
29 | 29 | }, |
30 | 30 | { |
|
42 | 42 | "source": [ |
43 | 43 | "# Upload files to this folder\n", |
44 | 44 | "FOLDER_PATH = \"./uploads\"\n", |
45 | | - "# Attempt to guess the format from file extension\n", |
46 | | - "# If set to specific format, it will only accept that format\n", |
47 | | - "ENFORCED_FORMAT = None\n", |
| 45 | + "\n", |
| 46 | + "# By default, format will be guessed from file extension\n", |
| 47 | + "# If set to specific format, notebook will only read that format\n", |
| 48 | + "ENFORCED_FORMATS = None # e.g. [\"cif\", \"espresso-in\"]\n", |
| 49 | + "\n", |
48 | 50 | "# If set to true, the file extension will be included in the resulting material name\n", |
49 | 51 | "USE_FILE_NAME_NO_EXTENSION = False\n", |
50 | | - "# If set to true, the supported formats will be printed below\n", |
| 52 | + "\n", |
| 53 | + "# If set to true, the supported formats and required extensions will be printed below\n", |
51 | 54 | "SHOW_SUPPORTED_FORMATS = False" |
52 | 55 | ], |
53 | 56 | "outputs": [], |
|
86 | 89 | "source": [ |
87 | 90 | "## 3. Data Processing\n", |
88 | 91 | "\n", |
89 | | - "### 3.1. Read data from files" |
| 92 | + "### 3.1. Read data from files in `uploads` folder" |
90 | 93 | ] |
91 | 94 | }, |
92 | 95 | { |
|
101 | 104 | "from pathlib import Path\n", |
102 | 105 | "from ase.io import read\n", |
103 | 106 | "\n", |
104 | | - "materials = []\n", |
105 | | - "unreadable_files = []\n", |
| 107 | + "ase_atoms, readable_file_names, unreadable_file_names = [], [], []\n", |
106 | 108 | "file_names = os.listdir(FOLDER_PATH)\n", |
107 | 109 | "\n", |
108 | 110 | "for file_name in file_names:\n", |
109 | 111 | " file_path = os.path.join(FOLDER_PATH, file_name)\n", |
110 | | - " try:\n", |
111 | | - " atoms = read(file_path, format=ENFORCED_FORMAT)\n", |
| 112 | + " formats = ENFORCED_FORMATS or [None]\n", |
112 | 113 | "\n", |
113 | | - " atoms.info[\"file_name\"] = Path(file_name).stem if USE_FILE_NAME_NO_EXTENSION else file_name\n", |
114 | | - " materials.append(atoms)\n", |
115 | | - " \n", |
116 | | - " except Exception as e:\n", |
117 | | - " print(e)\n", |
118 | | - " unreadable_files.append(file_name)\n", |
119 | | - " continue" |
| 114 | + " for fmt in formats:\n", |
| 115 | + " try:\n", |
| 116 | + " atoms = read(file_path, format=fmt)\n", |
| 117 | + " atoms.info[\"file_name\"] = Path(file_name).stem if USE_FILE_NAME_NO_EXTENSION else file_name\n", |
| 118 | + " ase_atoms.append(atoms)\n", |
| 119 | + " readable_file_names.append(file_name)\n", |
| 120 | + " print(\"Successfully read:\", atoms.info[\"file_name\"], \"using format:\", fmt)\n", |
| 121 | + " break\n", |
| 122 | + " except Exception:\n", |
| 123 | + " continue\n", |
| 124 | + " else:\n", |
| 125 | + " unreadable_file_names.append(file_name)\n", |
| 126 | + " print(\"Failed to read:\", file_name)" |
120 | 127 | ], |
121 | 128 | "outputs": [], |
122 | 129 | "execution_count": null |
|
125 | 132 | "cell_type": "markdown", |
126 | 133 | "id": "57b0d358", |
127 | 134 | "metadata": {}, |
128 | | - "source": [ |
129 | | - "### 3.2. Preview the data" |
130 | | - ] |
| 135 | + "source": "### 3.2. List imported the data" |
131 | 136 | }, |
132 | 137 | { |
133 | 138 | "cell_type": "code", |
134 | 139 | "id": "0e34472a", |
135 | 140 | "metadata": {}, |
136 | 141 | "source": [ |
137 | | - "print(f\"Successfully read {len(materials)} files\")\n", |
138 | | - "print(f\"Unreadable files: {unreadable_files}. \")\n" |
| 142 | + "print(f\"Successfully read {len(ase_atoms)} files: {readable_file_names}. \")\n", |
| 143 | + "print(f\"Unreadable files: {unreadable_file_names}. \")" |
139 | 144 | ], |
140 | 145 | "outputs": [], |
141 | 146 | "execution_count": null |
|
153 | 158 | "id": "a771a36a", |
154 | 159 | "metadata": {}, |
155 | 160 | "source": [ |
156 | | - "# Uncomment to see the list of supported formats and their file extensions\n", |
157 | 161 | "from ase.io.formats import ioformats\n", |
158 | 162 | "import pandas as pd\n", |
159 | 163 | "\n", |
160 | | - "if len(unreadable_files) > 0 or SHOW_SUPPORTED_FORMATS:\n", |
161 | | - " print(f\"Unreadable files found: {unreadable_files}. See formats/extensions below.\")\n", |
| 164 | + "if len(unreadable_file_names) > 0 or SHOW_SUPPORTED_FORMATS:\n", |
| 165 | + " print(f\"Unreadable files found: {unreadable_file_names}. See formats/extensions below.\")\n", |
162 | 166 | " data = [[frmt.name, frmt.extensions, frmt.description] for frmt in ioformats.values()]\n", |
163 | 167 | " dataframe = pd.DataFrame(data, columns=[\"Format Name\", \"File Extensions\", \"Description\"])\n", |
164 | 168 | " print(dataframe.to_markdown())" |
|
188 | 192 | "from express import ExPrESS\n", |
189 | 193 | "\n", |
190 | 194 | "def ase_to_poscar(atoms: Atoms):\n", |
191 | | - " \"\"\"\n", |
192 | | - " Converts ase.Atoms object to POSCAR format\n", |
193 | | - "\n", |
194 | | - " Args:\n", |
195 | | - " atoms (ase.Atoms): ase.Atoms object\n", |
196 | | - "\n", |
197 | | - " Returns:\n", |
198 | | - " str: POSCAR string\n", |
199 | | - " \"\"\"\n", |
200 | 195 | " output = io.StringIO()\n", |
201 | | - " write(output, atoms, format=\"vasp\")\n", |
202 | | - " content = output.getvalue()\n", |
203 | | - " output.close()\n", |
| 196 | + " try:\n", |
| 197 | + " write(output, atoms, format=\"vasp\")\n", |
| 198 | + " content = output.getvalue()\n", |
| 199 | + " except Exception as e:\n", |
| 200 | + " print(f\"Error converting ASE atoms to POSCAR: {e}\")\n", |
| 201 | + " content = None\n", |
| 202 | + " finally:\n", |
| 203 | + " output.close()\n", |
204 | 204 | "\n", |
205 | 205 | " return content\n", |
206 | 206 | "\n", |
207 | 207 | "def convert_ase_entry_to_esse(ase_entry):\n", |
208 | | - " poscar = ase_to_poscar(ase_entry)\n", |
209 | | - " kwargs = {\n", |
210 | | - " \"structure_string\": poscar,\n", |
211 | | - " \"structure_format\": \"poscar\"\n", |
212 | | - " }\n", |
| 208 | + " try:\n", |
| 209 | + " poscar = ase_to_poscar(ase_entry)\n", |
| 210 | + " if poscar is None:\n", |
| 211 | + " raise ValueError(\"Failed to generate POSCAR string\")\n", |
213 | 212 | "\n", |
214 | | - " handler = ExPrESS(\"structure\", **kwargs)\n", |
215 | | - " esse = handler.property(\"material\", **kwargs)\n", |
216 | | - " \n", |
217 | | - " esse[\"name\"] = ase_entry.info[\"file_name\"]\n", |
218 | | - " \n", |
219 | | - " return esse\n", |
| 213 | + " kwargs = {\n", |
| 214 | + " \"structure_string\": poscar,\n", |
| 215 | + " \"structure_format\": \"poscar\"\n", |
| 216 | + " }\n", |
| 217 | + "\n", |
| 218 | + " handler = ExPrESS(\"structure\", **kwargs)\n", |
| 219 | + " esse = handler.property(\"material\", **kwargs)\n", |
| 220 | + "\n", |
| 221 | + " esse[\"name\"] = ase_entry.info.get(\"file_name\", \"Unknown\")\n", |
| 222 | + "\n", |
| 223 | + " return esse\n", |
| 224 | + " except Exception as e:\n", |
| 225 | + " print(f\"Error processing ASE entry: {e}\")\n", |
| 226 | + " return None\n", |
220 | 227 | "\n", |
221 | | - "esse_entries = list(map(convert_ase_entry_to_esse, materials))" |
| 228 | + "esse_entries = [entry for entry in map(convert_ase_entry_to_esse, ase_atoms) if entry is not None]" |
222 | 229 | ], |
223 | 230 | "outputs": [], |
224 | 231 | "execution_count": null |
|
0 commit comments