-
Notifications
You must be signed in to change notification settings - Fork 874
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
SpaceGroup changes #3859
SpaceGroup changes #3859
Changes from 3 commits
ebc35f0
fe7363d
ebe1246
561dfef
25f90e7
d0c50ba
10b5a14
0eea0bd
c008de9
0b1dd3c
39d3683
b6d6c25
6a089c7
ccc4cc8
828cf5d
dd60f90
1d744b9
15acd36
6439fed
a33cc3c
81f76f4
26e7728
56416f2
21777c7
adcff10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -194,7 +194,7 @@ class SpaceGroup(SymmetryGroup): | |
translations: ClassVar = {k: Fraction(v) for k, v in SYMM_DATA["translations"].items()} | ||
full_sg_mapping: ClassVar = {v["full_symbol"]: k for k, v in SYMM_DATA["space_group_encoding"].items()} | ||
|
||
def __init__(self, int_symbol: str) -> None: | ||
def __init__(self, int_symbol: str, hexagonal: bool = True) -> None: | ||
"""Initialize a Space Group from its full or abbreviated international | ||
symbol. Only standard settings are supported. | ||
|
||
|
@@ -209,9 +209,22 @@ def __init__(self, int_symbol: str) -> None: | |
possible settings for a spacegroup, use the get_settings() | ||
classmethod. Alternative origin choices can be indicated by a | ||
translation vector, e.g. 'Fm-3m(a-1/4,b-1/4,c-1/4)'. | ||
hexagonal (bool): For rhombohedral groups, whether to handle as in | ||
hexagonal setting (default) or rhombohedral setting. | ||
If the int_symbol of a rhombohedral spacegroup is given with the | ||
setting ("(:)H"/"(:)R"), this parameter is overwritten accordingly | ||
(please note that the setting is not contained in the symbol | ||
attribute anymore). | ||
""" | ||
from pymatgen.core.operations import SymmOp | ||
|
||
if int_symbol.endswith("H"): | ||
self.hexagonal = True | ||
elif int_symbol.endswith("R"): | ||
self.hexagonal = False | ||
else: | ||
self.hexagonal = hexagonal | ||
|
||
int_symbol = re.sub(r" ", "", int_symbol) | ||
if int_symbol in SpaceGroup.abbrev_sg_mapping: | ||
int_symbol = SpaceGroup.abbrev_sg_mapping[int_symbol] | ||
|
@@ -223,13 +236,13 @@ def __init__(self, int_symbol: str) -> None: | |
for spg in SpaceGroup.SYMM_OPS: | ||
if int_symbol in [spg["hermann_mauguin"], spg["universal_h_m"]]: | ||
ops = [SymmOp.from_xyz_str(s) for s in spg["symops"]] | ||
self.symbol = re.sub(r":", "", re.sub(r" ", "", spg["universal_h_m"])) | ||
self.symbol = spg["hermann_mauguin"] | ||
if int_symbol in SpaceGroup.sg_encoding: | ||
self.full_symbol = SpaceGroup.sg_encoding[int_symbol]["full_symbol"] | ||
self.point_group = SpaceGroup.sg_encoding[int_symbol]["point_group"] | ||
else: | ||
self.full_symbol = re.sub(r" ", "", spg["universal_h_m"]) | ||
self.point_group = spg["schoenflies"] | ||
self.full_symbol = spg["hermann_mauguin"] # TODO full symbol not available from spg->maybe not add? | ||
self.point_group = spg["schoenflies"].split("^")[0] # TODO map onto Hermann Mauguin notation? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's come to a decision here before merging this PR. what would be the benefits of mapping onto Hermann Mauguin notation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The information is the same, but in these cases we'd have different notations for space group (Hermann Mauguin) and point group (Schoenflies) within one object. Also, it might cause issues if one wants to compare the point groups for a larger dataset (and the same point group could be there in different representations). In order to map it, we would either need a database or we could, in principle, extract the point group in Hermann Mauguin notation from the space group symbol (by removing the centering and translation parts of symmetry elements) - this would require additional testing, though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe there could be a PointGroup class method from_spacegroup() that does exactly this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that sounds like a good idea! would you prefer to do that in a separate PR (or just open an issue for it)? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great, i'd prefer to just open an issue for it and add it in this PR - will do both tomorrow (: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added the new class method and also added this info directly to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. thank you! this is great. it's super valuable to leave such a thorough paper trial for people to understand what happened later |
||
self.int_number = spg["number"] | ||
self.order = len(ops) | ||
self._symmetry_ops = {*ops} | ||
|
@@ -399,7 +412,7 @@ def check(param, ref, tolerance): | |
if crys_system == "hexagonal" or ( | ||
crys_system == "trigonal" | ||
and ( | ||
self.symbol.endswith("H") | ||
self.hexagonal | ||
or self.int_number | ||
in [143, 144, 145, 147, 149, 150, 151, 152, 153, 154, 156, 157, 158, 159, 162, 163, 164, 165] | ||
) | ||
|
@@ -531,7 +544,8 @@ def sg_symbol_from_int_number(int_number: int, hexagonal: bool = True) -> str: | |
hexagonal setting (default) or rhombohedral setting. | ||
|
||
Returns: | ||
str: Spacegroup symbol | ||
str: Spacegroup symbol / Space group symbol + "H" if group is | ||
rhombohedral and hexagonal=True | ||
""" | ||
syms = [] | ||
for n, v in SYMM_DATA["space_group_encoding"].items(): | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,17 +18,17 @@ | |
ORDERED_SYMBOLS = ( | ||
"P1 P-1 P121 P12_11 C121 P1m1 P1c1 C1m1 C1c1 P12/m1 P12_1/m1 C12/m1 P12/c1 P12_1/c1 C12/c1 P222 P222_1" | ||
" P2_12_12 P2_12_121 C222_1 C222 F222 I222 I2_12_121 Pmm2 Pmc2_1 Pcc2 Pma2 Pca2_1 Pnc2 Pmn2_1 Pba2 Pna2_1 Pnn2 " | ||
"Cmm2 Cmc2_1 Ccc2 Amm2 Aem2 Ama2 Aea2 Fmm2 Fdd2 Imm2 Iba2 Ima2 Pmmm Pnnn1 Pccm Pban1 Pmma Pnna Pmna Pcca Pbam " | ||
"Pccn Pbcm Pnnm Pmmn1 Pbcn Pbca Pnma Cmcm Cmce Cmmm Cccm Cmme Ccce1 Fmmm Fddd1 Immm Ibam Ibca Imma P4 P4_1 P4_2 " | ||
"P4_3 I4 I4_1 P-4 I-4 P4/m P4_2/m P4/n1 P4_2/n I4/m I4_1/a P422 P42_12 P4_122 P4_12_12 P4_222 P4_22_12 P4_322 " | ||
"Cmm2 Cmc2_1 Ccc2 Amm2 Aem2 Ama2 Aea2 Fmm2 Fdd2 Imm2 Iba2 Ima2 Pmmm Pnnn Pccm Pban Pmma Pnna Pmna Pcca Pbam " | ||
"Pccn Pbcm Pnnm Pmmn Pbcn Pbca Pnma Cmcm Cmce Cmmm Cccm Cmme Ccce Fmmm Fddd Immm Ibam Ibca Imma P4 P4_1 P4_2 " | ||
"P4_3 I4 I4_1 P-4 I-4 P4/m P4_2/m P4/n P4_2/n I4/m I4_1/a P422 P42_12 P4_122 P4_12_12 P4_222 P4_22_12 P4_322 " | ||
"P4_32_12 I422 I4_122 P4mm P4bm P4_2cm P4_2nm P4cc P4nc P4_2mc P4_2bc I4mm I4cm I4_1md I4_1cd P-42m P-42c P-42_1m " | ||
"P-42_1c P-4m2 P-4c2 P-4b2 P-4n2 I-4m2 I-4c2 I-42m I-42d P4/mmm P4/mcc P4/nbm1 P4/nnc1 P4/mbm P4/mnc P4/nmm1 " | ||
"P4/ncc1 P4_2/mmc P4_2/mcm P4_2/nbc P4_2/nnm P4_2/mbc P4_2/mnm P4_2/nmc P4_2/ncm I4/mmm I4/mcm I4_1/amd I4_1/acd " | ||
"P-42_1c P-4m2 P-4c2 P-4b2 P-4n2 I-4m2 I-4c2 I-42m I-42d P4/mmm P4/mcc P4/nbm P4/nnc P4/mbm P4/mnc P4/nmm " | ||
"P4/ncc P4_2/mmc P4_2/mcm P4_2/nbc P4_2/nnm P4_2/mbc P4_2/mnm P4_2/nmc P4_2/ncm I4/mmm I4/mcm I4_1/amd I4_1/acd " | ||
"P3 P3_1 P3_2 R3H P-3 R-3H P312 P321 P3_112 P3_121 P3_212 P3_221 R32H P3m1 P31m P3c1 P31c R3mH R3cH P-31m P-31c " | ||
"P-3m1 P-3c1 R-3mH R-3cH P6 P6_1 P6_5 P6_2 P6_4 P6_3 P-6 P6/m P6_3/m P622 P6_122 P6_522 P6_222 P6_422 P6_322 " | ||
"P6mm P6cc P6_3cm P6_3mc P-6m2 P-6c2 P-62m P-62c P6/mmm P6/mcc P6_3/mcm P6_3/mmc P23 F23 I23 P2_13 I2_13 Pm-3 " | ||
"Pn-31 Fm-3 Fd-31 Im-3 Pa-3 Ia-3 P432 P4_232 F432 F4_132 I432 P4_332 P4_132 I4_132 P-43m F-43m I-43m P-43n F-43c " | ||
"I-43d Pm-3m Pn-3n1 Pm-3n Pn-3m1 Fm-3m Fm-3c Fd-3m1 Fd-3c1 Im-3m Ia-3d" | ||
"Pn-3 Fm-3 Fd-3 Im-3 Pa-3 Ia-3 P432 P4_232 F432 F4_132 I432 P4_332 P4_132 I4_132 P-43m F-43m I-43m P-43n F-43c " | ||
"I-43d Pm-3m Pn-3n Pm-3n Pn-3m Fm-3m Fm-3c Fd-3m Fd-3c Im-3m Ia-3d" | ||
).split() | ||
|
||
|
||
|
@@ -150,6 +150,13 @@ def test_is_compatible(self): | |
assert sg.is_compatible(cubic) | ||
assert sg.is_compatible(rhom) | ||
assert not sg.is_compatible(hexagonal) | ||
sg = SpaceGroup("R-3m", hexagonal=True) | ||
assert not sg.is_compatible(cubic) | ||
assert sg.is_compatible(hexagonal) | ||
sg = SpaceGroup("R-3m", hexagonal=False) | ||
assert sg.is_compatible(cubic) | ||
assert sg.is_compatible(rhom) | ||
assert not sg.is_compatible(hexagonal) | ||
sg = SpaceGroup("Pnma") | ||
assert sg.is_compatible(cubic) | ||
assert sg.is_compatible(tet) | ||
|
@@ -198,14 +205,9 @@ def test_subgroup_supergroup(self): | |
assert SpaceGroup("Pma2").is_subgroup(SpaceGroup("Pccm")) | ||
assert not SpaceGroup.from_int_number(229).is_subgroup(SpaceGroup.from_int_number(230)) | ||
|
||
def test_hexagonal(self): | ||
for num in (146, 148, 155, 160, 161, 166, 167): | ||
sg = SpaceGroup.from_int_number(num, hexagonal=False) | ||
assert not sg.symbol.endswith("H") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why remove this test? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed it as the representation ("H" as last character) is not part of the symbol attribute in any case now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. replacing the assertion with a test for the hexagonal attribute sounds good |
||
|
||
def test_string(self): | ||
sg = SpaceGroup("R-3c") | ||
assert sg.to_latex_string() == r"R$\overline{3}$cH" | ||
assert sg.to_latex_string() == r"R$\overline{3}$c" | ||
sg = SpaceGroup("P6/mmm") | ||
assert sg.to_latex_string() == "P6/mmm" | ||
sg = SpaceGroup("P4_1") | ||
|
@@ -217,6 +219,11 @@ def test_repr(self): | |
symbol = ORDERED_SYMBOLS[num - 1] | ||
assert repr(sg) in f"SpaceGroup({symbol=})" | ||
|
||
def test_valid_symbol(self): # Added after issue #3845 | ||
for num in range(1, 231): | ||
symbol = SpaceGroup.from_int_number(num).symbol | ||
assert SpaceGroup(symbol).int_number == num | ||
Comment on lines
+245
to
+248
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is definitely a good test to have and an argument in favor of the changes in this PR |
||
|
||
def test_raises_on_bad_int_number(self): | ||
for num in (-5, 0, 231, 1000): | ||
with pytest.raises(ValueError, match=f"International number must be between 1 and 230, got {num}"): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you elaborate on this TODO? does this mean the current
full_symbol
is incorrect or incomplete?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - as far as I can see, the full symbol (e.g., F4/m-32/m instead of Fm-3m) is only contained in SpaceGroup.sg_encoding, but not in SpaceGroup.SYMM_OPS. Both spg keys "hermann_mauguin" and "universal_h_m" do not contain this information. We could still set this attribute but issue a warning (maybe that's better than not setting it in these cases?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a warning and this seems to be only invoked when initializing non-standard settings (as expected). E.g.,
SpaceGroup("Pmc2_1")
does not invoke a warning, butSpaceGroup("P2_1ma")
does.However, I struggle to write a test for that:
This fails with
Failed: DID NOT WARN. No warnings of type (<class 'UserWarning'>,) were emitted. Emitted warnings: [].
and I don't understand why. Any ideas?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are you sure you weren't testing against the PyPI release of
pymatgen
? your test passes for me. just pushed it to this PR. i expect it'll pass here as wellThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for figuring out this issue! a33cc3c