Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions news/add-structure-subpackage.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
**Added:**

* No news needed: add the ``structure`` subpackage.

**Changed:**

* <news item>

**Deprecated:**

* <news item>

**Removed:**

* <news item>

**Fixed:**

* <news item>

**Security:**

* <news item>
1 change: 1 addition & 0 deletions requirements/tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ codecov
coverage
pytest-cov
pytest-env
pyobjcryst
3 changes: 3 additions & 0 deletions src/diffpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@
# See LICENSE.rst for license information.
#
##############################################################################
from pkgutil import extend_path

__path__ = extend_path(__path__, __name__)
6 changes: 3 additions & 3 deletions src/diffpy/cmipdf/basepdfgenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@

import numpy

from diffpy.cmipdf.structure import struToParameterSet
from diffpy.srfit.exceptions import SrFitError
from diffpy.srfit.fitbase import ProfileGenerator
from diffpy.srfit.fitbase.parameter import ParameterAdapter
from diffpy.srfit.structure import struToParameterSet

# FIXME - Parameter creation will have to be smarter once deeper calculator
# configuration is enabled.
Expand Down Expand Up @@ -257,7 +257,7 @@ def set_structure(self, structure, name="phase", periodic=True):
This creates a DiffpyStructureParSet, ObjCrystCrystalParSet or
ObjCrystMoleculeParSet that adapts structure to a ParameterSet
interface.
See those classes (located in diffpy.srfit.structure) for how they are
See those classes (located in diffpy.cmipdf.structure) for how they are
used. The resulting ParameterSet will be managed by this generator.

Parameters
Expand Down Expand Up @@ -310,7 +310,7 @@ def set_structure_from_parset(self, parset, periodic=True):
self.add_parameter_set(parset)

# Set periodicity
self._phase.useSymmetry(periodic)
self._phase.use_symmetry(periodic)
return

def _prepare(self, r):
Expand Down
2 changes: 1 addition & 1 deletion src/diffpy/cmipdf/debyepdfgenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ def set_structure(self, structure, name="phase", periodic=False):
This creates a DiffpyStructureParSet, ObjCrystCrystalParSet or
ObjCrystMoleculeParSet that adapts structure to a ParameterSet
interface.
See those classes (located in diffpy.srfit.structure) for how they are
See those classes (located in diffpy.cmipdf.structure) for how they are
used. The resulting ParameterSet will be managed by this generator.

Parameters
Expand Down
66 changes: 66 additions & 0 deletions src/diffpy/cmipdf/structure/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/usr/bin/env python
##############################################################################
#
# (c) 2025 Simon Billinge.
# All rights reserved.
#
# File coded by: Caden Myers, Simon Billinge, and members of the Billinge
# group.
#
# See GitHub contributions for a more detailed list of contributors.
# https://github.com/diffpy/diffpy.cmipdf/graphs/contributors
#
# See LICENSE.rst for license information.
#
##############################################################################
"""Modules and classes that adapt structure representations to the
ParameterSet interface and automatic structure constraint generation
from space group information."""

from diffpy.cmipdf.structure.sgconstraints import constrain_as_space_group

__all__ = ["constrain_as_space_group", "struToParameterSet"]


def struToParameterSet(name, stru):
"""Creates a ParameterSet from an structure.

This returns a ParameterSet adapted for the structure depending on its
type.

Parameters
----------
stru
a structure object known by this module
name
A name to give the structure.

Raises TypeError if stru cannot be adapted
"""
from diffpy.cmipdf.structure.diffpyparset import DiffpyStructureParSet

if DiffpyStructureParSet.can_adapt(stru):
return DiffpyStructureParSet(name, stru)

from diffpy.cmipdf.structure.objcrystparset import ObjCrystCrystalParSet

if ObjCrystCrystalParSet.can_adapt(stru):
return ObjCrystCrystalParSet(name, stru)

from diffpy.cmipdf.structure.objcrystparset import ObjCrystMoleculeParSet

if ObjCrystMoleculeParSet.can_adapt(stru):
return ObjCrystMoleculeParSet(name, stru)

from diffpy.cmipdf.structure.cctbxparset import CCTBXCrystalParSet

if CCTBXCrystalParSet.can_adapt(stru):
return CCTBXCrystalParSet(name, stru)

raise TypeError("Unadaptable structure format")


# silence pyflakes checker
assert constrain_as_space_group

# End of file
65 changes: 65 additions & 0 deletions src/diffpy/cmipdf/structure/basestructureparset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env python
##############################################################################
#
# (c) 2025 Simon Billinge.
# All rights reserved.
#
# File coded by: Caden Myers, Simon Billinge, and members of the Billinge
# group.
#
# See GitHub contributions for a more detailed list of contributors.
# https://github.com/diffpy/diffpy.cmipdf/graphs/contributors
#
# See LICENSE.rst for license information.
#
##############################################################################
"""Base class for adapting structures to a ParameterSet interface.

The BaseStructureParSet is a ParameterSet with functionality required by
all structure adapters.
"""

__all__ = ["BaseStructureParSet"]

from diffpy.srfit.fitbase.parameterset import ParameterSet


class BaseStructureParSet(ParameterSet):
"""Base class for structure adapters.

BaseStructureParSet derives from ParameterSet and provides methods that
help interface the ParameterSet with the space group constraint methods in
the sgconstraints module and to ProfileGenerators.

Attributes
----------
stru
The adapted object
"""

@classmethod
def can_adapt(self, stru):
"""Return whether the structure can be adapted by this class."""
return False

def get_lattice(self):
"""Get a ParameterSet containing the lattice Parameters.

The returned ParameterSet may contain other Parameters than the
lattice Parameters. It is assumed that the lattice parameters
are named "a", "b", "c", "alpha", "beta", "gamma".

Lattice must also have the "angunits" attribute, which is either
"deg" or "rad", to signify degrees or radians.
"""
raise NotImplementedError("The must be overloaded")

def get_scatterers(self):
"""Get a list of ParameterSets that represents the scatterers.

The site positions must be accessible from the list entries via
the names "x", "y", and "z". The ADPs must be accessible as
well, but the name and nature of the ADPs (U-factors, B-factors,
isotropic, anisotropic) depends on the adapted structure.
"""
raise NotImplementedError("The must be overloaded")
115 changes: 115 additions & 0 deletions src/diffpy/cmipdf/structure/bvsrestraint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/env python
##############################################################################
#
# (c) 2025 Simon Billinge.
# All rights reserved.
#
# File coded by: Caden Myers, Simon Billinge, and members of the Billinge
# group.
#
# See GitHub contributions for a more detailed list of contributors.
# https://github.com/diffpy/diffpy.cmipdf/graphs/contributors
#
# See LICENSE.rst for license information.
#
##############################################################################
"""Bond-valence sum calculator from SrReal wrapped as a Restraint.

This can be used as an addition to a cost function during a structure
refinement to keep the bond-valence sum within tolerable limits.
"""

__all__ = ["BVSRestraint"]

from diffpy.srfit.exceptions import SrFitError
from diffpy.srfit.fitbase.restraint import Restraint


class BVSRestraint(Restraint):
"""Wrapping of BVSCalculator.bvmsdiff as a Restraint.

The restraint penalty is the root-mean-square deviation of the theoretical
and calculated bond-valence sum of a structure.

Attributes
----------
_calc
The SrReal BVSCalculator instance.
_parset
The SrRealParSet that created this BVSRestraint.
sig
The uncertainty on the BVS (default 1).
scaled
A flag indicating if the restraint is scaled (multiplied)
by the unrestrained point-average chi^2 (chi^2/numpoints)
(default False).
"""

def __init__(self, parset, sig=1, scaled=False):
"""Initialize the Restraint.

Parameters
----------
parset
SrRealParSet that creates this BVSRestraint.
sig
The uncertainty on the BVS (default 1).
scaled
A flag indicating if the restraint is scaled
(multiplied) by the unrestrained point-average chi^2
(chi^2/numpoints) (bool, default False).
"""
from diffpy.srreal.bvscalculator import BVSCalculator

self._calc = BVSCalculator()
self._parset = parset
self.sig = float(sig)
self.scaled = bool(scaled)
return

def penalty(self, w=1.0):
"""Calculate the penalty of the restraint.

Parameters
----------
w
The point-average chi^2 which is optionally used to scale the
penalty (float, default 1.0).
"""
# Get the bvms from the BVSCalculator
stru = self._parset._get_srreal_structure()
self._calc.eval(stru)
penalty = self._calc.bvmsdiff

# Scale by the prefactor
penalty /= self.sig**2

# Optionally scale by w
if self.scaled:
penalty *= w

return penalty

def _validate(self):
"""This evaluates the calculator.

Raises SrFitError if validation fails.
"""
from numpy import nan

p = self.penalty()
if p is None or p is nan:
raise SrFitError("Cannot evaluate penalty")
v = self._calc.value
if len(v) > 1 and not v.any():
emsg = (
"Bond valence sums are all zero. Check atom symbols in "
"the structure or define custom bond-valence parameters."
)
raise SrFitError(emsg)
return

# End of class BVSRestraint


# End of file
Loading
Loading