Source code for diffpy.cmistructure.cctbxparset

#!/usr/bin/env python
##############################################################################
#
# (c) 2009 The Trustees of Columbia University in the City of New York.
# (c) 2026 Contributors to diffpy.cmistructure.
# All rights reserved.
#
# File coded by: Chris Farrow and members of the diffpy community.
#
# Originally developed in diffpy.srfit by the DANSE Diffraction group and
# Simon J. L. Billinge.
#
# See GitHub contributions for a more detailed list of contributors.
# https://github.com/diffpy/diffpy.cmistructure/graphs/contributors
#
# See LICENSE.rst and LICENSE_DANSE.rst for license information.
#
##############################################################################
"""Wrappers for interfacing cctbx crystal with SrFit.

This wraps a cctbx.crystal as a ParameterSet with a similar hierarchy, which
can then be used within a FitRecipe. Note that all manipulations to the
cctbx.crystal should be done before wrapping. Changes made to the cctbx.crystal
object after wrapping may not be reflected within the wrapper, which can have
unpredictable results during a structure refinement.

The following classes are adapted:

- `CCTBXCrystalParSet`: wrapper for `cctbx.crystal`.
- `CCTBXUnitCellParSet`: wrapper for the unit cell of `cctbx.crystal`.
- `CCTBXScattererParSet`: wrapper for `cctbx.xray.scatterer`.
"""

from diffpy.cmistructure.basestructureparset import BaseStructureParSet
from diffpy.srfit.fitbase.parameter import ParameterAdapter
from diffpy.srfit.fitbase.parameterset import ParameterSet

__all__ = ["CCTBXScattererParSet", "CCTBXUnitCellParSet", "CCTBXCrystalParSet"]


[docs] class CCTBXScattererParSet(ParameterSet): """Adapt a cctbx.xray.scatterer to the ParameterSet interface. This class derives from ParameterSet. Attributes ---------- name : str The name of the scatterer. The name is always of the form "%s%i" % (element, number), where the number is the running index of that element type (starting at 0). x, y, z : ParameterAdapter The atom position in crystal coordinates. occupancy : ParameterAdapter The occupancy of the atom on its crystal location. Uiso : ParameterAdapter The isotropic displacement factor of the atom. """ def __init__(self, name, structure_parameter_set, index): """Initialize the scatterer ParameterSet. Parameters ---------- name : str The name of this scatterer. structure_parameter_set : CCTBXCrystalParSet The CCTBXCrystalParSet that contains the cctbx structure. index : int The index of the scatterer in the structure. """ ParameterSet.__init__(self, name) self.structure_parameter_set = structure_parameter_set self.index = index # x, y, z, occupancy self.add_parameter( ParameterAdapter("x", None, self._xyzgetter(0), self._xyzsetter(0)) ) self.add_parameter( ParameterAdapter("y", None, self._xyzgetter(1), self._xyzsetter(1)) ) self.add_parameter( ParameterAdapter("z", None, self._xyzgetter(2), self._xyzsetter(2)) ) self.add_parameter( ParameterAdapter("occupancy", None, self._getocc, self._setocc) ) self.add_parameter( ParameterAdapter("Uiso", None, self._getuiso, self._setuiso) ) return # Getters and setters def _xyzgetter(self, i): def f(dummy): return self.structure_parameter_set.structure.scatterers()[ self.index ].site[i] return f def _xyzsetter(self, i): def f(dummy, value): xyz = list( self.structure_parameter_set.structure.scatterers()[ self.index ].site ) xyz[i] = value self.structure_parameter_set.structure.scatterers()[ self.index ].site = tuple(xyz) return return f def _getocc(self, dummy): return self.structure_parameter_set.structure.scatterers()[ self.index ].occupancy def _setocc(self, dummy, value): self.structure_parameter_set.structure.scatterers()[ self.index ].occupancy = value return def _getuiso(self, dummy): return self.structure_parameter_set.structure.scatterers()[ self.index ].u_iso def _setuiso(self, dummy, value): self.structure_parameter_set.structure.scatterers()[ self.index ].u_iso = value return def _getelem(self): return self.structure.element_symbol() element = property(_getelem)
# End class CCTBXScattererParSet
[docs] class CCTBXUnitCellParSet(ParameterSet): """Adapt a cctbx unit_cell to the ParameterSet interface. Attributes ---------- name : str The name of this ParameterSet, always "unitcell". a, b, c, alpha, beta, gamma : ParameterAdapter The unit cell parameters. """ def __init__(self, structure_parameter_set): """Initialize the unit cell ParameterSet. Parameters ---------- structure_parameter_set : CCTBXCrystalParSet The CCTBXCrystalParSet that contains the cctbx structure and the unit cell being wrapped. """ ParameterSet.__init__(self, "unitcell") self.structure_parameter_set = structure_parameter_set self._latpars = list( self.structure_parameter_set.structure.unit_cell().parameters() ) self.add_parameter( ParameterAdapter("a", None, self._latgetter(0), self._latsetter(0)) ) self.add_parameter( ParameterAdapter("b", None, self._latgetter(1), self._latsetter(1)) ) self.add_parameter( ParameterAdapter("c", None, self._latgetter(2), self._latsetter(2)) ) self.add_parameter( ParameterAdapter( "alpha", None, self._latgetter(3), self._latsetter(3) ) ) self.add_parameter( ParameterAdapter( "beta", None, self._latgetter(4), self._latsetter(4) ) ) self.add_parameter( ParameterAdapter( "gamma", None, self._latgetter(5), self._latsetter(5) ) ) return def _latgetter(self, i): def f(dummy): return self._latpars[i] return f def _latsetter(self, i): def f(dummy, value): self._latpars[i] = value self.structure_parameter_set._update = True return return f
# End class CCTBXUnitCellParSet # FIXME - Special positions should be constant.
[docs] class CCTBXCrystalParSet(BaseStructureParSet): """Adapt a cctbx structure to the ParameterSet interface. Attributes ---------- structure : cctbx.crystal.special_position_settings The adapted cctbx structure object. scatterers : list of CCTBXScattererParSet The scatterer ParameterSets. unitcell : CCTBXUnitCellParSet The unit cell ParameterSet for the structure. """ def __init__(self, name, structure): """Initialize the crystal ParameterSet. Parameters ---------- name : str The name of this ParameterSet. structure : cctbx.crystal.special_position_settings The cctbx structure to adapt. """ ParameterSet.__init__(self, name) self.structure = structure self.add_parameter_set(CCTBXUnitCellParSet(self)) self.scatterers = [] self._update = False cdict = {} for s in structure.scatterers(): el = s.element_symbol() i = cdict.get(el, 0) sname = "%s%i" % (el, i) cdict[el] = i + 1 scatterer = CCTBXScattererParSet(sname, self, i) self.add_parameter_set(scatterer) self.scatterers.append(scatterer) # Constrain the lattice from diffpy.cmistructure.sgconstraints import _constrain_space_group symbol = self.get_space_group() _constrain_space_group(self, symbol) return
[docs] def update(self): """Rebuild the unit cell after a change in lattice parameters. Call this function before using the CCTBXCrystalParSet. The unit cell is only remade if a lattice parameter has changed. """ if not self._update: return self._update = False structure = self.structure sgn = structure.space_group().match_tabulated_settings().number() # Create the symmetry object from cctbx.crystal import symmetry symm = symmetry( unit_cell=self.unitcell._latpars, space_group_symbol=sgn ) # Now the new structure newstru = structure.__class__( crystal_symmetry=symm, scatterers=structure.scatterers() ) self.unitcell._latpars = list(newstru.unit_cell().parameters()) self.structure = newstru return
[docs] @classmethod def can_adapt(self, structure): """Return whether the structure can be adapted by this class. Parameters ---------- structure : object The structure object to check. Returns ------- bool The flag indicating if `structure` is a cctbx.crystal.special_position_settings. False if cctbx is not installed. """ try: from cctbx.crystal import special_position_settings except ImportError: return False return isinstance(structure, special_position_settings)
[docs] def get_lattice(self): """Return the ParameterSet containing the lattice Parameters. Returns ------- CCTBXUnitCellParSet The unit cell ParameterSet of the structure. """ return self.unitcell
[docs] def get_scatterers(self): """Return the list of ParameterSets that represent the scatterers. Returns ------- list of CCTBXScattererParSet The scatterer ParameterSets of the structure. """ return self.scatterers
[docs] def get_space_group(self): """Return the Hermann-Mauguin space group symbol of the structure. Returns ------- str The Hermann-Mauguin space group symbol. """ space_group = self.structure.space_group() t = space_group.type() return t.lookup_symbol()
# End class CCTBXCrystalParSet