feat: HOMO/LUMO NB - #351
Conversation
|
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
|
Warning Review limit reached
Next review available in: 50 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds defect formation energy, interfacial energy, and HOMO–LUMO/frequency notebooks; introduces shared bulk-material, total-energy, and SCF k-grid utilities; updates surface-energy integration, notebook outputs, documentation links, and link checking. ChangesMaterials Designer workflow expansion
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Notebook
participant MaterialsAPI
participant WorkflowAPI
participant JobAPI
participant PropertiesAPI
Notebook->>MaterialsAPI: prepare materials and references
Notebook->>WorkflowAPI: configure workflow
Notebook->>JobAPI: create and submit calculation
JobAPI-->>Notebook: completed job
Notebook->>PropertiesAPI: retrieve calculated properties
PropertiesAPI-->>Notebook: visualization data
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (1)
other/materials_designer/workflows/defect_formation_energy.ipynb (1)
458-465: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReuse
apply_scf_kgridinstead of reimplementing the k-grid patch.This block duplicates the shared
apply_scf_kgridhelper that the surface and interfacial notebooks already call. Reusing it keeps behavior consistent (e.g., thefirst_onlyoption and unit-name handling) and avoids drift.♻️ Suggested change
-# K-grid for the defective-cell SCF. -if SCF_KGRID is not None: - new_context = PointsGridDataProvider(dimensions=SCF_KGRID, isEdited=True).get_context_item_data() - for subworkflow in defect_workflow.subworkflows: - unit = subworkflow.get_unit_by_name(name="pw_scf") - if unit: - unit.add_context(new_context) - subworkflow.set_unit(unit) +# K-grid for the defective-cell SCF. +defect_workflow = apply_scf_kgrid(defect_workflow, scf_kgrid=SCF_KGRID)This also lets you drop the
PointsGridDataProviderimport and addapply_scf_kgridto the imports in this cell.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@other/materials_designer/workflows/defect_formation_energy.ipynb` around lines 458 - 465, Replace the inline SCF k-grid patching block with the shared apply_scf_kgrid helper, preserving the defective workflow and SCF_KGRID inputs. Update the cell imports to add apply_scf_kgrid and remove the now-unused PointsGridDataProvider import.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@other/materials_designer/workflows/defect_formation_energy.ipynb`:
- Around line 366-369: Update the RuntimeError message in the defect formation
energy workflow to remove the non-interpolated `{element}` placeholder and
reword the guidance generically for the missing elemental materials, while
preserving the existing missing-material details.
In `@other/materials_designer/workflows/homo_lumo_frequency.ipynb`:
- Around line 514-530: Guard the HOMO/LUMO gap calculation in the
CALCULATE_HOMO_LUMO block after fetching homo_data and lumo_data, checking that
both results are non-empty before indexing their first values. When either
result is empty, emit a clear message and skip the subtraction and formatted gap
output; preserve visualization for any returned data.
- Around line 296-312: Validate the standata lookups and required structure
before composing the workflow in the notebook: ensure the selected base entry
exists and contains the expected HOMO/LUMO configuration, and when both
CALCULATE_HOMO_LUMO and CALCULATE_FREQUENCY are enabled, ensure frequency.json
exists with a valid subworkflows[0] entry. Use specific lookup behavior and
raise clear, actionable errors for missing or malformed entries instead of
allowing KeyError/IndexError or silently omitting frequency calculations;
preserve the existing workflow composition for valid data.
In `@README.md`:
- Line 163: Synchronize the Materials Project API-key guidance by updating the
legacy URL references in README.ipynb and the settings configuration near the
API-key definition to the next-gen Materials Project URL used in README.md. Keep
the guidance consistent across all three locations unless a documented
compatibility reason requires retaining the legacy URL.
In `@src/py/mat3ra/notebooks_utils/core/entity/property/api.py`:
- Around line 96-102: Update find_total_energy_for_material so
source="my_account" filters by the resolved owner account used to create or
resolve the material, rather than always using client.my_account.id. Thread that
account through its callers, including organization accounts selected via
ACCOUNT_ID, while preserving curator ownership handling when the documented
my_account source includes curators.
---
Nitpick comments:
In `@other/materials_designer/workflows/defect_formation_energy.ipynb`:
- Around line 458-465: Replace the inline SCF k-grid patching block with the
shared apply_scf_kgrid helper, preserving the defective workflow and SCF_KGRID
inputs. Update the cell imports to add apply_scf_kgrid and remove the now-unused
PointsGridDataProvider import.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 5626a0b9-5a13-49d9-903f-cfdec2fad19d
📒 Files selected for processing (16)
.github/workflows/check_links.ymlREADME.mdexamples/assets/README.mdother/materials_designer/workflows/Introduction.ipynbother/materials_designer/workflows/defect_formation_energy.ipynbother/materials_designer/workflows/dielectric_tensor.ipynbother/materials_designer/workflows/homo_lumo_frequency.ipynbother/materials_designer/workflows/interfacial_energy.ipynbother/materials_designer/workflows/phonon_dos_dispersion.ipynbother/materials_designer/workflows/surface_energy.ipynbsrc/py/mat3ra/notebooks_utils/core/entity/material/analysis.pysrc/py/mat3ra/notebooks_utils/core/entity/material/api.pysrc/py/mat3ra/notebooks_utils/core/entity/property/api.pysrc/py/mat3ra/notebooks_utils/workflow.pytests/py/unit/core/entity/test_material_analysis.pytests/py/unit/test_workflow_utils.py
| " raise RuntimeError(\n", | ||
| " f\"Missing elemental reference material(s) for {missing}. \"\n", | ||
| " \"Add elemental material(s) from Standata, or add tag 'elemental' with metadata.element = {element}\"\n", | ||
| " )\n", |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
{element} won't interpolate in this error message.
Only the first concatenated string is an f-string; the second is a plain literal, so {element} is printed verbatim (and element isn't in scope here anyway). Reword to avoid the misleading placeholder.
🐛 Suggested fix
raise RuntimeError(
f"Missing elemental reference material(s) for {missing}. "
- "Add elemental material(s) from Standata, or add tag 'elemental' with metadata.element = {element}"
+ "Add the elemental material(s) from Standata, or tag existing ones 'elemental' "
+ "with a matching metadata.element."
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| " raise RuntimeError(\n", | |
| " f\"Missing elemental reference material(s) for {missing}. \"\n", | |
| " \"Add elemental material(s) from Standata, or add tag 'elemental' with metadata.element = {element}\"\n", | |
| " )\n", | |
| " raise RuntimeError(\n", | |
| " f\"Missing elemental reference material(s) for {missing}. \"\n", | |
| " \"Add the elemental material(s) from Standata, or tag existing ones 'elemental' \"\n", | |
| " \"with a matching metadata.element.\"\n", | |
| " )\n", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@other/materials_designer/workflows/defect_formation_energy.ipynb` around
lines 366 - 369, Update the RuntimeError message in the defect formation energy
workflow to remove the non-interpolated `{element}` placeholder and reword the
guidance generically for the missing elemental materials, while preserving the
existing missing-material details.
| "from mat3ra.standata.workflows import WorkflowStandata\n", | ||
| "from mat3ra.wode import Workflow, Subworkflow\n", | ||
| "from mat3ra.notebooks_utils.ipython.entity.workflow.visualize import visualize_workflow\n", | ||
| "\n", | ||
| "nwchem_workflows = WorkflowStandata.filter_by_application(app.name)\n", | ||
| "\n", | ||
| "base_search_term = \"total_energy.json\" if CALCULATE_HOMO_LUMO else \"frequency.json\"\n", | ||
| "workflow = Workflow.create(nwchem_workflows.get_by_name_first_match(base_search_term))\n", | ||
| "\n", | ||
| "if CALCULATE_HOMO_LUMO and CALCULATE_FREQUENCY:\n", | ||
| " frequency_config = nwchem_workflows.get_by_name_first_match(\"frequency.json\")\n", | ||
| " workflow.add_subworkflow(Subworkflow(**frequency_config[\"subworkflows\"][0]))\n", | ||
| "\n", | ||
| "workflow.name = MY_WORKFLOW_NAME\n", | ||
| "\n", | ||
| "visualize_workflow(workflow)\n" | ||
| ] |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Locate the NWChem workflow standata to confirm structure/property outputs
fd -e json total_energy frequency -x cat -n {}Repository: mat3ra/api-examples
Length of output: 254
🏁 Script executed:
#!/bin/bash
set -u
echo "== files matching homo/freq/workflow names =="
git ls-files | rg -n 'homo_lumo|frequency|total_energy|standata|workflow' || true
echo
echo "== target cell context =="
sed -n '260,330p' other/materials_designer/workflows/homo_lumo_frequency.ipynb 2>/dev/null || true
echo
echo "== find JSON files with total_energy or frequency =="
git ls-files | rg -n '(^|/)(total_energy|frequency)\.json$|standata|workflows' || trueRepository: mat3ra/api-examples
Length of output: 6136
Guard the standata workflow composition assumptions.
WorkflowStandata JSON entries are external to this repo, so this notebook assumes total_energy.json has the HOMO/LUMO properties/values and frequency.json["subworkflows"][0] exists. Add fail-safes or explicit checks and use more specific lookup behavior, otherwise the workflow can fail with a confusing KeyError/IndexError or silently skip the requested frequencies.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@other/materials_designer/workflows/homo_lumo_frequency.ipynb` around lines
296 - 312, Validate the standata lookups and required structure before composing
the workflow in the notebook: ensure the selected base entry exists and contains
the expected HOMO/LUMO configuration, and when both CALCULATE_HOMO_LUMO and
CALCULATE_FREQUENCY are enabled, ensure frequency.json exists with a valid
subworkflows[0] entry. Use specific lookup behavior and raise clear, actionable
errors for missing or malformed entries instead of allowing KeyError/IndexError
or silently omitting frequency calculations; preserve the existing workflow
composition for valid data.
| { | ||
| "cell_type": "code", | ||
| "execution_count": null, | ||
| "id": "40", | ||
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "from mat3ra.notebooks_utils.ipython.entity.property.visualize import visualize_properties\n", | ||
| "\n", | ||
| "if CALCULATE_HOMO_LUMO:\n", | ||
| " homo_data = client.properties.get_for_job(job_id, property_name=\"homo_energy\")\n", | ||
| " lumo_data = client.properties.get_for_job(job_id, property_name=\"lumo_energy\")\n", | ||
| " visualize_properties(homo_data, title=\"HOMO Energy\")\n", | ||
| " visualize_properties(lumo_data, title=\"LUMO Energy\")\n", | ||
| " homo_lumo_gap = lumo_data[0][\"value\"] - homo_data[0][\"value\"]\n", | ||
| " print(f\"HOMO-LUMO gap: {homo_lumo_gap:.4f} eV\")\n" | ||
| ] |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Guard against empty HOMO/LUMO property results before indexing.
homo_data[0]["value"] / lumo_data[0]["value"] will raise an unguarded IndexError if get_for_job returns an empty list (e.g., the property wasn't produced for this job). Since this runs unconditionally right after fetching the data, a partial failure here crashes the notebook with a low-signal traceback instead of a clear message.
🛡️ Proposed fix
if CALCULATE_HOMO_LUMO:
homo_data = client.properties.get_for_job(job_id, property_name="homo_energy")
lumo_data = client.properties.get_for_job(job_id, property_name="lumo_energy")
visualize_properties(homo_data, title="HOMO Energy")
visualize_properties(lumo_data, title="LUMO Energy")
- homo_lumo_gap = lumo_data[0]["value"] - homo_data[0]["value"]
- print(f"HOMO-LUMO gap: {homo_lumo_gap:.4f} eV")
+ if homo_data and lumo_data:
+ homo_lumo_gap = lumo_data[0]["value"] - homo_data[0]["value"]
+ print(f"HOMO-LUMO gap: {homo_lumo_gap:.4f} eV")
+ else:
+ print("⚠️ HOMO/LUMO data not available for this job")📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "40", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "from mat3ra.notebooks_utils.ipython.entity.property.visualize import visualize_properties\n", | |
| "\n", | |
| "if CALCULATE_HOMO_LUMO:\n", | |
| " homo_data = client.properties.get_for_job(job_id, property_name=\"homo_energy\")\n", | |
| " lumo_data = client.properties.get_for_job(job_id, property_name=\"lumo_energy\")\n", | |
| " visualize_properties(homo_data, title=\"HOMO Energy\")\n", | |
| " visualize_properties(lumo_data, title=\"LUMO Energy\")\n", | |
| " homo_lumo_gap = lumo_data[0][\"value\"] - homo_data[0][\"value\"]\n", | |
| " print(f\"HOMO-LUMO gap: {homo_lumo_gap:.4f} eV\")\n" | |
| ] | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "40", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "from mat3ra.notebooks_utils.ipython.entity.property.visualize import visualize_properties\n", | |
| "\n", | |
| "if CALCULATE_HOMO_LUMO:\n", | |
| " homo_data = client.properties.get_for_job(job_id, property_name=\"homo_energy\")\n", | |
| " lumo_data = client.properties.get_for_job(job_id, property_name=\"lumo_energy\")\n", | |
| " visualize_properties(homo_data, title=\"HOMO Energy\")\n", | |
| " visualize_properties(lumo_data, title=\"LUMO Energy\")\n", | |
| " if homo_data and lumo_data:\n", | |
| " homo_lumo_gap = lumo_data[0][\"value\"] - homo_data[0][\"value\"]\n", | |
| " print(f\"HOMO-LUMO gap: {homo_lumo_gap:.4f} eV\")\n", | |
| " else:\n", | |
| " print(\"⚠️ HOMO/LUMO data not available for this job\")\n" | |
| ] |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@other/materials_designer/workflows/homo_lumo_frequency.ipynb` around lines
514 - 530, Guard the HOMO/LUMO gap calculation in the CALCULATE_HOMO_LUMO block
after fetching homo_data and lumo_data, checking that both results are non-empty
before indexing their first values. When either result is empty, emit a clear
message and skip the subtraction and formatted gap output; preserve
visualization for any returned data.
| 3. Optionally, for local Jupyter without OIDC, set legacy API token values in [settings.json](src/py/mat3ra/notebooks_utils/core/api/settings.json). See [Get Authentication Params](examples/system/get_authentication_params.ipynb) for details. API tokens can also be generated in [Account Preferences](https://docs.mat3ra.com/accounts/ui/preferences/api/) on the platform. | ||
|
|
||
| NOTE: The Materials Project API key should be set in `settings.json` and obtained from [https://legacy.materialsproject.org/open](https://legacy.materialsproject.org/open). | ||
| NOTE: The Materials Project API key should be set in `settings.json` and obtained from [https://next-gen.materialsproject.org/api](https://next-gen.materialsproject.org/api). |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Synchronize the remaining Materials Project API-key references.
README.ipynb (Lines 83-91) and src/py/mat3ra/notebooks_utils/core/api/settings.py (Lines 9-18) still point to the legacy URL, so repository guidance is now inconsistent. Update those references or explicitly document why they must remain legacy.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` at line 163, Synchronize the Materials Project API-key guidance by
updating the legacy URL references in README.ipynb and the settings
configuration near the API-key definition to the next-gen Materials Project URL
used in README.md. Keep the guidance consistent across all three locations
unless a documented compatibility reason requires retaining the legacy URL.
| query = {"exabyteId": exabyte_id, "slug": "total_energy"} | ||
| if source == "curators": | ||
| query["owner.slug"] = "curators" | ||
| elif source == "my_account": | ||
| query["owner._id"] = client.my_account.id | ||
| elif source != "public": | ||
| raise ValueError(f"Invalid source: {source!r}. Expected 'public', 'curators', or 'my_account'.") |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm callers pass ACCOUNT_ID (possibly org) while this fn uses my_account.id
rg -nP --type=py -C2 'find_total_energy_for_material\s*\('
rg -nP --glob '*.ipynb' -C2 'find_total_energy_for_material'
# Inspect the my_account attribute source
rg -nP --type=py -C3 'my_account' src/py/mat3ra/notebooks_utilsRepository: mat3ra/api-examples
Length of output: 157
🏁 Script executed:
#!/bin/bash
set -u
echo "Repo files matching api.py / notebooks_utils:"
git ls-files | grep -E '(^|/)api\.py$|notebooks_utils|\.ipynb$' | sed -n '1,200p'
echo
echo "Find target file:"
fd -ap 'api.py' . | sed -n '1,120p'
echo
echo "Search exact function name all files:"
rg -n -C3 'find_total_energy_for_material' . || true
echo
echo "Search total_energy related:"
rg -n -C2 'total_energy|TotalEnergy|Total Energy|TOTAL' . | sed -n '1,240p' || trueRepository: mat3ra/api-examples
Length of output: 38750
🏁 Script executed:
#!/bin/bash
set -u
echo "Target function:"
sed -n '60,130p' src/py/mat3ra/notebooks_utils/core/entity/property/api.py
echo
echo "Auth/client/account-related definitions and selected account setup:"
rg -n -C3 'selected_account|client =|APIClient|ACCOUNT_ID|ORGANIZATION_NAME|my_account|owner_id' src/py/mat3ra/notebooks_utils core src/py examples other -g '*.py' -g '*.ipynb' | sed -n '1,260p'
echo
echo "Bulk material functions:"
rg -n -C3 'def get_bulk_material|def get_bulk_material_by_crystal' src/py/mat3ra/notebooks_utils
sed -n '1,140p' src/py/mat3ra/notebooks_utils/core/entity/material/api.pyRepository: mat3ra/api-examples
Length of output: 28047
🏁 Script executed:
#!/bin/bash
set -u
python3 - <<'PY'
import json
from pathlib import Path
targets = [
"other/materials_designer/workflows/interfacial_energy.ipynb",
"other/materials_designer/workflows/surface_energy.ipynb",
"other/materials_designer/workflows/defect_formation_energy.ipynb",
"other/materials_designer/workflows/total_energy.ipynb",
]
for path in targets:
p = Path(path)
print(f"\n--- {path} ---")
data = json.loads(p.read_text())
cells = data.get("cells", [])
for i, cell in enumerate(cells):
source = "".join(cell.get("source", []))
if "ACCOUNT_ID" in source or "BULK_TOTAL_ENERGY_SOURCE" in source or "PRISTINE_TOTAL_ENERGY_SOURCE" in source:
print(f"[cell {i}]")
print(source)
PYRepository: mat3ra/api-examples
Length of output: 14219
Route source="my_account" through the resolved account selector.
The notebooks resolve and create materials under ACCOUNT_ID, which can be an organization account when ORGANIZATION_NAME is set, but find_total_energy_for_material(..., source="my_account") queries only client.my_account.id. This makes total-energy lookups fail even though the matching bulk/material was resolved under a different owner, breaking surface, interfacial, and defect formation energy notebooks. Thread the requested owner account into this lookup, including curators when the source documentation says my_account is “curators' or your own”.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/py/mat3ra/notebooks_utils/core/entity/property/api.py` around lines 96 -
102, Update find_total_energy_for_material so source="my_account" filters by the
resolved owner account used to create or resolve the material, rather than
always using client.my_account.id. Thread that account through its callers,
including organization accounts selected via ACCOUNT_ID, while preserving
curator ownership handling when the documented my_account source includes
curators.
Summary by CodeRabbit