Skip to content

Add element and site projected phonon DOS support#339

Merged
janosh merged 4 commits intomainfrom
phonon-dos-element-projection
Feb 16, 2026
Merged

Add element and site projected phonon DOS support#339
janosh merged 4 commits intomainfrom
phonon-dos-element-projection

Conversation

@janosh
Copy link
Owner

@janosh janosh commented Feb 16, 2026

Closes #222

Summary by CodeRabbit

  • New Features

    • Phonon DOS plotting: supports element/site projections, accepts richer DOS inputs, and can display total DOS alongside projections; figure display/layout standardized.
  • Bug Fixes

    • Improved runtime validation with explicit errors for missing DOS data and more robust normalization and edge-case handling.
  • Chores

    • Removed strict early dependency exit and made JSON reading explicit text mode for robustness.
  • Documentation

    • Updated phonons README anchors/links.
  • Tests

    • Expanded tests for projections, normalization, unit conversion, smearing, and error cases.

- extend phonon_dos() with CompletePhononDos projection modes and optional total overlays
- harden DOS normalization with explicit error handling for zero-density and invalid integral inputs
- expand phonon plotly coverage with projected DOS behavior and normalization edge-case tests
- update phonon fixtures, example scripts, and README links for the new projected DOS workflow
@janosh janosh added enhancement Improvement to existing features/functionality phonons Phonon bands and DOS plots plotly Concerning plotly-powered functions testing Test all the things examples New or improved usage examples labels Feb 16, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 16, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds element/site projection support to phonon DOS plotting via CompletePhononDos and a new project parameter; centralizes DOS preparation (conversion, smearing, normalization); standardizes JSON reads to text mode and removes atomate2 exit guards; introduces a Plotly show_figure helper and accompanying tests/fixture updates.

Changes

Cohort / File(s) Summary
Core plotting logic
pymatviz/phonons/figures.py
Accepts CompletePhononDos inputs; adds project: Literal["element","site"] and show_total params to phonon_dos; implements projection expansion, _prepare_dos (unit conversion, smearing, normalization), stacking/total-overlay logic, and validation/error paths.
Script updates & helpers
assets/scripts/phonons/phonon_dos.py, assets/scripts/phonons/phonon_bands.py, assets/scripts/phonons/phonon_bands_and_dos.py
Removed top-level atomate2 ImportError/SystemExit guards; open JSON files with zopen(..., mode="rt"); added show_figure helper and routed Plotly rendering through it in DOS script.
Tests & fixtures
tests/conftest.py, tests/phonons/test_phonon_plotly.py
Added complete_phonon_dos fixture; updated TYPE_CHECKING imports to include CompletePhononDos; changed zopen calls to text mode; extended tests to cover element/site projections, show_total behavior, normalization modes, smearing/unit conversion, and related error cases.
Docs / readme
readme.md
Adjusted internal anchor targets for phonon_bands_and_dos links (line reference changes), no behavior changes.

Sequence Diagram

sequenceDiagram
    participant User as User/Script
    participant Pho as phonon_dos()
    participant Val as Validator
    participant Proj as Projection Logic
    participant Prep as DOS Preparer
    participant Plot as Plotly Renderer

    User->>Pho: call phonon_dos(doses=CompletePhononDos, project="element")
    Pho->>Val: validate inputs & params
    Val-->>Pho: validation OK
    Pho->>Proj: decompose CompletePhononDos by element/site
    Proj->>Prep: for each partial DOS -> convert units, smear, normalize
    Prep-->>Proj: prepared freq & density arrays
    Proj->>Pho: assemble per-entity traces (+ optional total)
    Pho->>Plot: add traces and call show_figure()
    Plot->>User: render/display Plotly figure
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped through DOS and split each tune,

By element and site beneath the moon.
JSON read as text, no exits to fear,
Traces stack and totals now appear.
Hooray — the plots sing loud and clear!

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding support for element and site projected phonon DOS visualization.
Linked Issues check ✅ Passed The PR successfully implements both element and site projection support for phonon DOS as required by issue #222, with new parameters and comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly related to phonon DOS projection support. Secondary improvements like explicit text mode for JSON reading and atomate2 guard removal are minor enablers for the main objective.
Docstring Coverage ✅ Passed Docstring coverage is 84.21% which is sufficient. The required threshold is 80.00%.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch phonon-dos-element-projection

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@pymatviz/phonons/figures.py`:
- Around line 408-459: The non-projection branch currently rejects
CompletePhononDos even though the API accepts it; modify the standard path that
builds dos_dict so that when project is None you accept CompletePhononDos by
converting it to a PhononDos (use PhononDos(dos.frequencies, dos.densities)),
e.g. add an elif isinstance(dos, CompletePhononDos) branch in the loop over
raw_doses to set dos_dict[key] = PhononDos(dos.frequencies, dos.densities), and
keep the existing TypeError only for truly unsupported types; reference symbols:
CompletePhononDos, PhononDos, dos_dict, raw_doses, project.

@janosh janosh removed the testing Test all the things label Feb 16, 2026
- simplify phonon_dos normalization and projection control flow
- support CompletePhononDos total plotting when project is None
- add regression test and refresh README source links from hooks
- streamline phonon_dos projection handling with one validated branch
- reduce repetition in phonon DOS example plotting via looped scenarios
- preserve behavior while keeping tests and type checks green
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@assets/scripts/phonons/phonon_dos.py`:
- Around line 57-58: The linter flags long error messages in the raise
statements checking phonopy_nacl.total_dos; to satisfy TRY003 either suppress
the rule or use a custom exception—quick fix: append "# noqa: TRY003" to the two
raise statements that reference phonopy_nacl.total_dos (the one checking if
phonopy_nacl.total_dos is None and the similar block around lines 73-76) so the
linter ignores the long message, or alternatively define a short-named custom
exception (e.g., PhonopyDOSError) and raise that from those checks instead of
RuntimeError.
🧹 Nitpick comments (1)
pymatviz/phonons/figures.py (1)

467-491: Inconsistent array mutation pattern.

Line 474 uses in-place division (densities /= density_norm) while line 491 creates a new array (densities = densities / ...). While this should work correctly since get_smeared_densities typically returns a new array, using the same pattern throughout would be clearer and safer against potential future changes to the upstream method.

♻️ Suggested change for consistency
         if normalize in ("max", "sum"):
             density_norm = densities.max() if normalize == "max" else densities.sum()
             if density_norm == 0:
                 msg_key = "max density" if normalize == "max" else "sum density"
                 raise ValueError(
                     f"Cannot normalize DOS with mode={normalize!r}: {msg_key} is 0."
                 )
-            densities /= density_norm
+            densities = densities / density_norm

- Flatten nested ternary into single conditional
- Use np.zeros_like fallback instead of None check
@janosh janosh merged commit 4bb4653 into main Feb 16, 2026
9 of 10 checks passed
@janosh janosh deleted the phonon-dos-element-projection branch February 16, 2026 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Improvement to existing features/functionality examples New or improved usage examples phonons Phonon bands and DOS plots plotly Concerning plotly-powered functions

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Element-projected phonon DOS and bandstructure

1 participant