def scales_and_derivatives(self, phi): """Calculate the overall scale factor at each position in 'phi' and the derivatives of that scale factor wrt all parameters of the model""" # obtain data from all scale factor components data = [f.get_factors_and_derivatives(phi) for f in self._factors] # FIXME only using phi at the moment. In future will need other information # such as s1 directions or central impacts, and will have to pass the right # bits of information to the right ScaleFactor components contained here scale_components, grad_components = zip(*data) # the overall scale is the product of the separate scale components overall_scale = reduce(lambda fac1, fac2: fac1 * fac2, scale_components) # to convert derivatives of each scale component to derivatives of the # overall scale we multiply by the product of the other scale components, # omitting the factor that has been differentiated if len(scale_components) > 1: omit_one_prods = products_omitting_one_item(scale_components) grad_components = [row_multiply(g, coeff) for g, coeff in \ zip(grad_components, omit_one_prods)] # Now combine the gradient components by columns to produce a single # gradient matrix for the overall scale each_ncol = [g.n_cols for g in grad_components] tot_ncol = sum(each_ncol) grad = sparse.matrix(len(overall_scale), tot_ncol) col_start = [0] + each_ncol[:-1] for icol, g in zip(col_start, grad_components): grad.assign_block(g, 0, icol) return overall_scale, grad
def test_row_multiply(): m = sparse.matrix(3, 2) m[0, 0] = 1.0 m[0, 1] = 2.0 m[1, 1] = 3.0 m[2, 0] = 4.0 fac = flex.double((3, 2, 1)) m2 = row_multiply(m, fac) assert m2.as_dense_matrix().as_1d() == flex.double( [3.0, 6.0, 0.0, 6.0, 4.0, 0.0]).all_eq(True)
def test_row_multiply(): m = sparse.matrix(3, 2) m[0,0] = 1. m[0,1] = 2. m[1,1] = 3. m[2,0] = 4. fac = flex.double((3, 2, 1)) m2 = row_multiply(m, fac) assert m2.as_dense_matrix().as_1d() == flex.double( [3.0, 6.0, 0.0, 6.0, 4.0, 0.0]).all_eq(True) print "OK"
def get_factors_and_derivatives(self, seq): """Calculate and return the smoothed values and their derivatives with respect to the underlying parameters for this scale factor component, for the reflections described by the values in seq. For example, these may be the phi rotation angle values for a scale factor component that is a function of phi.""" # Obtain data from the smoother, where value and sumweight are arrays with # the same length as seq. Weight is a sparse matrix with one row per # element of seq. Each row has some (typically 3) non-zero values # corresponding to the positions nearest the element of seq. value, weight, sumweight = self._smoother.multi_value_weight( seq, self._param) # The gradient of a single smoothed value with respect to the parameters, # d[v]/d[p] = w_i * (1. / sum(w_i)), where the sum is over the parameters. # Calculate this for all values v. inv_sw = 1. / sumweight dv_dp = row_multiply(weight, inv_sw) return value, dv_dp
def get_factors_and_derivatives(self, seq): """Calculate and return the smoothed values and their derivatives with respect to the underlying parameters for this scale factor component, for the reflections described by the values in seq. For example, these may be the phi rotation angle values for a scale factor component that is a function of phi.""" # Obtain data from the smoother, where value and sumweight are arrays with # the same length as seq. Weight is a sparse matrix with one row per # element of seq. Each row has some (typically 3) non-zero values # corresponding to the positions nearest the element of seq. value, weight, sumweight = self._smoother.multi_value_weight(seq, self._param) # The gradient of a single smoothed value with respect to the parameters, # d[v]/d[p] = w_i * (1. / sum(w_i)), where the sum is over the parameters. # Calculate this for all values v. inv_sw = 1. / sumweight dv_dp = row_multiply(weight, inv_sw) return value, dv_dp