Skip to content

Recreate structure fresh during get_primitive_cell#144

Open
pmrv wants to merge 6 commits intomainfrom
standardize
Open

Recreate structure fresh during get_primitive_cell#144
pmrv wants to merge 6 commits intomainfrom
standardize

Conversation

@pmrv
Copy link
Copy Markdown
Contributor

@pmrv pmrv commented Feb 14, 2024

This avoids a problem, when you pass standardize=True and the resulting cell would be larger than the original.

Summary by CodeRabbit

  • Bug Fixes

    • Reject non-fully periodic inputs for primitive-cell extraction; ensure returned primitives are explicitly periodic and warn when custom per-atom arrays are not preserved.
  • Documentation

    • Extended docstring/example to note non-copied custom arrays and related state implications.
  • Tests

    • Expanded and strengthened symmetry test coverage, updated tests to use periodic boundary conditions, and removed an obsolete test module.

@pmrv pmrv added bug Something isn't working enhancement New feature or request labels Feb 14, 2024
@pmrv pmrv requested a review from samwaseda February 14, 2024 17:01
@jan-janssen
Copy link
Copy Markdown
Member

======================================================================
ERROR: test_get_primitive_cell (test_symmetry.TestAtoms)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/work/structuretoolkit/structuretoolkit/tests/test_symmetry.py", line 149, in test_get_primitive_cell
    self.assertEqual(len(basis), len(sym.get_primitive_cell(standardize=True)))
  File "/home/runner/work/structuretoolkit/structuretoolkit/structuretoolkit/analyse/symmetry.py", line 349, in get_primitive_cell
    raise ValueError("Can only symmetrize periodic structures.")
ValueError: Can only symmetrize periodic structures.

======================================================================
ERROR: test_get_primitive_cell_hex (test_symmetry.TestAtoms)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/runner/work/structuretoolkit/structuretoolkit/tests/test_symmetry.py", line 175, in test_get_primitive_cell_hex
    structure_prim_base = sym.get_primitive_cell()
  File "/home/runner/work/structuretoolkit/structuretoolkit/structuretoolkit/analyse/symmetry.py", line 349, in get_primitive_cell
    raise ValueError("Can only symmetrize periodic structures.")
ValueError: Can only symmetrize periodic structures.

----------------------------------------------------------------------

I mark this pull request as draft until the tests pass.

@jan-janssen jan-janssen marked this pull request as draft February 14, 2024 17:14
@pmrv pmrv marked this pull request as ready for review February 14, 2024 17:26
@pmrv
Copy link
Copy Markdown
Contributor Author

pmrv commented Feb 14, 2024

I made tests pass by passing pbc=True, I think this was intended anyway.

@pmrv pmrv requested a review from samwaseda February 15, 2024 13:41
@jan-janssen jan-janssen self-requested a review as a code owner July 18, 2024 06:34
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Jul 18, 2024

📝 Walkthrough

Walkthrough

get_primitive_cell in structuretoolkit.analyse.symmetry.Symmetry was changed to require fully periodic input, use spglib scaled positions directly, construct a new primitive Structure with pbc=[True,True,True], and warn about non-copied custom arrays; extensive symmetry tests were added/updated and an old test module was removed.

Changes

Cohort / File(s) Summary
Core symmetry logic
src/structuretoolkit/analyse/symmetry.py
Reject non-fully-periodic structures, use spglib scaled positions return, build a new Structure with scaled_positions/cell and pbc=[True,True,True], emit logging.warning for custom arrays not copied, update docstring.
Expanded/updated tests
tests/test_analyse_symmetry.py
Large set of added/expanded tests: accept SpglibError in failure cases, add many cases for get_symmetry, equivalent points, space-group checks, get_primitive_cell (including standardize=True), and ensure pbc=True in ASE Atoms used in symmetry tests.
Removed legacy tests
tests/test_symmetry.py
Entire test module deleted (prior unittest-based symmetry tests removed).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Fix symmetry tests #222 — edits the same legacy symmetry test module (tests/test_symmetry.py), potentially conflicting with its deletion here.

Suggested reviewers

  • samwaseda

Poem

"I’m a rabbit in a lab of light,
I hop through lattices day and night.
I warn of arrays that won’t take flight,
I stitch new cells so edges fit tight.
🐇✨ Symmetry sings — a periodic delight."

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Recreate structure fresh during get_primitive_cell' directly describes the main implementation change in the PR, which involves reconstructing the structure via a new constructor call instead of copying and slicing the existing structure.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch standardize

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 and usage tips.

Copy link
Copy Markdown

@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

Outside diff range, codebase verification and nitpick comments (1)
structuretoolkit/analyse/symmetry.py (1)

388-390: Add a period at the end of the warning message.

The warning message should end with a period for consistency.

-            Custom arrays defined in the base structures
-            :attr:`ase.atoms.Atoms.arrays` are not copied to the new structure!
+            Custom arrays defined in the base structures
+            :attr:`ase.atoms.Atoms.arrays` are not copied to the new structure!.
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 8fc7273 and 8f5fbab.

Files selected for processing (2)
  • structuretoolkit/analyse/symmetry.py (1 hunks)
  • tests/test_symmetry.py (2 hunks)
Additional context used
Ruff
structuretoolkit/analyse/symmetry.py

421-421: Undefined name warning

(F821)

Additional comments not posted (3)
tests/test_symmetry.py (2)

176-178: LGTM! The addition of pbc=True is correct.

The change ensures that the structure is treated as periodic, which is necessary for the get_primitive_cell function to work correctly.


204-204: LGTM! The addition of pbc=True is correct.

The change ensures that the structure is treated as periodic, which is necessary for the get_primitive_cell function to work correctly.

structuretoolkit/analyse/symmetry.py (1)

392-393: Good check for periodic structures.

The check ensures that the function only operates on periodic structures, which is necessary for symmetrization.

Comment on lines +407 to +421
symbols = [indices_dict[i] for i in indices]
arrays = {
k: self._structure.arrays[k]
for k in self._structure.arrays
if k not in ("numbers", "positions")
}
new_structure = type(self._structure)(
symbols=symbols,
scaled_positions=scaled_positions,
cell=cell,
pbc=[True, True, True],
)
keys = set(arrays) - {"numbers", "positions"}
if len(keys) > 0:
warning(f"Custom arrays {keys} do not carry over to new structure!")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fix the undefined name warning.

The warning function is not defined. Use the warnings.warn function instead.

-        if len(keys) > 0:
-            warning(f"Custom arrays {keys} do not carry over to new structure!")
+        if len(keys) > 0:
+            import warnings
+            warnings.warn(f"Custom arrays {keys} do not carry over to new structure!")
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
symbols = [indices_dict[i] for i in indices]
arrays = {
k: self._structure.arrays[k]
for k in self._structure.arrays
if k not in ("numbers", "positions")
}
new_structure = type(self._structure)(
symbols=symbols,
scaled_positions=scaled_positions,
cell=cell,
pbc=[True, True, True],
)
keys = set(arrays) - {"numbers", "positions"}
if len(keys) > 0:
warning(f"Custom arrays {keys} do not carry over to new structure!")
symbols = [indices_dict[i] for i in indices]
arrays = {
k: self._structure.arrays[k]
for k in self._structure.arrays
if k not in ("numbers", "positions")
}
new_structure = type(self._structure)(
symbols=symbols,
scaled_positions=scaled_positions,
cell=cell,
pbc=[True, True, True],
)
keys = set(arrays) - {"numbers", "positions"}
if len(keys) > 0:
import warnings
warnings.warn(f"Custom arrays {keys} do not carry over to new structure!")
Tools
Ruff

421-421: Undefined name warning

(F821)

@jan-janssen jan-janssen marked this pull request as draft July 18, 2024 07:01
This avoids a problem, when you pass standardize=True and the resulting cell would be larger than the original.

Remove array copies and add warning

The trouble is that when spglib returns the symmetrized cell, it may permute, add or remove atoms
so that we cannot tell anymore which values from the original arrays we would need to copy or remove.
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 7, 2026

Codecov Report

❌ Patch coverage is 77.77778% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 82.60%. Comparing base (94ec44a) to head (15726ec).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/structuretoolkit/analyse/symmetry.py 77.77% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #144      +/-   ##
==========================================
- Coverage   82.69%   82.60%   -0.10%     
==========================================
  Files          25       25              
  Lines        1832     1834       +2     
==========================================
  Hits         1515     1515              
- Misses        317      319       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the symmetry analysis workflow to rebuild a fresh Atoms object in Symmetry.get_primitive_cell(), avoiding failures when standardize=True produces a cell with more atoms than the input. It also consolidates symmetry tests and expands coverage for periodic boundary conditions and standardized FCC cells.

Changes:

  • Reworked Symmetry.get_primitive_cell() to construct a new structure from spglib’s standardized cell output (and added a strict PBC requirement).
  • Consolidated/expanded symmetry tests into tests/test_analyse_symmetry.py, including new coverage for standardize=True on primitive FCC.
  • Removed the now-redundant tests/test_symmetry.py.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/structuretoolkit/analyse/symmetry.py Rebuilds a fresh structure in get_primitive_cell, adds PBC guard and warnings, and updates error handling.
tests/test_analyse_symmetry.py Adds/relocates symmetry tests and updates structures to use pbc=True, including a new FCC standardization regression test.
tests/test_symmetry.py Removed after moving coverage into test_analyse_symmetry.py.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 6 to 8
import string
from logging import warning

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

from logging import warning + calling warning(...) logs on the root logger and is inconsistent with the rest of the codebase, which uses warnings.warn(..., stacklevel=2) for user-facing notices (e.g. analyze/neighbors.py). Consider switching to warnings.warn (or a module-level logger via logging.getLogger(__name__)) so callers can filter/handle this message predictably.

Copilot uses AI. Check for mistakes.
Comment on lines +405 to +435
.. warning::
Custom arrays defined in the base structures
:attr:`ase.atoms.Atoms.arrays` are not copied to the new structure!
"""
if not all(self._structure.pbc):
raise ValueError("Can only symmetrize periodic structures.")
ret = spglib.standardize_cell(
self._get_spglib_cell(use_elements=use_elements, use_magmoms=use_magmoms),
to_primitive=not standardize,
)
if ret is None:
raise SymmetryError(spglib.error.get_error_message())
cell, positions, indices = ret
positions = (cell.T @ positions.T).T
new_structure = self._structure.copy()
new_structure.cell = cell
new_structure = new_structure[: len(indices)]
raise SymmetryError(spglib.spglib.spglib_error.message)
cell, scaled_positions, indices = ret
indices_dict = {
v: k
for k, v in structuretoolkit.common.helper.get_species_indices_dict(
structure=self._structure
).items()
}
new_structure.symbols = [indices_dict[i] for i in indices]
new_structure.positions = positions
symbols = [indices_dict[i] for i in indices]
arrays = {
k: self._structure.arrays[k]
for k in self._structure.arrays
if k not in ("numbers", "positions")
}
new_structure = type(self._structure)(
symbols=symbols,
scaled_positions=scaled_positions,
cell=cell,
pbc=[True, True, True],
)
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The docstring warns only about losing custom Atoms.arrays, but the new construction type(self._structure)(...) also drops other ase.Atoms state that copy() would preserve (e.g. info, constraints, calculator, and standard per-atom arrays like initial_magmoms/tags if present). Either preserve the relevant metadata when possible or expand the warning/documentation to reflect all state that will be lost.

Copilot uses AI. Check for mistakes.
pmrv and others added 2 commits April 7, 2026 16:49
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@pmrv pmrv marked this pull request as ready for review April 7, 2026 17:47
@pmrv
Copy link
Copy Markdown
Contributor Author

pmrv commented Apr 7, 2026

@samwaseda I've updated this and merge two test files that we had into one.

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (1)
src/structuretoolkit/analyse/symmetry.py (1)

7-7: logging.warning vs warnings.warn - different semantics.

The import from logging import warning is valid, but logging.warning() and warnings.warn() serve different purposes:

  • logging.warning() logs to the logging system (may be silently ignored if logging isn't configured)
  • warnings.warn() issues a Python warning that users can filter/catch and is more appropriate for deprecation-style messages

For alerting users about data loss (custom arrays not carried over), warnings.warn() is typically more appropriate as it's more visible by default.

♻️ Suggested change to use warnings.warn
-from logging import warning
+import warnings

And in line 433:

-            warning(f"Custom arrays {keys} do not carry over to new structure!")
+            warnings.warn(f"Custom arrays {keys} do not carry over to new structure!")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/structuretoolkit/analyse/symmetry.py` at line 7, The code currently
imports logging.warning and uses it to notify about custom arrays not being
carried over; change the import to use the warnings module and call
warnings.warn(...) instead of warning(...). Specifically, remove or replace
"from logging import warning" with "import warnings" and update the call site
that emits the custom-arrays/data-loss message (the warning currently emitted
around the data-loss handling in symmetry.py) to use
warnings.warn("...message...", category=UserWarning, stacklevel=2) so users can
filter/catch the warning; keep the original message text and adjust any
tests/handlers expecting logging.warning accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/structuretoolkit/analyse/symmetry.py`:
- Line 7: The code currently imports logging.warning and uses it to notify about
custom arrays not being carried over; change the import to use the warnings
module and call warnings.warn(...) instead of warning(...). Specifically, remove
or replace "from logging import warning" with "import warnings" and update the
call site that emits the custom-arrays/data-loss message (the warning currently
emitted around the data-loss handling in symmetry.py) to use
warnings.warn("...message...", category=UserWarning, stacklevel=2) so users can
filter/catch the warning; keep the original message text and adjust any
tests/handlers expecting logging.warning accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89cb8da8-d655-4a39-ad55-bf5063a6c247

📥 Commits

Reviewing files that changed from the base of the PR and between 8f5fbab and 15726ec.

📒 Files selected for processing (3)
  • src/structuretoolkit/analyse/symmetry.py
  • tests/test_analyse_symmetry.py
  • tests/test_symmetry.py
💤 Files with no reviewable changes (1)
  • tests/test_symmetry.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request format_black

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants