Skip to content

Commit

Permalink
Fix the check_compatibility issue and add the wp.get_all_positions fu…
Browse files Browse the repository at this point in the history
…nction
  • Loading branch information
qzhu2017 committed Nov 22, 2021
1 parent 6364f3f commit 27e0655
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 220 deletions.
109 changes: 1 addition & 108 deletions pyxtal/crystal.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def __init__(
self.set_sites(sites)

# Lattice and coordinates
compat, self.degrees = self._check_compatible()
compat, self.degrees = self.group.check_compatible(self.numIons)
if not compat:
self.valid = False
msg = "Compoisition " + str(self.numIons)
Expand Down Expand Up @@ -328,113 +328,6 @@ def _set_ion_wyckoffs(self, numIon, specie, cell, wyks):

return None

def _check_compatible(self):
"""
Checks if the number of atoms is compatible with the Wyckoff
positions. Considers the number of degrees of freedom for each Wyckoff
position, and makes sure at least one valid combination of WP's exists.
NOTE Comprhys: Is degrees of freedom used symnomously with multiplicity?
perhaps standardising to multiplicity would be clearer?
"""
# Store whether or not at least one degree of freedom exists
has_freedom = False
# Store the wp's already used that don't have any freedom
used_indices = []
# Loop over species
for numIon in self.numIons:
# Get lists of multiplicity, maxn and freedom
l_mult0 = []
l_maxn0 = []
l_free0 = []
indices0 = []
for i_wp, wp in enumerate(self.group):
indices0.append(i_wp)
l_mult0.append(len(wp))
l_maxn0.append(numIon // len(wp))
if np.allclose(wp[0].rotation_matrix, np.zeros([3, 3])):
l_free0.append(False)
else:
l_free0.append(True)
# Remove redundant multiplicities:
l_mult = []
l_maxn = []
l_free = []
indices = []
for mult, maxn, free, i_wp in zip(l_mult0, l_maxn0, l_free0, indices0):
if free is True:
if mult not in l_mult:
l_mult.append(mult)
l_maxn.append(maxn)
l_free.append(True)
indices.append(i_wp)
elif free is False and i_wp not in used_indices:
l_mult.append(mult)
indices.append(i_wp)
if mult <= numIon:
l_maxn.append(1)
elif mult > numIon:
l_maxn.append(0)
l_free.append(False)

# Loop over possible combinations
p = 0 # Create pointer variable to move through lists

# Store the number of each WP, used across possible WP combinations
n0 = [0] * len(l_mult)
n = deepcopy(n0)
for i, mult in enumerate(l_mult):
if l_maxn[i] != 0:
p = i
n[i] = l_maxn[i]
break
p2 = p
if n == n0:
return False, False
while True:
num = np.dot(n, l_mult)
dobackwards = False
# The combination works: move to next species
if num == numIon:
# Check if at least one degree of freedom exists
for val, free, i_wp in zip(n, l_free, indices):
if val > 0:
if free is True:
has_freedom = True
elif free is False:
used_indices.append(i_wp)
break
# All combinations failed: return False
if n == n0 and p >= len(l_mult) - 1:
return False, False
# Too few atoms
if num < numIon:
# Forwards routine
# Move p to the right and max out
if p < len(l_mult) - 1:
p += 1
n[p] = min((numIon - num) // l_mult[p], l_maxn[p])
elif p == len(l_mult) - 1:
# p is already at last position: trigger backwards routine
dobackwards = True
# Too many atoms
if num > numIon or dobackwards is True:
# Backwards routine
# Set n[p] to 0, move p backwards to non-zero, and decrease by 1
n[p] = 0
while p > 0 and p > p2:
p -= 1
if n[p] != 0:
n[p] -= 1
if n[p] == 0 and p == p2:
p2 = p + 1
break
if has_freedom:
# All species passed: return True
return True, True
else:
# All species passed, but no degrees of freedom: return 0
return True, False

def _check_consistency(self, site, numIon):
num = 0
Expand Down
113 changes: 2 additions & 111 deletions pyxtal/molecular_crystal.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from pyxtal.lattice import Lattice, cellsize
from pyxtal.wyckoff_site import mol_site
from pyxtal.molecule import pyxtal_molecule
from pyxtal.symmetry import Group, jk_from_i
from pyxtal.symmetry import Group
from pyxtal.symmetry import choose_wyckoff_molecular as wyc_mol
from pyxtal.msg import Comp_CompatibilityError, Symm_CompatibilityError

Expand Down Expand Up @@ -128,7 +128,7 @@ def __init__(
if no_check_compability:
compat, self.degrees = True, True
else:
compat, self.degrees = self._check_compatible()
compat, self.degrees = self.group.check_compatible(self.numMols, self.valid_orientations)
if not compat:
msg = "Compoisition " + str(self.numMols)
msg += " not compatible with symmetry "
Expand Down Expand Up @@ -456,115 +456,6 @@ def fun_dist(angle, ori, mo, pt):

return None

def _check_compatible(self):
"""
Checks if the number of molecules is compatible with the Wyckoff
positions. Considers the number of degrees of freedom for each Wyckoff
position, and makes sure at least one valid combination of WP's exists.
"""
# Store whether or not at least one degree of freedom exists
has_freedom = False
# Store the wp's already used that don't have any freedom
used_indices = []
# Loop over species
for i_mol, numIon in enumerate(self.numMols):
# Get lists of multiplicity, maxn and freedom
l_mult0 = []
l_maxn0 = []
l_free0 = []
indices0 = []
for i_wp, wp in enumerate(self.group):
# Check that at least one valid orientation exists
j, k = jk_from_i(i_wp, self.group.wyckoffs_organized)
if len(self.valid_orientations[i_mol]) > j:
if len(self.valid_orientations[i_mol][j]) > k:
indices0.append(i_wp)
l_mult0.append(len(wp))
l_maxn0.append(numIon // len(wp))
if np.allclose(wp[0].rotation_matrix, np.zeros([3, 3])):
l_free0.append(False)
else:
l_free0.append(True)
# Remove redundant multiplicities:
l_mult = []
l_maxn = []
l_free = []
indices = []
for mult, maxn, free, i_wp in zip(l_mult0, l_maxn0, l_free0, indices0):
if free:
if mult not in l_mult:
l_mult.append(mult)
l_maxn.append(maxn)
l_free.append(True)
indices.append(i_wp)
#elif not free and i_wp not in used_indices:
elif i_wp not in used_indices:
l_mult.append(mult)
l_maxn.append(1)
l_free.append(False)
indices.append(i_wp)
# Loop over possible combinations
# Create pointer variable to move through lists
p = 0
# Store the number of each WP, used across possible WP combinations
n0 = [0] * len(l_mult)
n = deepcopy(n0)
for i, mult in enumerate(l_mult):
if l_maxn[i] != 0:
p = i
n[i] = l_maxn[i]
break
p2 = p

if n == n0:
#print("n == n0", n, n0)
return False, False
while True:
num = np.dot(n, l_mult)
dobackwards = False
# The combination works: move to next species
if num == numIon:
# Check if at least one degree of freedom exists
for val, free, i_wp in zip(n, l_free, indices):
if val > 0:
if free is True:
has_freedom = True
elif free is False:
indices.append(i_wp)
break
# All combinations failed: return False
if n == n0 and p >= len(l_mult) - 1:
#print("All combinations failed: return False")
return False, False
# Too few atoms
if num < numIon:
# Forwards routine
# Move p to the right and max out
if p < len(l_mult) - 1:
p += 1
n[p] = min((numIon - num) // l_mult[p], l_maxn[p])
else:
# p is already at last position: trigger backwards routine
dobackwards = True
# Too many atoms
if num > numIon or dobackwards is True:
# Backwards routine
# Set n[p] to 0, move p backwards to non-zero, and decrease by 1
n[p] = 0
while p > 0 and p > p2:
p -= 1
if n[p] != 0:
n[p] -= 1
if n[p] == 0 and p == p2:
p2 = p + 1
break
# All species passed: return True
if has_freedom:
return True, True
# All species passed, but no degrees of freedom: return 0
else:
return True, False

def _check_consistency(self, site, numMol):
"""
Check if the composition is consistent with symmetry
Expand Down
Loading

0 comments on commit 27e0655

Please sign in to comment.