diff --git a/other/materials_designer/workflows/Introduction.ipynb b/other/materials_designer/workflows/Introduction.ipynb
index c5987b4d..e2510604 100644
--- a/other/materials_designer/workflows/Introduction.ipynb
+++ b/other/materials_designer/workflows/Introduction.ipynb
@@ -51,7 +51,7 @@
"## 5. Vibrational\n",
"\n",
"### 5.1. Phonons\n",
- "#### 5.1.1. Phonon DOS and Dispersion. *(to be added)*\n",
+ "#### [5.1.1. Phonon DOS and Dispersion.](phonon_dos_dispersion.ipynb)\n",
"\n",
"\n",
"## 6. Thermodynamics\n",
diff --git a/other/materials_designer/workflows/phonon_dos_dispersion.ipynb b/other/materials_designer/workflows/phonon_dos_dispersion.ipynb
new file mode 100644
index 00000000..47b96ebf
--- /dev/null
+++ b/other/materials_designer/workflows/phonon_dos_dispersion.ipynb
@@ -0,0 +1,685 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# Phonon Density of States + Dispersions\n",
+ "\n",
+ "Compute the phonon **dispersion curves** and phonon **density of states (DOS)** of a single material using Quantum ESPRESSO on the Mat3ra platform.\n",
+ "\n",
+ "The workflow runs, in sequence: SCF (`pw.x`) → DFPT on a q-grid (`ph.x`) → interatomic force constants (`q2r.x`) → phonon DOS on a q-grid and dispersion along a high-symmetry path (`matdyn.x`).\n",
+ "\n",
+ "Single material; no reference materials or prerequisites. Phonon DFPT cost scales steeply with the number of atoms, so use a **small primitive cell**.\n",
+ "\n",
+ "
Usage
\n",
+ "\n",
+ "1. Set the material and parameters in cells 1.2 / 1.3 below (default: **Silicon**, which gives clean phonons out of the box). For harder cases (e.g. Graphene / 2D) use the controls in 1.3 — relaxation, denser k/q grids, higher cutoffs — to avoid imaginary modes.\n",
+ "2. Click \"Run\" > \"Run All\".\n",
+ "3. Inspect the phonon dispersion curves and DOS at the end. Acoustic branches should go to 0 at Γ, with no large imaginary (negative) modes.\n",
+ "\n",
+ "## Summary\n",
+ "\n",
+ "1. Set up the environment and parameters.\n",
+ "2. Authenticate and initialize API client.\n",
+ "3. Load the material.\n",
+ "4. Configure the Phonon DOS + Dispersions workflow.\n",
+ "5. Configure compute.\n",
+ "6. Create the job.\n",
+ "7. Submit and monitor the job.\n",
+ "8. Retrieve and visualize the phonon dispersion and DOS."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1",
+ "metadata": {},
+ "source": [
+ "## 1. Set up the environment and parameters\n",
+ "### 1.1. Install packages (JupyterLite)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.notebooks_utils.packages import install_packages\n",
+ "\n",
+ "await install_packages(\"made|api_examples\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3",
+ "metadata": {},
+ "source": [
+ "### 1.2. Set parameters"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from datetime import datetime\n",
+ "from mat3ra.ide.compute import QueueName\n",
+ "\n",
+ "# 2. Auth and organization parameters\n",
+ "ORGANIZATION_NAME = None\n",
+ "\n",
+ "# 3. Material parameters\n",
+ "FOLDER = \"../uploads\"\n",
+ "MATERIAL_NAME = \"Silicon\" # small primitive cell (FCC, mp-149); phonon DFPT is expensive\n",
+ "\n",
+ "# 4. Workflow parameters\n",
+ "WORKFLOW_SEARCH_TERM = \"phonon_dos_dispersion.json\"\n",
+ "APPLICATION_NAME = \"espresso\"\n",
+ "MY_WORKFLOW_NAME = \"Phonon Density of States + Dispersions\"\n",
+ "\n",
+ "# Model parameters\n",
+ "MODEL_SUBTYPE = \"gga\" # \"gga\" or \"lda\"\n",
+ "\n",
+ "# 5. Compute parameters\n",
+ "CLUSTER_NAME = None # specify full or partial name i.e. \"cluster-001\" to select\n",
+ "QUEUE_NAME = QueueName.D\n",
+ "PPN = 1\n",
+ "\n",
+ "# 6. Job parameters\n",
+ "timestamp = datetime.now().strftime(\"%Y-%m-%d %H:%M\")\n",
+ "POLL_INTERVAL = 30 # seconds"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5",
+ "metadata": {},
+ "source": [
+ "### 1.3. Set specific phonon parameters"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Method parameters\n",
+ "PSEUDOPOTENTIAL_TYPE = \"us\" # \"us\" (ultrasoft), \"nc\" (norm-conserving), \"paw\"\n",
+ "FUNCTIONAL = \"pbe\" # for gga: \"pbe\", \"pbesol\"; for lda: \"pz\"\n",
+ "\n",
+ "# Relax the structure before phonons. Phonons require a force-minimized geometry —\n",
+ "# an unrelaxed structure produces imaginary (negative) modes. Recommended for any\n",
+ "# material not already at its equilibrium geometry (e.g. Graphene / 2D).\n",
+ "ADD_RELAXATION = False\n",
+ "\n",
+ "# Electronic k-grids; if None, the workflow default is used\n",
+ "SCF_KGRID = None # e.g. [8, 8, 8] (3D) or [12, 12, 1] (2D)\n",
+ "RELAXATION_KGRID = None # e.g. [8, 8, 8] (used only when ADD_RELAXATION)\n",
+ "\n",
+ "# Phonon q-grid for the DFPT run (ph.x); if None, the workflow default is used\n",
+ "PHONON_QGRID = None # e.g. [4, 4, 4] (3D) or [6, 6, 1] (2D)\n",
+ "\n",
+ "# Phonon DOS interpolation grid (matdyn.x); if None, the workflow default is used\n",
+ "DOS_QGRID = None # e.g. [12, 12, 12]\n",
+ "\n",
+ "# Phonon dispersion path (matdyn.x); if None, the workflow default is used\n",
+ "QPATH = None # e.g. [{\"point\": \"G\", \"steps\": 20}, {\"point\": \"M\", \"steps\": 20},\n",
+ " # {\"point\": \"K\", \"steps\": 20}, {\"point\": \"G\", \"steps\": 20}]\n",
+ "\n",
+ "# Energy cutoffs (raise for harder cases — e.g. 60 / 480 for Graphene)\n",
+ "ECUTWFC = 40\n",
+ "ECUTRHO = 200"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7",
+ "metadata": {},
+ "source": [
+ "## 2. Authenticate and initialize API client\n",
+ "### 2.1. Authenticate"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.notebooks_utils.auth import authenticate\n",
+ "\n",
+ "await authenticate()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9",
+ "metadata": {},
+ "source": [
+ "### 2.2. Initialize API client"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "10",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.api_client import APIClient\n",
+ "\n",
+ "client = APIClient.authenticate()\n",
+ "client"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "11",
+ "metadata": {},
+ "source": [
+ "### 2.3. Select account"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "12",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "client.list_accounts()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "13",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "selected_account = client.my_account\n",
+ "\n",
+ "if ORGANIZATION_NAME:\n",
+ " selected_account = client.get_account(name=ORGANIZATION_NAME)\n",
+ "\n",
+ "ACCOUNT_ID = selected_account.id\n",
+ "print(f\"✅ Selected account ID: {ACCOUNT_ID}, name: {selected_account.name}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "14",
+ "metadata": {},
+ "source": [
+ "### 2.4. Select project"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "15",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "projects = client.projects.list({\"isDefault\": True, \"owner._id\": ACCOUNT_ID})\n",
+ "project_id = projects[0][\"_id\"]\n",
+ "print(f\"✅ Using project: {projects[0]['name']} ({project_id})\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "16",
+ "metadata": {},
+ "source": [
+ "## 3. Create material\n",
+ "### 3.1. Load material from local file (or Standata)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.made.material import Material\n",
+ "from mat3ra.standata.materials import Materials\n",
+ "from mat3ra.notebooks_utils.ipython.entity.material.visualize import visualize_materials as visualize\n",
+ "from mat3ra.notebooks_utils.material import load_material_from_folder\n",
+ "\n",
+ "material = load_material_from_folder(FOLDER, MATERIAL_NAME) or Material.create(\n",
+ " Materials.get_by_name_first_match(MATERIAL_NAME))\n",
+ "\n",
+ "visualize(material)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "18",
+ "metadata": {},
+ "source": [
+ "### 3.2. Save material to the platform"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "19",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.notebooks_utils.core.entity.material.api import get_or_create_material\n",
+ "\n",
+ "material.basis.set_labels_from_list([])\n",
+ "saved_material_response = get_or_create_material(client, material, ACCOUNT_ID)\n",
+ "saved_material = Material.create(saved_material_response)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "20",
+ "metadata": {},
+ "source": [
+ "## 4. Configure workflow\n",
+ "### 4.1. Select application"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "21",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.standata.applications import ApplicationStandata\n",
+ "from mat3ra.ade.application import Application\n",
+ "\n",
+ "app_config = ApplicationStandata.get_by_name_first_match(APPLICATION_NAME)\n",
+ "app = Application(**app_config)\n",
+ "print(f\"Using application: {app.name}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "22",
+ "metadata": {},
+ "source": [
+ "### 4.2. Load workflow from Standata and preview it"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "23",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.standata.workflows import WorkflowStandata\n",
+ "from mat3ra.wode.workflows import Workflow\n",
+ "from mat3ra.notebooks_utils.ipython.entity.workflow.visualize import visualize_workflow\n",
+ "\n",
+ "workflow_config = WorkflowStandata.filter_by_application(app.name).get_by_name_first_match(WORKFLOW_SEARCH_TERM)\n",
+ "workflow = Workflow.create(workflow_config)\n",
+ "workflow.name = MY_WORKFLOW_NAME\n",
+ "\n",
+ "visualize_workflow(workflow)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "24",
+ "metadata": {},
+ "source": [
+ "### 4.3. Add relaxation (optional)\n",
+ "Prepend a relaxation subworkflow so the phonons are computed on a force-minimized structure."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "25",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "if ADD_RELAXATION:\n",
+ " workflow.add_relaxation()\n",
+ " visualize_workflow(workflow)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "26",
+ "metadata": {},
+ "source": [
+ "### 4.4. Set model and its parameters (physics)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.standata.model_tree import ModelTreeStandata\n",
+ "from mat3ra.mode import ModelFactory\n",
+ "\n",
+ "model_config = ModelTreeStandata.get_model_by_parameters(\n",
+ " type=\"dft\", subtype=MODEL_SUBTYPE, functional=FUNCTIONAL\n",
+ ")\n",
+ "model_config[\"method\"] = {\"type\": \"pseudopotential\", \"subtype\": PSEUDOPOTENTIAL_TYPE}\n",
+ "model = ModelFactory.create(model_config)\n",
+ "\n",
+ "for subworkflow in workflow.subworkflows:\n",
+ " subworkflow.model = model\n",
+ "\n",
+ "visualize_workflow(workflow)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "28",
+ "metadata": {},
+ "source": [
+ "### 4.5. Modify method (computational parameters)\n",
+ "Optional overrides — each applies only if its parameter is set above. Electronic k-grid + cutoffs on `pw.x`; phonon q-grid on `ph.x`; DOS interpolation grid and dispersion path on `matdyn.x`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "29",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.wode.context.providers import (\n",
+ " PlanewaveCutoffsContextProvider, PointsGridDataProvider, PointsPathDataProvider,\n",
+ ")\n",
+ "\n",
+ "# The phonon subworkflow is index 0, or 1 when a relaxation subworkflow is prepended.\n",
+ "phonon_subworkflow = workflow.subworkflows[1 if ADD_RELAXATION else 0]\n",
+ "\n",
+ "\n",
+ "def set_grid(subworkflow, unit_name, dimensions, name=None):\n",
+ " unit = subworkflow.get_unit_by_name(name=unit_name)\n",
+ " if unit:\n",
+ " unit.add_context(PointsGridDataProvider(dimensions=dimensions, isEdited=True, **({\"name\": name} if name else {})).get_context_item_data())\n",
+ " subworkflow.set_unit(unit)\n",
+ "\n",
+ "\n",
+ "def set_path(subworkflow, unit_name, path, name):\n",
+ " unit = subworkflow.get_unit_by_name(name=unit_name)\n",
+ " if unit:\n",
+ " unit.add_context(PointsPathDataProvider(path=path, isEdited=True, name=name).get_context_item_data())\n",
+ " subworkflow.set_unit(unit)\n",
+ "\n",
+ "\n",
+ "# Relaxation electronic k-grid\n",
+ "if RELAXATION_KGRID is not None and ADD_RELAXATION:\n",
+ " unit = workflow.subworkflows[0].get_unit_by_name(name_regex=\"relax\")\n",
+ " if unit:\n",
+ " unit.add_context(PointsGridDataProvider(dimensions=RELAXATION_KGRID, isEdited=True).get_context_item_data())\n",
+ " workflow.subworkflows[0].set_unit(unit)\n",
+ "\n",
+ "# SCF electronic k-grid (pw.x)\n",
+ "if SCF_KGRID is not None:\n",
+ " set_grid(phonon_subworkflow, \"pw_scf\", SCF_KGRID)\n",
+ "\n",
+ "# Phonon q-grid for DFPT (ph.x)\n",
+ "if PHONON_QGRID is not None:\n",
+ " set_grid(phonon_subworkflow, \"ph_grid\", PHONON_QGRID, name=\"qgrid\")\n",
+ "\n",
+ "# Phonon DOS interpolation grid (matdyn.x)\n",
+ "if DOS_QGRID is not None:\n",
+ " set_grid(phonon_subworkflow, \"matdyn_grid\", DOS_QGRID, name=\"igrid\")\n",
+ "\n",
+ "# Phonon dispersion path (matdyn.x)\n",
+ "if QPATH is not None:\n",
+ " set_path(phonon_subworkflow, \"matdyn_path\", QPATH, name=\"ipath\")\n",
+ "\n",
+ "# Energy cutoffs on every pw.x unit\n",
+ "if ECUTWFC is not None:\n",
+ " cutoffs_context = PlanewaveCutoffsContextProvider(\n",
+ " wavefunction=ECUTWFC, density=ECUTRHO, isEdited=True\n",
+ " ).get_context_item_data()\n",
+ " for unit_name in [\"pw_relax\", \"pw_vc-relax\", \"pw_scf\"]:\n",
+ " for swf in workflow.subworkflows:\n",
+ " unit = swf.get_unit_by_name(name=unit_name)\n",
+ " if unit:\n",
+ " unit.add_context(cutoffs_context)\n",
+ " swf.set_unit(unit)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30",
+ "metadata": {},
+ "source": [
+ "### 4.6. Preview final workflow"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "31",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "visualize_workflow(workflow)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "32",
+ "metadata": {},
+ "source": [
+ "### 4.7. Save workflow to collection"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "33",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.notebooks_utils.core.entity.workflow.api import get_or_create_workflow\n",
+ "\n",
+ "saved_workflow_response = get_or_create_workflow(client, workflow, ACCOUNT_ID)\n",
+ "saved_workflow = Workflow.create(saved_workflow_response)\n",
+ "print(f\"Workflow ID: {saved_workflow.id}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "34",
+ "metadata": {},
+ "source": [
+ "## 5. Create the compute configuration\n",
+ "### 5.1. Get list of clusters"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "35",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "clusters = client.clusters.list()\n",
+ "print(f\"Available clusters: {[c['hostname'] for c in clusters]}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "36",
+ "metadata": {},
+ "source": [
+ "### 5.2. Create compute configuration"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "37",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.ide.compute import Compute\n",
+ "\n",
+ "if CLUSTER_NAME:\n",
+ " cluster = next((c for c in clusters if CLUSTER_NAME in c[\"hostname\"]), None)\n",
+ "else:\n",
+ " cluster = clusters[0]\n",
+ "\n",
+ "compute = Compute(cluster=cluster, queue=QUEUE_NAME, ppn=PPN)\n",
+ "print(f\"Using cluster: {compute.cluster.hostname}, queue: {QUEUE_NAME}, ppn: {PPN}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "38",
+ "metadata": {},
+ "source": [
+ "## 6. Create the job\n",
+ "### 6.1. Create job"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "39",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.notebooks_utils.job import create_job\n",
+ "from mat3ra.utils.namespace import dict_to_namespace_recursive\n",
+ "from mat3ra.notebooks_utils.ui import display_JSON\n",
+ "\n",
+ "job_name = f\"{MY_WORKFLOW_NAME} {saved_material.formula} {timestamp}\"\n",
+ "job_response = create_job(\n",
+ " api_client=client,\n",
+ " materials=[saved_material],\n",
+ " workflow=workflow,\n",
+ " project_id=project_id,\n",
+ " owner_id=ACCOUNT_ID,\n",
+ " prefix=job_name,\n",
+ " compute=compute.to_dict(),\n",
+ ")\n",
+ "\n",
+ "job = dict_to_namespace_recursive(job_response)\n",
+ "job_id = job._id\n",
+ "print(f\"✅ Job created: {job_id}\")\n",
+ "display_JSON(job_response)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "40",
+ "metadata": {},
+ "source": [
+ "## 7. Submit the job and monitor the status"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "41",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "client.jobs.submit(job_id)\n",
+ "print(f\"✅ Job {job_id} submitted successfully!\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "42",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.notebooks_utils.api.job import wait_for_jobs_to_finish_async\n",
+ "\n",
+ "await wait_for_jobs_to_finish_async(client.jobs, [job_id], poll_interval=POLL_INTERVAL)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "43",
+ "metadata": {},
+ "source": [
+ "## 8. Retrieve and visualize results\n",
+ "### 8.1. Phonon dispersion"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "44",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from mat3ra.prode import PropertyName\n",
+ "from mat3ra.notebooks_utils.core.entity.property.api import get_properties_for_job\n",
+ "from mat3ra.notebooks_utils.ipython.entity.property.visualize import visualize_properties\n",
+ "\n",
+ "phonon_dispersions_data = get_properties_for_job(\n",
+ " client, job_id, property_name=PropertyName.non_scalar.phonon_dispersions.value\n",
+ ")\n",
+ "visualize_properties(phonon_dispersions_data, title=\"Phonon Dispersion\", extra_config={\"material\": material.to_dict()})\n",
+ "\n",
+ "# Sanity check: confirm real, non-trivial values were computed (not an empty/failed result)\n",
+ "_freqs = [f for band in phonon_dispersions_data[0][\"yDataSeries\"] for f in band]\n",
+ "print(f\"Phonon dispersion: {len(phonon_dispersions_data[0]['yDataSeries'])} bands, frequency range {min(_freqs):.1f} to {max(_freqs):.1f} cm^-1\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "45",
+ "metadata": {},
+ "source": [
+ "### 8.2. Phonon density of states"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "46",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "phonon_dos_data = get_properties_for_job(\n",
+ " client, job_id, property_name=PropertyName.non_scalar.phonon_dos.value\n",
+ ")\n",
+ "visualize_properties(phonon_dos_data, title=\"Phonon DOS\", extra_config={\"material\": material.to_dict()})\n",
+ "\n",
+ "# Sanity check: confirm real, non-trivial values were computed (not an empty/failed result)\n",
+ "_dos_freqs = phonon_dos_data[0][\"xDataArray\"][0]\n",
+ "_dos_vals = phonon_dos_data[0][\"yDataSeries\"][0]\n",
+ "print(f\"Phonon DOS: frequency range {min(_dos_freqs):.1f} to {max(_dos_freqs):.1f} cm^-1, peak DOS {max(_dos_vals):.4f} states/cm^-1\")"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "pygments_lexer": "ipython3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}