Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add structure optimization for sphinx #415

Merged
merged 6 commits into from
Feb 27, 2025
Merged

Add structure optimization for sphinx #415

merged 6 commits into from
Feb 27, 2025

Conversation

jan-janssen
Copy link
Member

@jan-janssen jan-janssen commented Feb 27, 2025

Summary by CodeRabbit

  • New Features

    • Introduced an automated atomic structure optimization process that now calculates and returns optimized positions along with associated energy and force information.
  • Refactor

    • Improved the calculation input generation process for enhanced clarity.
    • Updated calculation parameters to use clearer, more descriptive naming for improved usability.
    • Enhanced tests to reflect changes in functionality and parameter naming conventions.

Copy link
Contributor

coderabbitai bot commented Feb 27, 2025

Warning

Rate limit exceeded

@jan-janssen has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 26 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 388a903 and 469b3d8.

📒 Files selected for processing (1)
  • tests/test_evcurve_sphinxdft.py (2 hunks)

Walkthrough

This pull request refactors key input-related functions in the SphinxDFT calculator module. The original _write_input function is renamed to _generate_input, with changes to its parameters and unit conversion. A new function, optimize_positions_with_sphinxdft, is added to perform structure optimization. The static calculation and evaluation functions are updated with new parameter names and additional options for optimizer arguments. Test cases are likewise modified to validate the updated functionality and naming conventions.

Changes

File Changes
atomistics/calculators/sphinxdft.py - Renamed _write_input to _generate_input and removed the working_directory parameter; renamed eCut to energy_cutoff_in_eV with conversion from eV to Hartree.
- Added optimize_positions_with_sphinxdft function for position optimization.
- Updated calc_static_with_sphinxdft and evaluate_with_sphinx by renaming parameters and adding an optional sphinx_optimizer_kwargs.
tests/test_sphinx_parser.py - Updated imports to reflect the renaming from _write_input to _generate_input and the addition of optimize_positions_with_sphinxdft.
- Modified existing tests (test_write_input, test_calc_static) for updated parameter names.
- Renamed and reworked test_evaluate_with_sphinx to test_optimize_positions_with_sphinxdft and added new test cases for energy/forces evaluation and structure optimization.

Possibly related PRs

  • Add interface for SphinxDFT code #413: Involves similar refactoring of the SphinxDFT module functions with renaming and the introduction of structure optimization, directly related to this pull request.

Suggested reviewers

  • samwaseda

Poem

I’m a clever rabbit hopping through the code,
Tweaking inputs along each secret road.
With functions reborn, I leap at bugs so sly,
Nibbling excess lines as I hop by.
Cheers to changes in every byte and node,
A joyful code feast on this winding road! 🐰


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 0

🧹 Nitpick comments (7)
tests/test_sphinx_parser.py (7)

9-10: Remove unused imports if no longer needed.

Although these imports match the refactoring in sphinxdft.py, please consider removing any constants or functions (e.g., HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM) that are not used in this test file, to keep imports clean.


59-60: Rename ambiguous variable.

Using l as a loop variable can be confusing. Rename it to something like line for better readability.

- "".join([l for l in input_sx.split("\n") if "eCut" in l])
+ "".join([line for line in input_sx.split("\n") if "eCut" in line])
🧰 Tools
🪛 Ruff (0.8.2)

60-60: Ambiguous variable name: l

(E741)


63-64: Rename ambiguous variable.

Same reasoning as above. Use a more descriptive variable name instead of l.

- "".join([l for l in input_sx.split("\n") if "folding" in l])
+ "".join([line for line in input_sx.split("\n") if "folding" in line])
🧰 Tools
🪛 Ruff (0.8.2)

64-64: Ambiguous variable name: l

(E741)


67-68: Rename ambiguous variable.

Again, replace l with a clearer name for better readability and consistency.

- "".join([l for l in input_sx.split("\n") if "potType" in l])
+ "".join([line for line in input_sx.split("\n") if "potType" in line])
🧰 Tools
🪛 Ruff (0.8.2)

68-68: Ambiguous variable name: l

(E741)


90-105: Consider testing final atomic positions.

Currently, the test checks only for the presence of "structure_with_optimized_positions" in the results dictionary. Including an assertion to verify changes in positions (or a lower final energy) after optimization could strengthen the test.


111-112: Encapsulate repeated parameters.

These repeated default arguments for max_electronic_steps and energy_cutoff_in_eV are consistent with code elsewhere, but consider extracting them into constants or fixtures to reduce future duplication.


122-138: Add assertions to verify optimization outcome.

Similar to test_optimize_positions_with_sphinxdft, verifying the final positions or checking that an optimization step actually took place would make this test more robust. Currently, you only check the output dictionary key count.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66b638e and 31860bc.

📒 Files selected for processing (2)
  • atomistics/calculators/sphinxdft.py (8 hunks)
  • tests/test_sphinx_parser.py (5 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
tests/test_sphinx_parser.py

17-17: atomistics.calculators.sphinxdft.HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM imported but unused; consider using importlib.util.find_spec to test for availability

(F401)


18-18: atomistics.calculators.sphinxdft.BOHR_TO_ANGSTROM imported but unused; consider using importlib.util.find_spec to test for availability

(F401)


60-60: Ambiguous variable name: l

(E741)


64-64: Ambiguous variable name: l

(E741)


68-68: Ambiguous variable name: l

(E741)

⏰ Context from checks skipped due to timeout of 90000ms (4)
  • GitHub Check: unittest_qe
  • GitHub Check: unittest_matrix (macos-latest, 3.12)
  • GitHub Check: unittest_gpaw
  • GitHub Check: notebooks
🔇 Additional comments (10)
tests/test_sphinx_parser.py (2)

50-56: Parameter naming consistency check.

These parameters, especially maxSteps and energy_cutoff_in_eV, align well with the refactored _generate_input function. The refactoring from working_directory to returning the input object is consistent with the new design. Nice job!


106-106: New test function naming looks consistent.

Renaming this test method to convey “energy and forces” clarity is a good improvement.

atomistics/calculators/sphinxdft.py (8)

8-8: Great use of apply_minimization.

This import is necessary to integrate the newly introduced optimization routine. Looks good!


24-30: Refactor from _write_input to _generate_input is clear.

Removing the working_directory parameter and returning the constructed Sphinx input object improves flexibility. Good approach!


42-42: Correct unit conversion.

Dividing by HARTREE_TO_EV to convert eV to Hartree is correct. Implementation looks solid.


91-130: New function: position optimization.

  1. Good job integrating _generate_input and apply_minimization.
  2. The final updated positions are correctly multiplied by 1/BOHR_TO_ANGSTROM to switch units to Å.
  3. Consider verifying whether using an initial guess for wavefunctions is beneficial for performance of large systems.

Overall, the functionality and design are consistent with the rest of the refactoring.


137-138: Renamed parameters align with the entire refactor.

Switching from maxSteps to max_electronic_steps and eCut to energy_cutoff_in_eV preserves clarity across modules.


183-184: Minimal dictionary usage.

Initializing sphinx_optimizer_kwargs to {} if None is a standard Python approach. Good practice.


186-198: Key-based task dispatch is intuitive.

Using "optimize_positions" for conditionally running optimize_positions_with_sphinxdft is a straightforward approach. This ensures the new functionality is seamlessly integrated into evaluate_with_sphinx.


200-212: Graceful handling of tasks.

  1. The early return for calc_energy, calc_forces, or calc_stress keeps the logic modular.
  2. The fallback ValueError for unknown tasks provides clarity to users.

All looks great here.

Copy link
Contributor

@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

🧹 Nitpick comments (7)
tests/test_sphinx_parser.py (7)

8-19: Remove unused imports

Two imported constants are not used in this file:

  • HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM
  • BOHR_TO_ANGSTROM

Consider removing these imports to keep the code clean.

try:
    from sphinx_parser.toolkit import to_sphinx
    from atomistics.calculators.sphinxdft import (
        OutputParser,
        _generate_input,
        calc_static_with_sphinxdft,
        optimize_positions_with_sphinxdft,
        evaluate_with_sphinx,
        HARTREE_TO_EV,
-       HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM,
-       BOHR_TO_ANGSTROM,
    )
🧰 Tools
🪛 Ruff (0.8.2)

17-17: atomistics.calculators.sphinxdft.HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM imported but unused; consider using importlib.util.find_spec to test for availability

(F401)


18-18: atomistics.calculators.sphinxdft.BOHR_TO_ANGSTROM imported but unused; consider using importlib.util.find_spec to test for availability

(F401)


47-47: Rename test method to match refactored function

Since the _write_input function has been renamed to _generate_input, this test method should also be renamed for consistency.

-def test_write_input(self):
+def test_generate_input(self):

59-60: Simplify expression and rename ambiguous variable

Two issues in this line:

  1. The expression 25.0 * HARTREE_TO_EV / HARTREE_TO_EV simplifies to 25.0
  2. The variable name l is ambiguous and should be more descriptive
-    "	eCut = " + str(25.0 * HARTREE_TO_EV / HARTREE_TO_EV) + ";",
-    "".join([l for l in input_sx.split("\n") if "eCut" in l])
+    "	eCut = 25.0;",
+    "".join([line for line in input_sx.split("\n") if "eCut" in line])
🧰 Tools
🪛 Ruff (0.8.2)

60-60: Ambiguous variable name: l

(E741)


63-64: Rename ambiguous variable in list comprehension

The variable name l is ambiguous and should be more descriptive.

-    "".join([l for l in input_sx.split("\n") if "folding" in l])
+    "".join([line for line in input_sx.split("\n") if "folding" in line])
🧰 Tools
🪛 Ruff (0.8.2)

64-64: Ambiguous variable name: l

(E741)


67-68: Rename ambiguous variable in list comprehension

The variable name l is ambiguous and should be more descriptive.

-    "".join([l for l in input_sx.split("\n") if "potType" in l])
+    "".join([line for line in input_sx.split("\n") if "potType" in line])
🧰 Tools
🪛 Ruff (0.8.2)

68-68: Ambiguous variable name: l

(E741)


90-104: Enhance test coverage for structure optimization

The current test only verifies that the resulting structure has the same number of atoms as the input structure. Consider adding more assertions to verify the correctness of the optimization, such as:

  1. Checking that the final positions have changed from the initial positions
  2. Verifying the final energy is lower than the initial energy
  3. Checking that forces are close to zero after optimization

Also, consider using consistent parameter naming (snake_case) for dEnergy.

def test_optimize_positions_with_sphinxdft(self):
    structure_result = optimize_positions_with_sphinxdft(
        structure=self._structure,
        working_directory=self._output_directory,
        executable_function=executable_function,
        max_electronic_steps=100,
        energy_cutoff_in_eV=25.0 * HARTREE_TO_EV,
        kpoint_coords=None,
        kpoint_folding=None,
        mode="linQN",
-       dEnergy=1.0e-6,
+       energy_convergence=1.0e-6,
        max_ionic_steps=50,
    )
    self.assertEqual(len(structure_result), len(self._structure))
+   # Verify positions have changed
+   self.assertFalse(np.allclose(structure_result.positions, self._structure.positions))
+   # Verify forces are close to zero (if available)
+   # self.assertTrue(np.all(np.isclose(structure_result.get_forces(), 0.0, atol=1e-4)))

121-138: Enhance test coverage and use consistent parameter naming

Similar to the previous test method, the assertions for structure optimization are minimal. Consider adding more comprehensive checks to verify the correctness of the optimization.

Also, there's an inconsistent parameter naming convention in sphinx_optimizer_kwargs. Consider using snake_case throughout for consistency.

    sphinx_optimizer_kwargs={
        "mode": "linQN",
-       "dEnergy": 1.0e-6,
+       "energy_convergence": 1.0e-6,
        "max_ionic_steps": 50,
    },
)
self.assertTrue("structure_with_optimized_positions" in results.keys())
self.assertEqual(len(results), 1)
+# Verify the optimized structure has the expected number of atoms
+self.assertEqual(len(results["structure_with_optimized_positions"]), len(self._structure))
+# Verify positions have changed from the original structure
+self.assertFalse(np.allclose(
+    results["structure_with_optimized_positions"].positions, 
+    self._structure.positions
+))
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 31860bc and 388a903.

📒 Files selected for processing (1)
  • tests/test_sphinx_parser.py (5 hunks)
🧰 Additional context used
🪛 Ruff (0.8.2)
tests/test_sphinx_parser.py

17-17: atomistics.calculators.sphinxdft.HARTREE_OVER_BOHR_TO_EV_OVER_ANGSTROM imported but unused; consider using importlib.util.find_spec to test for availability

(F401)


18-18: atomistics.calculators.sphinxdft.BOHR_TO_ANGSTROM imported but unused; consider using importlib.util.find_spec to test for availability

(F401)


60-60: Ambiguous variable name: l

(E741)


64-64: Ambiguous variable name: l

(E741)


68-68: Ambiguous variable name: l

(E741)

⏰ Context from checks skipped due to timeout of 90000ms (16)
  • GitHub Check: unittest_matrix (ubuntu-latest, 3.10)
  • GitHub Check: unittest_sphinxdft
  • GitHub Check: unittest_matrix (ubuntu-latest, 3.11)
  • GitHub Check: unittest_matrix (windows-latest, 3.12)
  • GitHub Check: unittest_qe
  • GitHub Check: unittest_matrix (ubuntu-latest, 3.12)
  • GitHub Check: unittest_old
  • GitHub Check: unittest_matrix (macos-latest, 3.12)
  • GitHub Check: unittest_matgl
  • GitHub Check: unittest_mace
  • GitHub Check: unittest_grace
  • GitHub Check: unittest_abinit
  • GitHub Check: unittest_gpaw
  • GitHub Check: pip_check
  • GitHub Check: coverage
  • GitHub Check: notebooks

Comment on lines +53 to 54
energy_cutoff_in_eV=25.0 * HARTREE_TO_EV,
kpoint_coords=None,
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Clarify unit conversion in parameter name

The parameter energy_cutoff_in_eV suggests the value is already in eV, but you're multiplying by HARTREE_TO_EV, which appears to be converting from Hartree to eV. Consider either:

  1. Renaming the parameter to clarify the expected unit
  2. Removing the conversion factor if the value is already in eV

🏁 Script executed:

#!/bin/bash
# Check the value of HARTREE_TO_EV constant to understand the conversion
rg -A 2 'HARTREE_TO_EV\s*=' -t py

Length of output: 295


Unit Conversion Clarification – Action Required

In the snippet at tests/test_sphinx_parser.py (lines 53–54), the parameter is defined as:

energy_cutoff_in_eV = 25.0 * HARTREE_TO_EV,
kpoint_coords = None,

Since HARTREE_TO_EV is set to convert Hartree to eV (as defined in atomistics/calculators/sphinxdft.py), the literal value 25.0 is actually in Hartree. This makes the parameter’s name misleading because it implies the value is already in eV.

Please address one of the following:

  • Rename the parameter (e.g., to energy_cutoff_in_Hartree) to clearly indicate that the input is in Hartree and is subsequently converted to eV.
  • Remove the conversion factor if the intended behavior is to define the cutoff directly in electronvolts.

Also, remember to update any associated documentation and tests for consistency.

Copy link

codecov bot commented Feb 27, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 82.04%. Comparing base (66b638e) to head (469b3d8).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #415      +/-   ##
==========================================
+ Coverage   81.89%   82.04%   +0.14%     
==========================================
  Files          41       41              
  Lines        2447     2467      +20     
==========================================
+ Hits         2004     2024      +20     
  Misses        443      443              

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

@jan-janssen jan-janssen merged commit 4d610fd into main Feb 27, 2025
28 checks passed
@jan-janssen jan-janssen deleted the sphinx_structure branch February 27, 2025 10:21
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.

1 participant