import libcasm.clusterography
import libcasm.configuration
import libcasm.occ_events
import libcasm.xtal
[docs]
def make_occevent_suborbits(
supercell: libcasm.configuration.Supercell, occ_event: libcasm.occ_events.OccEvent
) -> list[list[libcasm.occ_events.OccEvent]]:
r"""Make the sub-orbits of OccEvent in a supercell
This method generates the sub-orbits that occur due to a supercell that has less
symmetry than the prim. Each sub-orbit is made up of OccEvent that are equivalent
with respect to the supercell factor group. OccEvent in different sub-orbits are
equivalent with respect to the prim factor group, but not the supercell factor
group.
Parameters
----------
supercell: ~libcasm.configuration.Supercell
The :class:`~libcasm.configuration.Supercell`.
occ_event: ~libcasm.occ_events.OccEvent
The :class:`~libcasm.occ_events.OccEvent`.
Returns
-------
suborbits: list[list[~libcasm.occ_events.OccEvent]]
The sub-orbits, where `suborbits[i][j]` is the j-th
:class:`~libcasm.occ_events.OccEvent` in the i-th sub-orbit.
"""
prim = supercell.prim
prim_factor_group = prim.factor_group
prim_rep = libcasm.occ_events.make_occevent_symgroup_rep(
prim_factor_group.elements, prim.xtal_prim
)
orbit = libcasm.occ_events.make_prim_periodic_orbit(occ_event, prim_rep)
def in_any_suborbit(x, suborbits):
for suborbit in suborbits:
if x in suborbit:
return True
return False
suborbits = []
scel_factor_group = supercell.factor_group
scel_rep = libcasm.occ_events.make_occevent_symgroup_rep(
scel_factor_group.elements, prim.xtal_prim
)
for x in orbit:
if in_any_suborbit(x, suborbits):
continue
new_suborbit = libcasm.occ_events.make_prim_periodic_orbit(x, scel_rep)
if new_suborbit not in suborbits:
suborbits.append(new_suborbit)
return suborbits
def _make_symop_inverse(
op: libcasm.xtal.SymOp,
) -> libcasm.xtal.SymOp:
"""Make the inverse SymOp
Parameters
----------
op: libcasm.xtal.SymOp
A SymOp
Returns
-------
op_inv: libcasm.xtal.SymOp
The inverse SymOp
"""
return libcasm.xtal.SymOp(
matrix=op.matrix().T,
translation=-(op.matrix().T @ op.translation()),
time_reversal=op.time_reversal(),
)
[docs]
def make_equivalents_generators(
phenomenal_prototype: libcasm.clusterography.Cluster,
generating_group: libcasm.sym_info.SymGroup,
prim: libcasm.configuration.Prim,
) -> tuple[
list[libcasm.xtal.SymOp], list[int], list[libcasm.xtal.IntegralSiteCoordinateRep]
]:
"""Make symmetry operations that generate all the equivalent local orbits in \
the primitive cell.
Notes
-----
- If the `cluster_specs.generating_group()` is a subgroup of the phenomenal
cluster group, then there will be >1 distinct sets of local orbits around the
phenomenal cluster.
- This method finds the cluster group operations that generate the distinct set of
local orbits, then it uses the phenomenal cluster orbit equivalence map to
find operations that transform the local orbits sets to the equivalent
phenomenal clusters in the primitive cell.
Parameters
----------
phenomenal_prototype: casmclust.Cluster
The prototype phenomenal cluster. The prototype phenomenal cluster must be
chosen from one of the equivalents that is generated by
:func:`~libcasm.clusterography.make_periodic_orbit` using the prim factor
group.
generating_group: sym_info.SymGroup
The local orbits generating group.
prim: libcasm.configuration.Prim
The prim, with symmetry info
Returns
-------
ops: list[libcasm.xtal.SymOp]
Symmetry operations that generate the equivalent local orbits in
the primitive unit cell.
indices: list[int]
Indices of prim factor group operations corresponding to `ops`.
site_reps: list[libcasm.xtal.IntegralSiteCoordinateRep]
Symmetry group representation for transforming IntegralSiteCoordinate
and Cluster corresponding to `ops`.
"""
import libcasm.clusterography as casmclust
# collect needed sym groups
factor_grp = prim.factor_group
generating_grp = generating_group
site_rep = prim.integral_site_coordinate_symgroup_rep
phenomenal_cluster_grp = casmclust.make_cluster_group(
cluster=phenomenal_prototype,
group=factor_grp,
lattice=prim.xtal_prim.lattice(),
integral_site_coordinate_symgroup_rep=site_rep,
)
# find indices of factor group operations
# that generate equivalent (but rotated) local basis sets
# about the phenomenal cluster.
i_factor_grp_equiv_on_phenomenal = set()
for i_cluster_grp in range(len(phenomenal_cluster_grp.elements)):
i_factor_grp = phenomenal_cluster_grp.head_group_index[i_cluster_grp]
i_factor_grp_min = i_factor_grp
for j_generating_grp in range(len(generating_grp.elements)):
j_factor_grp = generating_grp.head_group_index[j_generating_grp]
k_product = factor_grp.mult(j_factor_grp, i_factor_grp)
if k_product < i_factor_grp_min:
i_factor_grp_min = k_product
i_factor_grp_equiv_on_phenomenal.add(i_factor_grp_min)
# generate the phenomenal cluster orbit and equivalence map
phenomenal_orbit = casmclust.make_periodic_orbit(
orbit_element=phenomenal_prototype,
integral_site_coordinate_symgroup_rep=site_rep,
)
equivalence_map = casmclust.make_periodic_equivalence_map(
orbit=phenomenal_orbit,
symgroup=factor_grp,
lattice=prim.xtal_prim.lattice(),
integral_site_coordinate_symgroup_rep=site_rep,
)
equivalence_map_indices = casmclust.make_periodic_equivalence_map_indices(
orbit=phenomenal_orbit,
integral_site_coordinate_symgroup_rep=site_rep,
)
# find op and factor group index that transform phenomenal to orbit prototype
to_prototype_op = None
i_to_prototype = None
sorted_phenomenal = phenomenal_prototype.sorted()
for i_clust, clust in enumerate(phenomenal_orbit):
sorted_clust = clust.sorted()
if sorted_clust == sorted_phenomenal:
to_prototype_op = _make_symop_inverse(equivalence_map[i_clust][0])
i_to_prototype = factor_grp.inv(equivalence_map_indices[i_clust][0])
break
if to_prototype_op is None:
raise Exception(
"Error in make_equivalents_generators: Failed to find to_prototype_op."
"The phenomenal cluster must be chosen from one of the"
"equivalents generated by `libcasm.clusterography.make_periodic_orbit`."
)
# equiv bset = to_equiv_op * (to_prototype_op * (cluster_grp_op * phenomenal bset))
# ^ distinct bset on phenomenal
# ^ bset on prototype
# ^ bset on other phenomenal
generating_indices = []
for i_factor_grp in i_factor_grp_equiv_on_phenomenal:
for i_equiv in range(len(equivalence_map)):
i_to_equiv = equivalence_map_indices[i_equiv][0]
i_generating_op = factor_grp.mult(
i_to_equiv, factor_grp.mult(i_to_prototype, i_factor_grp)
)
generating_indices.append(i_generating_op)
generating_indices.sort()
generating_ops = []
for i in generating_indices:
generating_ops.append(factor_grp.elements[i])
generating_site_reps = casmclust.make_integral_site_coordinate_symgroup_rep(
group_elements=generating_ops,
xtal_prim=prim.xtal_prim,
)
return (generating_ops, generating_indices, generating_site_reps)
[docs]
def make_occevent_equivalents_generators(
prototype_event: libcasm.occ_events.OccEvent,
prim: libcasm.configuration.Prim,
) -> tuple[
list[libcasm.xtal.SymOp], list[int], list[libcasm.xtal.IntegralSiteCoordinateRep]
]:
"""Make symmetry operations that generate all the equivalent OccEvent in \
the primitive cell.
Parameters
----------
prototype_event: libcasm.occ_events.OccEvent
The prototype OccEvent. The underlying cluster `prototype_event.cluster` must be
chosen from one of the equivalents that is generated by
:func:`~libcasm.clusterography.make_periodic_orbit` using the prim factor
group.
prim: libcasm.configuration.Prim
The prim, with symmetry info
Returns
-------
ops: list[libcasm.xtal.SymOp]
Symmetry operations that generate the equivalent local orbits in
the primitive unit cell.
indices: list[int]
Indices of prim factor group operations corresponding to `ops`.
site_reps: list[libcasm.xtal.IntegralSiteCoordinateRep]
Symmetry group representation for transforming IntegralSiteCoordinate
and Cluster corresponding to `ops`.
"""
occevent_symgroup_rep = libcasm.occ_events.make_occevent_symgroup_rep(
prim.factor_group.elements, prim.xtal_prim
)
generating_group = libcasm.occ_events.make_occevent_group(
occ_event=prototype_event,
group=prim.factor_group,
lattice=prim.xtal_prim.lattice(),
occevent_symgroup_rep=occevent_symgroup_rep,
)
return make_equivalents_generators(
phenomenal_prototype=prototype_event.cluster(),
generating_group=generating_group,
prim=prim,
)