qzhu2017 / PyXtal

A code to generate atomic structure with symmetry
MIT License
234 stars 59 forks source link

How can we obtain site-mapping between specific structures along subgroup relation #247

Closed kyledmiller closed 3 months ago

kyledmiller commented 3 months ago

Thanks for the work you've all done here. This library is incredibly feature-rich. I am having trouble with one specific task though.

What I want

I would like to use PyXtal to generate a mapping between sites of two specific pre-existing structures which have a group-subgroup relationship. For example, going between cubic and tetragonal perovskite, we see a splitting of the oxygen wyckoff site. I would like to be able to import 2 cif files and then generate the information/mapping below.

CIF 1 (Cub)            --> CIF 2 (Tet)
Atom 1      == Ba (1b) --> Ba (1b)          == Atom 1
Atom 2      == Ti (1a) --> Ti (1a)          == Atom 2
Atoms 3,4,5 == O (3d)  -->  O (1a) & O (2c) == Atom 3 & Atoms 4,5

What I've tried

get_transition() -- works to obtain child and parent structures in the same setting and describing the transformation but doesn't explicitly give site mapping or wyckoff splitting info wyckoff_split() -- provides possible splittings of a set of wyckoff sites but I can't figure out how to systematically identify which splitting occurs between two input structures

I suspect this is already possible and I'm missing some existing functionality. Any advice would be appreciated.

qzhu2017 commented 3 months ago

@kyledmiller Thanks for your question! To produce what you want, can you upload two example cif file here? I may be able to get back to you quickly with a working script as soon as I get the structures.

kyledmiller commented 3 months ago

Of course! Thanks so much for the quick response. Here are some example structures.

They are CIF formate but I had to change the extension for GitHub to allow the upload.

BaTiO3_losym.txt BaTiO3_hisym.txt

qzhu2017 commented 3 months ago

Currently, we only return the transition path, but sometimes people may just want to get the atomic mapping for the purpose of symetry analysis.

By a 2nd look, it seems that something similar was planned earlier. https://github.com/qzhu2017/PyXtal/blob/789b7024e7f5c95a4317e0b83ae377602ffc70ab/pyxtal/supergroup.py#L1028C1-L1029C1

kyledmiller commented 3 months ago
  • [ ] to output the atomic mapping information for the get_transition() function.

Currently, we only return the transition path, but sometimes people may just want to get the atomic mapping for the purpose of sysmetry analysis.

Thanks for the response but perhaps something went wrong with the markdown because it looks like some of the comment is missing.

qzhu2017 commented 3 months ago

@kyledmiller Checkout my most recently commit

$ pip install --upgrade git+https://github.com/qzhu2017/PyXtal.git@master

After that, try to run the following script assuming that you input files are BTO-ls.cif and BTO-hs.cif.

from pyxtal import pyxtal
from pyxtal.supergroup import supergroups

lt = pyxtal(); lt.from_seed('BTO-ls.cif'); print(lt)
ht = pyxtal(); ht.from_seed('BTO-hs.cif'); print(ht)

strucs, _, _, path, splitters = ht.get_transition(lt, d_tol=1.0)
# from low to high symmetry
path.reverse()
path = path[1:]
sup = supergroups(lt, path=path, show=True, max_per_G=2500)

# from high to low symmetry
for sp in splitters: print(sp)

I am still not sure how you want to extract the information. If you just want to view the results, both ways as shown in the script should be fine.

If you want to programmatically access the data, there may be a better way to do so.

kyledmiller commented 3 months ago

That is extremely helpful. Thank you very much for the quick response, Prof. Zhu.

It looks like there's a missing argument in a few of the return statements. I went ahead and made a PR to touch up the changes.

Or here's a diff if you prefer

diff --git a/pyxtal/__init__.py b/pyxtal/__init__.py
index 4027fdc..ede32ce 100644
--- a/pyxtal/__init__.py
+++ b/pyxtal/__init__.py
@@ -2210,13 +2210,14 @@ class pyxtal:
             - displacements:
             - cell translation:
             - the list of space groups along the path
+            - the list of splitters along the path
         """
         #ref_struc.sort_sites_by_numIons()
         #self.sort_sites_by_numIons()
         paths = self.group.search_subgroup_paths(ref_struc.group.number)
         if len(paths) == 0:
             print("No valid paths between the structure pairs")
-            return None, None, None, None
+            return None, None, None, None, None
         else:
             Skipped = len(paths) - max_path
             if Skipped > 0: paths = paths[:max_path] #sample(paths, max_path)
@@ -2239,7 +2240,7 @@ class pyxtal:
                         (strucs, disp, tran, count, sps) = r
                         if strucs is not None:
                             if strucs[-1].disp < d_tol2: #stop
-                                return strucs, disp, tran, p0
+                                return strucs, disp, tran, p0, sps
                             else:
                                 good_ds.append(strucs[-1].disp)
                                 good_disps.append(disp)
qzhu2017 commented 3 months ago

@kyledmiller Thanks, I just merged your pull request. Let me know if you have any other request. I am glad that this function is useful for your research.