def gradients(self): """A generator function to return the gradients dR/dp for all the restraints referring to a particular crystal's cell parameters. The return value is a list of sparse matrices, one for each of the 6 cell parameters being restrained. Each sparse matrix has as many columns as the crystal unit cell parameterisation has parameters, and as many rows as there are crystals being restrained. Gradients of zero are detected and not set in the sparse matrices to save memory.""" for i, xlucp in enumerate(self._xlucp): B = xlucp.get_state() dB_dp = flex.mat3_double(xlucp.get_ds_dp()) # Use C++ function for speed ccg = CalculateCellGradients(B, dB_dp) dRdp = [] if self._sel[0]: dRdp.append(self._construct_grad_block(ccg.da_dp(), i)) if self._sel[1]: dRdp.append(self._construct_grad_block(ccg.db_dp(), i)) if self._sel[2]: dRdp.append(self._construct_grad_block(ccg.dc_dp(), i)) if self._sel[3]: dRdp.append(self._construct_grad_block(ccg.daa_dp(), i)) if self._sel[4]: dRdp.append(self._construct_grad_block(ccg.dbb_dp(), i)) if self._sel[5]: dRdp.append(self._construct_grad_block(ccg.dcc_dp(), i)) yield dRdp
def _calculate_uc_gradients(self, sel=[True] * 6): """Calculate gradients of the unit cell parameters with respect to each of the parameters of the crystal unit cell model parameterisation""" B = self._xlucp.get_state() dB_dp = flex.mat3_double(self._xlucp.get_ds_dp()) # Use C++ function for speed ccg = CalculateCellGradients(B, dB_dp) nparam = len(dB_dp) da = list(ccg.da_dp()) if sel[0] else [0.0] * nparam db = list(ccg.db_dp()) if sel[1] else [0.0] * nparam dc = list(ccg.dc_dp()) if sel[2] else [0.0] * nparam daa = list(ccg.daa_dp()) if sel[3] else [0.0] * nparam dbb = list(ccg.dbb_dp()) if sel[4] else [0.0] * nparam dcc = list(ccg.dcc_dp()) if sel[5] else [0.0] * nparam return (da, db, dc, daa, dbb, dcc)
def _calculate_uc_gradients(self, sel=[True]*6): '''Calculate gradients of the unit cell parameters with respect to each of the parameters of the crystal unit cell model parameterisation''' B = self._xlucp.get_state() dB_dp = flex.mat3_double(self._xlucp.get_ds_dp()) # Use C++ function for speed ccg = CalculateCellGradients(B, dB_dp) nparam = len(dB_dp) da = list(ccg.da_dp()) if sel[0] else [0.0] * nparam db = list(ccg.db_dp()) if sel[1] else [0.0] * nparam dc = list(ccg.dc_dp()) if sel[2] else [0.0] * nparam daa = list(ccg.daa_dp()) if sel[3] else [0.0] * nparam dbb = list(ccg.dbb_dp()) if sel[4] else [0.0] * nparam dcc = list(ccg.dcc_dp()) if sel[5] else [0.0] * nparam return (da, db, dc, daa, dbb, dcc)
def __init__(self, model_parameterisations, sigma): """model_parameterisations is a list of CrystalUnitCellParameterisations sigma is a sequence of 6 elements giving the 'sigma' for each of the unit cell parameters, from which weights for the residuals will be calculated. Values of zero in sigma will remove the restraint for the cell parameter at that position""" self._xlucp = model_parameterisations self._nxls = len(model_parameterisations) # common factors used in gradient calculations self._meangradfac = 1.0 / self._nxls self._gradfac = 1.0 - self._meangradfac self._weights = [] # initially want to calculate all gradients self._sel = [True] * 6 # identify any cell dimensions constrained to be equal. If any are and a # restraint has been requested for that cell dimension, remove the restraint # for all crystals and warn in the log msg = ("Unit cell similarity restraints were requested for both the " "{0} and {1} dimensions, however for the crystal in experiment " "{2} these are constrained to be equal. Only the strongest " "of these restraints will be retained for all crystals in " "the restrained group.") for ixl, xlucp in enumerate(self._xlucp): B = xlucp.get_state() dB_dp = flex.mat3_double(xlucp.get_ds_dp()) ccg = CalculateCellGradients(B, dB_dp) grads = [ ccg.da_dp(), ccg.db_dp(), ccg.dc_dp(), ccg.daa_dp(), ccg.dbb_dp(), ccg.dcc_dp(), ] a, b, c, aa, bb, cc = xlucp.get_model().get_unit_cell().parameters( ) if abs(a - b) < 1e-10: grad_diff = [ abs(e1 - e2) for (e1, e2) in zip(grads[0], grads[1]) ] if max(grad_diff) < 1e-10: # a and b are equal for this crystal, therefore keep only the # strongest requested restraint if sigma[0] > 0.0 and sigma[1] > 0.0: logger.debug( msg.format("a", "b", xlucp.get_experiment_ids()[0])) strong, weak = sorted([sigma[0], sigma[1]]) sigma[0] = strong sigma[1] = 0.0 if abs(a - c) < 1e-10: grad_diff = [ abs(e1 - e2) for (e1, e2) in zip(grads[0], grads[2]) ] if max(grad_diff) < 1e-10: # a and c are equal for this crystal, therefore keep only the # strongest requested restraint if sigma[0] > 0.0 and sigma[2] > 0.0: logger.debug( msg.format("a", "c", xlucp.get_experiment_ids()[0])) strong, weak = sorted([sigma[0], sigma[2]]) sigma[0] = strong sigma[2] = 0.0 if abs(b - c) < 1e-10: grad_diff = [ abs(e1 - e2) for (e1, e2) in zip(grads[1], grads[2]) ] if max(grad_diff) < 1e-10: # b and c are equal for this crystal, therefore keep only the # strongest requested restraint if sigma[1] > 0.0 and sigma[2] > 0.0: logger.debug( msg.format("b", "c", xlucp.get_experiment_ids()[0])) strong, weak = sorted([sigma[1], sigma[2]]) sigma[1] = strong sigma[2] = 0.0 # A gradient of zero indicates that cell parameter is constrained and thus # to be ignored in restraints # _sigma = [] msg = ( "Unit cell similarity restraints were requested for the {0} " "parameter, however for the crystal in experiment {1}, {0} is " "constrained. This restraint will be removed for all crystals in " "the restrained group.") for i, (grad, pname) in enumerate( zip(grads, ["a", "b", "c", "alpha", "beta", "gamma"])): tst = (abs(g) <= 1.0e-10 for g in grad) if all(tst): # this parameter is constrained, so remove any requested restraints # at this position if sigma[i] > 0.0: logger.debug( msg.format(pname, xlucp.get_experiment_ids()[0])) sigma[i] = 0.0 # set the selection for gradient calculations to the unconstrained parameters self._sel = [s > 0.0 for s in sigma] self.nrestraints_per_cell = self._sel.count(True) # repeat the weights for each unit cell being restrained weights = [1.0 / s**2 for s in sigma if s > 0.0] weights = [flex.double(self._nxls, w) for w in weights] self._weights = weights[0] for w in weights[1:]: self._weights.extend(w)