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 calc_displacements_ellipsoid function #87

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
Open

Conversation

kavanase
Copy link
Member

No description provided.

@kavanase kavanase changed the title displacements2 Add calc_displacements_ellipsoid function Aug 20, 2024
@SMTG-Bham SMTG-Bham deleted a comment from coderabbitai bot Aug 20, 2024
@kavanase
Copy link
Member Author

@coderabbitai review

Copy link

coderabbitai bot commented Aug 20, 2024

Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

coderabbitai bot commented Aug 20, 2024

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

The recent changes to the doped/utils/displacements.py module significantly improve its functionality for analyzing defect-related displacements in crystal structures. A new function, calc_displacements_ellipsoid, has been introduced to fit ellipsoids to displacements, enhancing visualization. Additionally, the existing calc_site_displacements function has been refined for clarity, and import statements have been organized. These enhancements not only broaden analytical capabilities but also streamline the code for better readability and maintainability.

Changes

File Path Change Summary
doped/utils/displacements.py - Added calc_displacements_ellipsoid to calculate and visualize defect displacements.
- Refined calc_site_displacements, improving logic and structure by repositioning _get_bulk_struct_with_defect.
- Updated import statements and removed commented code for clarity and maintainability.

Poem

Hop, hop, in the code we delight,
New ellipsoids shimmering bright!
With clarity now, our paths align,
Defect displacements, oh what a design!
A rabbit's cheer for the code we mend,
In the crystal world, new journeys ascend! 🐇✨


Tip

Early access features: disabled

We are currently testing the following features in early access:

  • Anthropic claude-3-5-sonnet for code reviews: Anthropic claims that the new Claude model has stronger code understanding and code generation capabilities than their previous models. We're excited to hear your feedback as we evaluate its performance over the next few days.

Note:

  • You can enable or disable early access features from the CodeRabbit UI or by updating the CodeRabbit configuration file.
  • Please join our Discord Community to provide feedback and report issues on the discussion post.

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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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 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

@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

Outside diff range, codebase verification and nitpick comments (9)
doped/utils/displacements.py (9)

604-604: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- marker=dict(color="black", size=3),
+ marker={"color": "black", "size": 3},
Tools
Ruff

604-604: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


609-611: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- scene=dict(
-     aspectmode="data",
- ),
+ scene={"aspectmode": "data"},
Tools
Ruff

609-611: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


638-638: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- line=dict(color="black", width=2),
+ line={"color": "black", "width": 2},
Tools
Ruff

638-638: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


744-753: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- marker=dict(
-     size=10,
-     opacity=0.5,
-     color=anisotropy_info_df["the_longest_radius"],  # Set color according to column "a"
-     colorscale="rainbow",
-     colorbar=dict(
-         title="The longest radius of ellipsoid",
-         titleside="right",
-     ),
- ),
+ marker={
+     "size": 10,
+     "opacity": 0.5,
+     "color": anisotropy_info_df["the_longest_radius"],  # Set color according to column "a"
+     "colorscale": "rainbow",
+     "colorbar": {
+         "title": "The longest radius of ellipsoid",
+         "titleside": "right",
+     },
+ },
Tools
Ruff

744-753: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


749-752: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


761-761: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- line=dict(color="black", dash="dash"),
+ line={"color": "black", "dash": "dash"},
Tools
Ruff

761-761: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


771-771: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- title_font=dict(size=10),
+ title_font={"size": 10},
Tools
Ruff

771-771: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


772-772: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- tickfont=dict(size=12),
+ tickfont={"size": 12},
Tools
Ruff

772-772: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


782-782: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- title_font=dict(size=10),
+ title_font={"size": 10},
Tools
Ruff

782-782: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


783-783: Optimize dictionary creation.

Rewrite the dict call as a literal for better performance and readability.

- tickfont=dict(size=12),
+ tickfont={"size": 12},
Tools
Ruff

783-783: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between b3c674d and ca0d8c1.

Files selected for processing (1)
  • doped/utils/displacements.py (3 hunks)
Additional context used
Ruff
doped/utils/displacements.py

604-604: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


609-611: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


638-638: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


744-753: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


749-752: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


761-761: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


771-771: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


772-772: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


782-782: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)


783-783: Unnecessary dict call (rewrite as a literal)

Rewrite as a literal

(C408)

Additional comments not posted (2)
doped/utils/displacements.py (2)

35-35: LGTM!

The changes to calc_site_displacements improve clarity and modularity. The function is well-structured and handles edge cases appropriately.


985-985: LGTM!

The repositioning of _get_bulk_struct_with_defect improves the modularity of the code. The function is well-documented and handles different defect types appropriately.

@kavanase
Copy link
Member Author

@teruya7 this looks very nice, thank you very much for adding to the code! 🙌

Some small things on the checklist to get this merged:

  • Would you mind adding some quick test cases, similar to those added for the original calc_site_displacements functions in test_displacements.py?
    • Likewise, adding a short example (probably using one of these test cases) to the advanced analysis tutorial would be nice to illustrate this feature!
  • (Lower priority): It would be nice if, similar to plot_site_displacements, using plotly instead of matplotlib was an option rather than a requirement. Would you be able to try implementing both backends?

@kavanase
Copy link
Member Author

Also following the CodeRabbit suggestions above; could you change the dict() calls to literal dicts ({...}) as suggested? This is the preferred formatting if you use the doped pre-commit

@teruya7
Copy link
Collaborator

teruya7 commented Aug 21, 2024

@kavanase
Thank you for your kind comments.
I will modify the points you have mentioned.

@kavanase
Copy link
Member Author

@teruya7 that was quick! 🙌
I have given you write access to doped now, so would be easiest to push directly to this PR for making this as efficient as possible.
Can you make sure to pull this branch as is first before making any other updates, to avoid merge conflicts? (There were a good few with the last branch so this will avoid some headaches).

@kavanase kavanase added the enhancement New feature or request label Aug 23, 2024
@kavanase
Copy link
Member Author

Added some other fixes and cleanup there. One issue, for the cell axes in the plotly outputs, there's a small issue where it seems to be getting them a bit wrong:
image
(From the tutorial notebook plot)

I think this is probably due to my refactoring of that part of the code to try make it a bit more succinct. Would you be able to find the issue with this and fix it? 🙏

Copy link
Member Author

@kavanase kavanase left a comment

Choose a reason for hiding this comment

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

Added two code requests there!

Once done, I think this is all ready to be merged 😃
Thanks again @teruya7!

@@ -126,6 +126,22 @@ def test_plot_site_displacements_error(self):
with pytest.raises(ValueError):
defect_entry.plot_site_displacements(vector_to_project_on=[0, 0, 1], relative_to_defect=True)

def test_calc_displacements_ellipsoid(self):
Copy link
Member Author

Choose a reason for hiding this comment

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

Nice!
Could you add some quick image comparison tests (for the plotting functions, using matplotlib) here too, like the tests at the bottom of this module?
For this you just need to add @custom_mpl_image_compare(filename="...") above the test function as for the others, where filename is the name of the reference file to compare to in tests/data/remote_baseline_plots, and your test function returns the matplotlib Figure object. Would be good to do some quick tests for the different possible combinations of options.

Then maybe a quick test each like you've done here for the outputs of the function with a substitution and interstitial defect please? (Best to test each type of defect when possible). There's an example of this in test_calc_site_displacements

Comment on lines +997 to +1085
bulk_sc, defect_sc_with_site, defect_site_index = _get_bulk_struct_with_defect(defect_entry)

# Map sites in defect supercell to bulk supercell
mappings = get_site_mapping_indices(defect_sc_with_site, bulk_sc)
mappings_dict = {i[1]: i[2] for i in mappings} # {defect_sc_index: bulk_sc_index}
# Loop over sites in defect sc
disp_dict = { # mapping defect site index (in defect sc) to displacement
"Index (defect)": [],
"Species": [],
"Species_with_index": [],
"Displacement": [],
"Displacement Norm": [],
"Distance to defect": [],
"X sites in cartesian coordinate (defect)": [],
"Y sites in cartesian coordinate (defect)": [],
"Z sites in cartesian coordinate (defect)": [],
} # type: dict

sc_defect_frac_coords = _get_defect_supercell_bulk_site_coords(defect_entry)
if sc_defect_frac_coords is None:
raise ValueError(
"The relaxed defect position (`DefectEntry.sc_defect_frac_coords`) has not been parsed. "
"Please use `DefectsParser`/`DefectParser` to parse relaxed defect positions before "
"calculating site displacements."
)

for i, site in enumerate(defect_sc_with_site):
bulk_sc_index = mappings_dict[i] # Map to bulk sc
bulk_site = bulk_sc[bulk_sc_index] # Get site in bulk sc
# Calculate displacement (need to account for pbc!)
# First final point, then initial point
frac_disp = pbc_diff(site.frac_coords, bulk_site.frac_coords) # in fractional coords
disp = bulk_sc.lattice.get_cartesian_coords(frac_disp) # in Angstroms
# Distance to defect site (last site in defect sc)
distance = defect_sc_with_site.get_distance(i, defect_site_index) # len(defect_sc_with_site) - 1)

disp_dict["Index (defect)"].append(i)
disp_dict["Displacement"].append(disp)
disp_dict["Displacement Norm"].append(np.linalg.norm(disp, ord=2))
disp_dict["Distance to defect"].append(distance)
disp_dict["Species_with_index"].append(f"{site.specie.name}({i})")
disp_dict["Species"].append(site.specie.name)
disp_dict["X sites in cartesian coordinate (defect)"].append(
_shift_defect_site_to_center_of_the_supercell(
site.frac_coords, sc_defect_frac_coords, bulk_sc
)[0]
)
disp_dict["Y sites in cartesian coordinate (defect)"].append(
_shift_defect_site_to_center_of_the_supercell(
site.frac_coords, sc_defect_frac_coords, bulk_sc
)[1]
)
disp_dict["Z sites in cartesian coordinate (defect)"].append(
_shift_defect_site_to_center_of_the_supercell(
site.frac_coords, sc_defect_frac_coords, bulk_sc
)[2]
)

with warnings.catch_warnings():
warnings.filterwarnings("ignore", "invalid value encountered in scalar divide")

# sort each list in disp dict by index of species in bulk element list, then by distance to defect:
element_list = [
el.symbol for el in defect_entry.defect.structure.composition.elements
] # host elements
element_list += sorted(
[ # extrinsic elements, sorted alphabetically for deterministic ordering in output:
el.symbol
for el in defect_entry.defect.defect_structure.composition.elements
if el.symbol not in element_list
]
)
# Combine the lists into a list of tuples, then sort, then unpack:
combined = list(zip(*disp_dict.values()))
combined.sort(
key=lambda x: (element_list.index(x[1]), x[4], x[0])
) # Sort by species, then distance, then index

(
disp_dict["Index (defect)"],
disp_dict["Species"],
disp_dict["Species_with_index"],
disp_dict["Displacement"],
disp_dict["Displacement Norm"],
disp_dict["Distance to defect"],
disp_dict["X sites in cartesian coordinate (defect)"],
disp_dict["Y sites in cartesian coordinate (defect)"],
disp_dict["Z sites in cartesian coordinate (defect)"],
) = zip(*combined)
Copy link
Member Author

Choose a reason for hiding this comment

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

A good chunk of this code is duplicated from the calc_site_displacements function. It would be best for code efficiency and maintenance if this is pulled out into a helper function that then is used in both functions (with flags for relative_to_defect, vector_to_project_on and ellipsoid to determine which disp_dict data is needed?).
Could you implement this please?

@kavanase
Copy link
Member Author

I also updated the functions to return the Figure objects if generated btw, which is useful so users can further customise if they want, and for testing.

@teruya7
Copy link
Collaborator

teruya7 commented Aug 25, 2024

Thank you for checking!
I will modify codes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants