-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/SOF-7339 update: rewrite ZSL notebook to use made-tools #118
Changes from all commits
ecabfdb
9d4815f
78c7e0f
e6abb84
913dae3
be1e72c
bd3f6d1
73f94d8
923d471
bb9a6d6
7be52d9
ecd3857
1509db8
3390054
49ea2f1
3ad723a
fafedc6
fcd7582
8a5e59d
72e825c
9782033
0e94158
89acf15
c3a77a8
7c351ea
4a5c147
84a9443
923bb53
d4a07d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,13 +46,11 @@ | |
"outputs": [], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can just pass
substrate = materials[0] layer = materials[1] There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line #5. interfaces_range = slice(0, 1) # select the first interface with the lowest strain Let's move the comment above and add with the lowest strain and number of atoms
The actual selection by termination and slice functionality can go to the holder class itself too Reply via ReviewNB There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line #4. materials = list(map(lambda interface_config: from_pymatgen(interface_config), selected_interface)) This lambda function can go to interface_data_holder Reply via ReviewNB There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line #4. await micropip.install('mat3ra-api-examples[dev]', deps=False) Remove Reply via ReviewNB There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line #1. print(interface_data_holder.terminations)
Maybe we should print the number of interfaces for the first termination, not all of them Should be:
print(f"Terminations found: {interface_data_holder.terminations)}") print(f"Interfaces for the first termination: {interface_data_holder.get_interfaces_for_termination(0))}") Reply via ReviewNB There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line #3. materials = list(selected_interface) We should not need Reply via ReviewNB There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We probably don't need print statement here either. We should instead add a visualization function to plot the selected interface(s) in a subsequent task |
||
"source": [ | ||
"SUBSTRATE_PARAMETERS = {\n", | ||
" \"MATERIAL_INDEX\": 0, # the index of the material in the materials_in list\n", | ||
" \"MILLER_INDICES\": (1, 1, 1), # the miller indices of the interfacial plane\n", | ||
" \"THICKNESS\": 3, # in layers\n", | ||
"}\n", | ||
"\n", | ||
"LAYER_PARAMETERS = {\n", | ||
" \"MATERIAL_INDEX\": 1, # the index of the material in the materials_in list\n", | ||
" \"MILLER_INDICES\": (0, 0, 1), # the miller indices of the interfacial plane\n", | ||
" \"THICKNESS\": 1, # in layers\n", | ||
"}\n", | ||
|
@@ -107,7 +105,8 @@ | |
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## 2. Install Packages" | ||
"## 2. Install Packages\n", | ||
"The step executes only in Pyodide environment. For other environments, the packages should be installed via `pip install` as directed in README." | ||
] | ||
}, | ||
{ | ||
|
@@ -120,35 +119,30 @@ | |
"if sys.platform == \"emscripten\":\n", | ||
" import micropip\n", | ||
" await micropip.install('mat3ra-api-examples', deps=False)\n", | ||
"from utils.jupyterlite import install_packages\n", | ||
"await install_packages(\"create_interface_with_min_strain_zsl.ipynb\",\"../../config.yml\")" | ||
" from utils.jupyterlite import install_packages\n", | ||
" await install_packages(\"create_interface_with_min_strain_zsl.ipynb\",\"../../config.yml\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## 3. Load and prepare input Materials\n" | ||
"## 3. Load input Materials\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"outputs": [], | ||
"source": [ | ||
"from utils.jupyterlite import get_data\n", | ||
"from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer\n", | ||
"from src.utils import to_pymatgen\n", | ||
"from mat3ra.made.material import Material\n", | ||
"\n", | ||
"# Get the list of input materials and load them into `materials_in` variable\n", | ||
"get_data(\"materials_in\", globals())\n", | ||
"\n", | ||
"if \"materials_in\" in globals():\n", | ||
" pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", | ||
" if USE_CONVENTIONAL_CELL: pymatgen_materials = [SpacegroupAnalyzer(item).get_conventional_standard_structure() for\n", | ||
" item in pymatgen_materials]\n", | ||
"\n", | ||
" for material in pymatgen_materials:\n", | ||
" print(material, \"\\n\")" | ||
"materials = [] \n", | ||
"for material_config in globals()[\"materials_in\"]:\n", | ||
" print(material_config, \"\\n\")\n", | ||
" materials.append(Material(material_config))" | ||
], | ||
"metadata": { | ||
"collapsed": false | ||
|
@@ -177,66 +171,28 @@ | |
}, | ||
"outputs": [], | ||
"source": [ | ||
"from src.pymatgen_coherent_interface_builder import CoherentInterfaceBuilder, ZSLGenerator\n", | ||
"from src.utils import translate_to_bottom\n", | ||
"\n", | ||
"# Translate the materials to the bottom of the cell to allow for multilayer heterostructures creation\n", | ||
"pymatgen_materials = [translate_to_bottom(item) for item in pymatgen_materials]\n", | ||
" \n", | ||
"def create_interfaces(settings):\n", | ||
" print(\"Creating interfaces...\")\n", | ||
" zsl = ZSLGenerator(\n", | ||
" max_area_ratio_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA_TOL\"],\n", | ||
" max_area=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA\"],\n", | ||
" max_length_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_LENGTH_TOL\"],\n", | ||
" max_angle_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_ANGLE_TOL\"],\n", | ||
" )\n", | ||
"\n", | ||
" cib = CoherentInterfaceBuilder(\n", | ||
" substrate_structure=pymatgen_materials[settings[\"SUBSTRATE_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", | ||
" film_structure=pymatgen_materials[settings[\"LAYER_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", | ||
" substrate_miller=settings[\"SUBSTRATE_PARAMETERS\"][\"MILLER_INDICES\"],\n", | ||
" film_miller=settings[\"LAYER_PARAMETERS\"][\"MILLER_INDICES\"],\n", | ||
" zslgen=zsl,\n", | ||
" strain_tol=settings[\"ZSL_PARAMETERS\"][\"STRAIN_TOL\"],\n", | ||
" )\n", | ||
"\n", | ||
" # Find terminations\n", | ||
" cib._find_terminations()\n", | ||
" terminations = cib.terminations\n", | ||
"from mat3ra.made.tools.build import create_interfaces\n", | ||
"\n", | ||
" # Create interfaces for each termination\n", | ||
" interfaces = {}\n", | ||
" for termination in terminations:\n", | ||
" interfaces[termination] = []\n", | ||
" for interface in cib.get_interfaces(\n", | ||
" termination,\n", | ||
" gap=settings[\"INTERFACE_PARAMETERS\"][\"DISTANCE_Z\"],\n", | ||
" film_thickness=settings[\"LAYER_PARAMETERS\"][\"THICKNESS\"],\n", | ||
" substrate_thickness=settings[\"SUBSTRATE_PARAMETERS\"][\"THICKNESS\"],\n", | ||
" in_layers=True,\n", | ||
" ):\n", | ||
" # Wrap atoms to unit cell\n", | ||
" interface[\"interface\"].make_supercell((1, 1, 1), to_unit_cell=True)\n", | ||
" interfaces[termination].append(interface)\n", | ||
" return interfaces, terminations\n", | ||
"\n", | ||
"\n", | ||
"interfaces, terminations = create_interfaces(\n", | ||
"interface_data_holder = create_interfaces(\n", | ||
" substrate=materials[0],\n", | ||
" layer=materials[1],\n", | ||
" settings={\n", | ||
" \"SUBSTRATE_PARAMETERS\": SUBSTRATE_PARAMETERS,\n", | ||
" \"LAYER_PARAMETERS\": LAYER_PARAMETERS,\n", | ||
" \"USE_CONVENTIONAL_CELL\": USE_CONVENTIONAL_CELL,\n", | ||
" \"ZSL_PARAMETERS\": ZSL_PARAMETERS,\n", | ||
" \"INTERFACE_PARAMETERS\": INTERFACE_PARAMETERS,\n", | ||
" }\n", | ||
" },\n", | ||
" sort_by_strain_and_size=True,\n", | ||
" remove_duplicates=True,\n", | ||
")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### 5.2. Print out the interfaces and terminations" | ||
"### 4.2. Print out the interfaces and terminations" | ||
] | ||
}, | ||
{ | ||
|
@@ -245,18 +201,15 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"print(f'Found {len(terminations)} terminations')\n", | ||
"for termination in terminations:\n", | ||
" print(f\"Found {len(interfaces[termination])} interfaces for\", termination, \"termination\")" | ||
"print(\"Found terminations:\", interface_data_holder.terminations)\n", | ||
"print(f\"Number of interfaces for a termination: {len(interface_data_holder.get_interfaces_for_termination(0))}\")" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## 5. Sort interfaces by strain\n", | ||
"\n", | ||
"### 5.1. Sort all interfaces" | ||
"### 4.2. Print out interfaces with the lowest strain for each termination" | ||
] | ||
}, | ||
{ | ||
|
@@ -265,48 +218,19 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"# Could be \"strain\", \"von_mises_strain\", \"mean_abs_strain\"\n", | ||
"strain_mode = \"mean_abs_strain\"\n", | ||
"\n", | ||
"\n", | ||
"# Sort interfaces by the specified strain mode and number of sites\n", | ||
"def sort_interfaces(interfaces, terminations):\n", | ||
" sorted_interfaces = {}\n", | ||
" for termination in terminations:\n", | ||
" sorted_interfaces[termination] = sorted(\n", | ||
" interfaces[termination], key=lambda x: (x[strain_mode], x[\"interface\"].num_sites)\n", | ||
" )\n", | ||
" return sorted_interfaces\n", | ||
"\n", | ||
"\n", | ||
"sorted_interfaces = sort_interfaces(interfaces, terminations)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### 5.2. Print out interfaces with lowest strain for each termination" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"for termination in terminations:\n", | ||
"for termination in interface_data_holder.terminations:\n", | ||
" print(f\"Interface with lowest strain for termination {termination} (index 0):\")\n", | ||
" first_interface = sorted_interfaces[termination][0]\n", | ||
" print(\" strain:\", first_interface[strain_mode] * 100, \"%\")\n", | ||
" print(\" number of atoms:\", first_interface[\"interface\"].num_sites)" | ||
" interfaces = interface_data_holder.get_interfaces_for_termination(termination)\n", | ||
" first_interface = interfaces[0]\n", | ||
" print(f\" strain: {first_interface.get_mean_abs_strain() * 100:.3f}%\")\n", | ||
" print(\" number of atoms:\", first_interface.num_sites)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## 6. Plot the results\n", | ||
"## 5. Plot the results\n", | ||
"\n", | ||
"Plot the number of atoms vs strain. Adjust the parameters as needed.\n" | ||
] | ||
|
@@ -317,91 +241,26 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import plotly.graph_objs as go\n", | ||
"from collections import defaultdict\n", | ||
"from utils.plot import plot_strain_vs_atoms\n", | ||
"\n", | ||
"PLOT_SETTINGS = {\n", | ||
" \"HEIGHT\": 600,\n", | ||
" \"X_SCALE\": \"log\", # or linear\n", | ||
" \"Y_SCALE\": \"log\", # or linear\n", | ||
"}\n", | ||
"\n", | ||
"plot_strain_vs_atoms(interface_data_holder, PLOT_SETTINGS)\n", | ||
"\n", | ||
"def plot_strain_vs_atoms(sorted_interfaces, terminations, settings):\n", | ||
" # Create a mapping from termination to its index\n", | ||
" termination_to_index = {termination: i for i, termination in enumerate(terminations)}\n", | ||
"\n", | ||
" grouped_interfaces = defaultdict(list)\n", | ||
" for termination, interfaces in sorted_interfaces.items():\n", | ||
" for index, interface_data in enumerate(interfaces):\n", | ||
" strain_percentage = interface_data[\"mean_abs_strain\"] * 100\n", | ||
" num_sites = interface_data[\"interface\"].num_sites\n", | ||
" key = (strain_percentage, num_sites)\n", | ||
" grouped_interfaces[key].append((index, termination))\n", | ||
"\n", | ||
" data = []\n", | ||
" for (strain, num_sites), indices_and_terminations in grouped_interfaces.items():\n", | ||
" termination_indices = defaultdict(list)\n", | ||
" for index, termination in indices_and_terminations:\n", | ||
" termination_indices[termination].append(index)\n", | ||
" all_indices = [index for indices in termination_indices.values() for index in indices]\n", | ||
" index_range = f\"{min(all_indices)}-{max(all_indices)}\" if len(all_indices) > 1 else str(min(all_indices))\n", | ||
"\n", | ||
" hover_text = \"<br>-----<br>\".join(\n", | ||
" f\"Termination: {termination}<br>Termination index: {termination_to_index[termination]}<br>Interfaces Index Range: {index_range}<br>Strain: {strain:.2f}%<br>Atoms: {num_sites}\"\n", | ||
" for termination, indices in termination_indices.items()\n", | ||
" )\n", | ||
" trace = go.Scatter(\n", | ||
" x=[strain],\n", | ||
" y=[num_sites],\n", | ||
" text=[hover_text],\n", | ||
" mode=\"markers\",\n", | ||
" hoverinfo=\"text\",\n", | ||
" name=f\"Indices: {index_range}\",\n", | ||
" )\n", | ||
" data.append(trace)\n", | ||
"\n", | ||
" layout = go.Layout(\n", | ||
" xaxis=dict(title=\"Strain (%)\", type=settings[\"X_SCALE\"]),\n", | ||
" yaxis=dict(title=\"Number of atoms\", type=settings[\"Y_SCALE\"]),\n", | ||
" hovermode=\"closest\",\n", | ||
" height=settings[\"HEIGHT\"],\n", | ||
" legend_title_text=\"Interfaces Index Range\",\n", | ||
" )\n", | ||
" fig = go.Figure(data=data, layout=layout)\n", | ||
" fig.show()\n", | ||
"\n", | ||
"\n", | ||
"plot_strain_vs_atoms(sorted_interfaces, terminations, PLOT_SETTINGS)\n", | ||
"\n", | ||
"for i, termination in enumerate(terminations):\n", | ||
" print(f\"Termination {i}:\", termination)" | ||
"print(\"Terminations: \\n\", interface_data_holder.terminations)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## 7. Select the interface to pass outside this kernel\n", | ||
"## 6. Select the interface to pass outside this kernel\n", | ||
"\n", | ||
"### 7.1. Select the interface with the desired termination and strain\n", | ||
"\n", | ||
"The data in `sorted_interfaces` now contains an object with the following structure:\n", | ||
"\n", | ||
"```json\n", | ||
"{\n", | ||
" \"('C_P6/mmm_2', 'Si_R-3m_1')\": [\n", | ||
" { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 0...},\n", | ||
" { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 1...},\n", | ||
" ...\n", | ||
" ],\n", | ||
" \"<termination at index 1>\": [\n", | ||
" { ...interface for 'termination at index 1' at index 0...},\n", | ||
" { ...interface for 'termination at index 1' at index 1...},\n", | ||
" ...\n", | ||
" ]\n", | ||
"}\n", | ||
"```\n", | ||
"### 6.1. Select the interface with the desired termination and strain\n", | ||
"\n", | ||
"Select the index for termination first, and for it - the index in the list of corresponding interfaces sorted by strain (index 0 has minimum strain)." | ||
] | ||
|
@@ -412,19 +271,18 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"termination_index = 0\n", | ||
"number_of_interfaces_to_include = 1\n", | ||
"\n", | ||
"termination = terminations[termination_index]\n", | ||
"\n", | ||
"selected_interfaces = sorted_interfaces[termination][:number_of_interfaces_to_include]" | ||
"# Could be either the termination as tuple, e.g. `('Ni_P6/mmm_1', 'C_C2/m_2')` or its index: `0`\n", | ||
"termination_or_its_index = 0\n", | ||
"# select the first interface with the lowest strain and the smallest number of atoms\n", | ||
"interfaces_slice_range_or_index = 0\n", | ||
"selected_interfaces = interface_data_holder.get_interfaces_as_materials(termination_or_its_index, interfaces_slice_range_or_index)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"### 7.2. Pass data to the outside runtime\n" | ||
"### 6.2. Pass data to the outside runtime\n" | ||
] | ||
}, | ||
{ | ||
|
@@ -433,12 +291,9 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"from src.utils import from_pymatgen\n", | ||
"from utils.jupyterlite import set_data\n", | ||
"\n", | ||
"materials = list(map(lambda interface_config: from_pymatgen(interface_config[\"interface\"]), selected_interfaces))\n", | ||
"\n", | ||
"set_data(\"materials\", materials)" | ||
"set_data(\"materials\", selected_interfaces)" | ||
] | ||
} | ||
], | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we keeping this change? If yes, then how will the packages be installed in Python (not Pyodide)?
Reply via ReviewNB