Skip to content

Commit

Permalink
Lazily compute structure factor
Browse files Browse the repository at this point in the history
Instead of computing the structure factor every time a property of the
material changes, flag the structure factor as invalid, and only re-compute
it if it is requested.

This significantly speeds up interaction with the lattice parameter, such
as with the PT sliders.

Signed-off-by: Patrick Avery <[email protected]>
  • Loading branch information
psavery committed Jan 9, 2024
1 parent b764fae commit bea9b1c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 8 deletions.
24 changes: 24 additions & 0 deletions hexrd/material/crystallography.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,9 @@ def __init__(self,
raise RuntimeError('have unparsed keyword arguments with keys: '
+ str(list(kwargs.keys())))

# This is only used to calculate the structure factor if invalidated
self.__unitcell = None

self.__calc()

return
Expand Down Expand Up @@ -935,7 +938,27 @@ def set_wavelength(self, wavelength):

wavelength = property(get_wavelength, set_wavelength, None)

def invalidate_structure_factor(self, unitcell):
# It can be expensive to compute the structure factor, so provide the
# option to just invalidate it, while providing a unit cell, so that
# it can be lazily computed from the unit cell.
self.__structFact = None
self._powder_intensity = None
self.__unitcell = unitcell

def _compute_sf_if_needed(self):
any_invalid = (
self.__structFact is None or
self._powder_intensity is None
)
if any_invalid and self.__unitcell is not None:
# Compute the structure factor first.
# This can be expensive to do, so we lazily compute it when needed.
hkls = self.getHKLs(allHKLs=True)
self.set_structFact(self.__unitcell.CalcXRSF(hkls))

def get_structFact(self):
self._compute_sf_if_needed()
return self.__structFact[~self.exclusions]

def set_structFact(self, structFact):
Expand All @@ -953,6 +976,7 @@ def set_structFact(self, structFact):

@property
def powder_intensity(self):
self._compute_sf_if_needed()
return self._powder_intensity[~self.exclusions]

@staticmethod
Expand Down
14 changes: 6 additions & 8 deletions hexrd/material/material.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def __init__(
self.reset_v0()

self._newPdata()
self.update_structure_factor()
self.invalidate_structure_factor()

def __str__(self):
"""String representation"""
Expand Down Expand Up @@ -291,7 +291,7 @@ def _newUnitcell(self):
def _hkls_changed(self):
# Call this when something happens that changes the hkls...
self._newPdata()
self.update_structure_factor()
self.invalidate_structure_factor()

def _newPdata(self):
"""Create a new plane data instance if the hkls have changed"""
Expand Down Expand Up @@ -405,10 +405,8 @@ def enable_hkls_below_tth(self, tth_threshold=90.0):

self._pData.exclusions = dflt_excl

def update_structure_factor(self):
hkls = self.planeData.getHKLs(allHKLs=True)
sf = self.unitcell.CalcXRSF(hkls)
self.planeData.set_structFact(sf)
def invalidate_structure_factor(self):
self.planeData.invalidate_structure_factor(self.unitcell)

def compute_powder_overlay(
self, ttharray=np.linspace(0, 80, 2000), fwhm=0.25, scale=1.0
Expand Down Expand Up @@ -1268,7 +1266,7 @@ def charge(self, vals):

self._charge = vals
# self._newUnitcell()
# self.update_structure_factor()
# self.invalidate_structure_factor()

@property
def absorption_length(self):
Expand Down Expand Up @@ -1390,7 +1388,7 @@ def _set_atomdata(self, atomtype, atominfo, U, charge):
self.charge = charge

self._newUnitcell()
self.update_structure_factor()
self.invalidate_structure_factor()

#
# ========== Methods
Expand Down

0 comments on commit bea9b1c

Please sign in to comment.