Skip to content

feature/SOF-7917 Feat: Defect formation energy - #346

Merged
VsevolodX merged 14 commits into
mainfrom
feature/SOF-7917
Jul 23, 2026
Merged

feature/SOF-7917 Feat: Defect formation energy#346
VsevolodX merged 14 commits into
mainfrom
feature/SOF-7917

Conversation

@VsevolodX

@VsevolodX VsevolodX commented Jul 16, 2026

Copy link
Copy Markdown
Member
  • update: defect energy NB

Summary by CodeRabbit

  • New Features
    • Added a workflow notebook for calculating neutral defect formation energies.
    • Added configurable bulk-energy reference sources to surface and interfacial energy workflows.
    • Improved account-aware selection when loading existing materials and reference energies.
    • Linked the defect formation energy workflow from the introduction notebook.
  • Documentation
    • Updated Materials Project API setup guidance and “next-gen” API links (including example assets).
  • Improvements
    • Cleaned up dielectric-tensor and phonon workflow result output by removing redundant diagnostics.
  • Tests
    • Added unit coverage for bulk total-energy source scoping behavior.
  • Chores
    • Updated link-checking to avoid blocked Materials Project URL checks.

@review-notebook-app

Copy link
Copy Markdown

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2dd412d1-9a05-4b97-a11f-08be40663e89

📥 Commits

Reviewing files that changed from the base of the PR and between ae4b038 and d2abf9f.

📒 Files selected for processing (1)
  • pyproject.toml

📝 Walkthrough

Walkthrough

Adds a defect formation energy notebook, introduces source-scoped total-energy lookup, updates surface and interfacial workflows, removes notebook sanity-check output, links the new workflow, and refreshes Materials Project documentation and link-checking configuration.

Changes

Materials workflow updates

Layer / File(s) Summary
Scoped total-energy lookup API
src/py/mat3ra/notebooks_utils/core/entity/property/api.py, tests/py/unit/core/entity/test_property_api_find_total_energy_for_material.py
find_total_energy_for_material now supports public, curator, and current-account property scopes with validation and coverage for query and empty-result behavior.
Defect workflow inputs and references
other/materials_designer/workflows/defect_formation_energy.ipynb
Adds authentication, material loading, elemental reference resolution, pristine-energy lookup, and Quantum ESPRESSO input preparation.
Defect job execution and results
other/materials_designer/workflows/defect_formation_energy.ipynb
Configures and submits the ordered defective/pristine workflow, waits for completion, and visualizes formation-energy results.
Surface and interfacial energy references
other/materials_designer/workflows/interfacial_energy.ipynb, other/materials_designer/workflows/surface_energy.ipynb
Adds configurable bulk energy sources, account-scoped material searches, and updated interface visualization settings.
Workflow visualization output
other/materials_designer/workflows/dielectric_tensor.ipynb, other/materials_designer/workflows/phonon_dos_dispersion.ipynb
Removes post-visualization sanity-check calculations and printed diagnostic output.
Defect workflow index entry
other/materials_designer/workflows/Introduction.ipynb
Links the defect formation energy notebook from the Thermodynamics index.

Repository link maintenance

Layer / File(s) Summary
Materials Project documentation links
README.md, examples/assets/README.md
Replaces legacy Materials Project URLs with next-generation URLs.
Materials Project link-checker exclusion
.github/workflows/check_links.yml
Documents the blocked domain and excludes matching Materials Project URLs from automated checks.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant DefectFormationEnergyNotebook
  participant Mat3raAPI
  participant ComputeCluster
  User->>DefectFormationEnergyNotebook: configure defect and pristine inputs
  DefectFormationEnergyNotebook->>Mat3raAPI: authenticate and resolve materials and references
  DefectFormationEnergyNotebook->>Mat3raAPI: create and submit multi-material job
  Mat3raAPI->>ComputeCluster: execute patched DFT workflow
  ComputeCluster-->>Mat3raAPI: return completed job
  DefectFormationEnergyNotebook->>Mat3raAPI: retrieve and visualize formation energy
Loading

Possibly related PRs

Suggested reviewers: timurbazhirov

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding defect formation energy workflow support.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/SOF-7917

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
other/materials_designer/workflows/defect_formation_energy.ipynb (1)

376-389: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider using a shared helper for material resolution.

If the newly added analysis.py utilities (mentioned in the PR stack) include a generic helper for resolving materials with a specific property by hash and name, consider using it here to replace resolve_pristine_with_total_energy and reduce code duplication.

🤖 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 376 - 389, Replace the local resolve_pristine_with_total_energy
implementation with the shared analysis.py helper that resolves materials by
hash and name while requiring a specific property. Pass the existing material,
name, and Total Energy lookup requirements through that helper, preserving
hash-first resolution, name fallback, duplicate avoidance, and the existing
(Material, property) return contract.
🤖 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/interfacial_energy.ipynb`:
- Around line 120-123: Validate N_INTERFACES before applying the workflow,
ensuring it is explicitly provided and limited to the supported interface counts
for the structure. Update the apply_workflow_parameters path or its caller so
invalid or missing set-n-interfaces values fail clearly instead of leaving γ
normalization unset.
- Around line 245-254: Update the interface lookup in the `interface is None`
branch and the bulk hash resolver to include an `ACCOUNT_ID` filter in their
platform material queries. Preserve the existing name-regex and hash-matching
behavior while ensuring both lookups only return materials belonging to the
current account.

In `@other/materials_designer/workflows/surface_energy.ipynb`:
- Around line 292-297: Add the missing find_total_energy_for_material function
to mat3ra.notebooks_utils.core.entity.property.api, ensuring it is exported and
supports the call with client and bulk_material.id used by surface_energy.ipynb.
Reuse the existing total-energy property lookup behavior and return the expected
tuple so the bulk-energy lookup proceeds without ImportError.

In `@src/py/mat3ra/notebooks_utils/core/entity/material/analysis.py`:
- Around line 162-165: Update find_owned_material to include owner._id
constrained to owner_id in the bulk_query passed to api_client.materials.list,
then return only the matching owned material. Remove the fallback to matches[0]
so the function returns None when no material belongs to owner_id.

---

Nitpick comments:
In `@other/materials_designer/workflows/defect_formation_energy.ipynb`:
- Around line 376-389: Replace the local resolve_pristine_with_total_energy
implementation with the shared analysis.py helper that resolves materials by
hash and name while requiring a specific property. Pass the existing material,
name, and Total Energy lookup requirements through that helper, preserving
hash-first resolution, name fallback, duplicate avoidance, and the existing
(Material, property) return contract.
🪄 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

Run ID: a6512c90-5ff5-4af4-b6f9-58dda3d52e8c

📥 Commits

Reviewing files that changed from the base of the PR and between 6a6518d and 3dd4662.

📒 Files selected for processing (6)
  • README.md
  • other/materials_designer/workflows/Introduction.ipynb
  • other/materials_designer/workflows/defect_formation_energy.ipynb
  • other/materials_designer/workflows/interfacial_energy.ipynb
  • other/materials_designer/workflows/surface_energy.ipynb
  • src/py/mat3ra/notebooks_utils/core/entity/material/analysis.py

Comment thread other/materials_designer/workflows/interfacial_energy.ipynb Outdated
Comment thread other/materials_designer/workflows/interfacial_energy.ipynb
Comment thread other/materials_designer/workflows/surface_energy.ipynb Outdated
Comment on lines +162 to +165
def find_owned_material(api_client: Any, bulk_query: dict, owner_id: str) -> Optional[Any]:
matches = api_client.materials.list(bulk_query)
owned = next((item for item in matches if item.get("owner", {}).get("_id") == owner_id), None)
return owned or (matches[0] if matches else None)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not fall back to another account’s material.

When no match belongs to owner_id, Line 165 returns the first global match. The notebook can consequently validate another account’s Total Energy while submitting under the selected account. Include owner._id in the API query and return None when no owned match exists.

Proposed fix
 def find_owned_material(api_client: Any, bulk_query: dict, owner_id: str) -> Optional[Any]:
-    matches = api_client.materials.list(bulk_query)
-    owned = next((item for item in matches if item.get("owner", {}).get("_id") == owner_id), None)
-    return owned or (matches[0] if matches else None)
+    matches = api_client.materials.list({**bulk_query, "owner._id": owner_id})
+    return matches[0] if matches else None
📝 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.

Suggested change
def find_owned_material(api_client: Any, bulk_query: dict, owner_id: str) -> Optional[Any]:
matches = api_client.materials.list(bulk_query)
owned = next((item for item in matches if item.get("owner", {}).get("_id") == owner_id), None)
return owned or (matches[0] if matches else None)
def find_owned_material(api_client: Any, bulk_query: dict, owner_id: str) -> Optional[Any]:
matches = api_client.materials.list({**bulk_query, "owner._id": owner_id})
return matches[0] if matches else None
🤖 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/material/analysis.py` around lines
162 - 165, Update find_owned_material to include owner._id constrained to
owner_id in the bulk_query passed to api_client.materials.list, then return only
the matching owned material. Remove the fallback to matches[0] so the function
returns None when no material belongs to owner_id.

@VsevolodX VsevolodX changed the title feature/SOF 7917 feature/SOF-7917 Feat: Defect formation energy Jul 16, 2026
@VsevolodX
VsevolodX changed the base branch from main to feature/SOF-7954 July 16, 2026 01:33
Base automatically changed from feature/SOF-7954 to main July 23, 2026 03:33
@coderabbitai coderabbitai Bot mentioned this pull request Jul 23, 2026
Matches formation_energy.ipynb's own ELEMENTAL_TE_SOURCE default -- most
callers want the best-precision total_energy regardless of owner, not
scoped to the current account.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
other/materials_designer/workflows/defect_formation_energy.ipynb (1)

356-369: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Restrict elemental references to Standata.

This query accepts any accessible material tagged elemental, despite the notebook promising Standata references. A user-owned or third-party match can therefore alter the chemical potentials and formation energy. Filter by the Standata/curator owner identity before grouping results.

🤖 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 356 - 369, Update the elemental_materials_data query to restrict results
to the established Standata/curator owner identity before
element_materials_by_symbol groups them, while preserving the existing elemental
tag and metadata.element filters and missing-element validation.
🤖 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 137-140: Update the documented source options in
other/materials_designer/workflows/defect_formation_energy.ipynb lines 137-140,
other/materials_designer/workflows/interfacial_energy.ipynb lines 125-128, and
other/materials_designer/workflows/surface_energy.ipynb lines 114-117 so
“my_account” is described as the current account only; leave the other source
descriptions unchanged.

In `@src/py/mat3ra/notebooks_utils/core/entity/property/api.py`:
- Around line 96-102: Move the source validation in the property lookup flow
before the material’s exabyteId check or any fetch/inspection, so invalid values
such as "everyone" always raise ValueError even when exabyteId is missing.
Preserve the existing query construction for public, curators, and my_account,
and add a regression test covering an invalid source with a material lacking
exabyteId.

---

Outside diff comments:
In `@other/materials_designer/workflows/defect_formation_energy.ipynb`:
- Around line 356-369: Update the elemental_materials_data query to restrict
results to the established Standata/curator owner identity before
element_materials_by_symbol groups them, while preserving the existing elemental
tag and metadata.element filters and missing-element validation.
🪄 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: 460df256-ba76-4bbb-bdf8-bd0dfe325813

📥 Commits

Reviewing files that changed from the base of the PR and between 3dd4662 and ae4b038.

📒 Files selected for processing (11)
  • .github/workflows/check_links.yml
  • README.md
  • examples/assets/README.md
  • other/materials_designer/workflows/Introduction.ipynb
  • other/materials_designer/workflows/defect_formation_energy.ipynb
  • other/materials_designer/workflows/dielectric_tensor.ipynb
  • other/materials_designer/workflows/interfacial_energy.ipynb
  • other/materials_designer/workflows/phonon_dos_dispersion.ipynb
  • other/materials_designer/workflows/surface_energy.ipynb
  • src/py/mat3ra/notebooks_utils/core/entity/property/api.py
  • tests/py/unit/core/entity/test_property_api_find_total_energy_for_material.py

Comment on lines +137 to +140
"# Whose total_energy properties to consider for the pristine reference:\n",
"# \"public\" (any owner, highest precision wins), \"curators\" (only curators'),\n",
"# or \"my_account\" (curators' or your own).\n",
"PRISTINE_TOTAL_ENERGY_SOURCE = \"my_account\"\n"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the documented my_account scope.

find_total_energy_for_material(..., source="my_account") filters only by owner._id; it does not include curator properties. The current guidance can make users expect a curator fallback that will not occur.

  • other/materials_designer/workflows/defect_formation_energy.ipynb#L137-L140: describe my_account as the current account only.
  • other/materials_designer/workflows/interfacial_energy.ipynb#L125-L128: describe my_account as the current account only.
  • other/materials_designer/workflows/surface_energy.ipynb#L114-L117: describe my_account as the current account only.
📍 Affects 3 files
  • other/materials_designer/workflows/defect_formation_energy.ipynb#L137-L140 (this comment)
  • other/materials_designer/workflows/interfacial_energy.ipynb#L125-L128
  • other/materials_designer/workflows/surface_energy.ipynb#L114-L117
🤖 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 137 - 140, Update the documented source options in
other/materials_designer/workflows/defect_formation_energy.ipynb lines 137-140,
other/materials_designer/workflows/interfacial_energy.ipynb lines 125-128, and
other/materials_designer/workflows/surface_energy.ipynb lines 114-117 so
“my_account” is described as the current account only; leave the other source
descriptions unchanged.

Comment on lines +96 to +102
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'.")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate source before fetching or inspecting the material.

With a material lacking exabyteId, execution returns None at Line 95 before reaching this validation, so source="everyone" is silently accepted. Validate first and add a regression test for invalid source plus missing exabyteId.

Proposed fix
+    if source not in ("public", "curators", "my_account"):
+        raise ValueError(
+            f"Invalid source: {source!r}. Expected 'public', 'curators', or 'my_account'."
+        )
+
     material = client.materials.get(material_id)
     exabyte_id = material.get("exabyteId")
     if not exabyte_id:
         return None
@@
-    elif source != "public":
-        raise ValueError(f"Invalid source: {source!r}. Expected 'public', 'curators', or 'my_account'.")
🤖 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, Move the source validation in the property lookup flow before the
material’s exabyteId check or any fetch/inspection, so invalid values such as
"everyone" always raise ValueError even when exabyteId is missing. Preserve the
existing query construction for public, curators, and my_account, and add a
regression test covering an invalid source with a material lacking exabyteId.

property/api.py imports mat3ra.api_client and mat3ra.prode at module level,
but the tests extras group only pulled in [materials] + mat3ra-wode --
never [api], and mat3ra-prode isn't in [materials] either. No prior test
imported this module, so a clean install (CI) never surfaced the gap; a
locally pre-populated venv masked it. Use [workflows] instead, which
already bundles materials + api + prode + wode + mode + ade + ide together.
@VsevolodX
VsevolodX merged commit b6d020f into main Jul 23, 2026
8 checks passed
@VsevolodX
VsevolodX deleted the feature/SOF-7917 branch July 23, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants