def _get_points_within_radius(point, radius, radius_step=0.2, angle_step=pi / 5): """ Generates a list of points and their associated radius in steps around a sphere. Parameters ---------- point : tuple of float, float, float X, Y, Z, coordinates to center the sampling around. radius : float Max radius around the center to sample. radius_step : float, optional Steps along the radius to use when sampling. angle_step : float, optional Steps around each radii distance to use when sampling. Amount is in radians. Returns ------- list of tuple of float, float, float List of points to be sampled. list of float List of radii corresponding to each point. """ points = [point] radiuses = [0] for r in xfrange(radius_step, radius, radius_step): for theta in xfrange(-pi, pi, angle_step): for phi in xfrange(-pi, pi, angle_step): x = r * cos(theta) * sin(phi) + point[0] y = r * sin(theta) * sin(phi) + point[1] z = r * cos(phi) + point[2] points.append((x, y, z)) radiuses.append(r) return points, radiuses
def structure_factors(self, max_cycles=10): """P. van der Sluis and A. L. Spek, Acta Cryst. (1990). A46, 194-201.""" assert self.mask is not None if self.n_voids() == 0: return if self.use_set_completion: f_calc_set = self.complete_set else: f_calc_set = self.fo2.set() self.f_calc = f_calc_set.structure_factors_from_scatterers( self.xray_structure, algorithm="direct").f_calc() f_obs = self.f_obs() self.scale_factor = flex.sum(f_obs.data())/flex.sum( flex.abs(self.f_calc.data())) f_obs_minus_f_calc = f_obs.f_obs_minus_f_calc( 1/self.scale_factor, self.f_calc) self.fft_scale = self.xray_structure.unit_cell().volume()\ / self.crystal_gridding.n_grid_points() epsilon_for_min_residual = 2 for i in range(max_cycles): self.diff_map = miller.fft_map(self.crystal_gridding, f_obs_minus_f_calc) self.diff_map.apply_volume_scaling() stats = self.diff_map.statistics() masked_diff_map = self.diff_map.real_map_unpadded().set_selected( self.mask.data.as_double() == 0, 0) n_solvent_grid_points = self.n_solvent_grid_points() for j in range(self.n_voids()): # exclude voids with negative electron counts from the masked map # set the electron density in those areas to be zero selection = self.mask.data == j+2 if self.exclude_void_flags[j]: masked_diff_map.set_selected(selection, 0) continue diff_map_ = masked_diff_map.deep_copy().set_selected(~selection, 0) f_000 = flex.sum(diff_map_) * self.fft_scale f_000_s = f_000 * ( self.crystal_gridding.n_grid_points() / (self.crystal_gridding.n_grid_points() - n_solvent_grid_points)) if f_000_s < 0: masked_diff_map.set_selected(selection, 0) f_000_s = 0 self.exclude_void_flags[j] = True self.f_000 = flex.sum(masked_diff_map) * self.fft_scale f_000_s = self.f_000 * (masked_diff_map.size() / (masked_diff_map.size() - self.n_solvent_grid_points())) if (self.f_000_s is not None and approx_equal_relatively(self.f_000_s, f_000_s, 0.0001)): break # we have reached convergence else: self.f_000_s = f_000_s masked_diff_map.add_selected( self.mask.data.as_double() > 0, self.f_000_s/self.xray_structure.unit_cell().volume()) if 0: from crys3d import wx_map_viewer wx_map_viewer.display( title="masked diff_map", raw_map=masked_diff_map.as_double(), unit_cell=f_obs.unit_cell()) self._f_mask = f_obs.structure_factors_from_map(map=masked_diff_map) self._f_mask *= self.fft_scale scales = [] residuals = [] min_residual = 1000 for epsilon in xfrange(epsilon_for_min_residual, 0.9, -0.2): f_model_ = self.f_model(epsilon=epsilon) scale = flex.sum(f_obs.data())/flex.sum(flex.abs(f_model_.data())) residual = flex.sum(flex.abs( 1/scale * flex.abs(f_obs.data())- flex.abs(f_model_.data()))) \ / flex.sum(1/scale * flex.abs(f_obs.data())) scales.append(scale) residuals.append(residual) min_residual = min(min_residual, residual) if min_residual == residual: scale_for_min_residual = scale epsilon_for_min_residual = epsilon self.scale_factor = scale_for_min_residual f_model = self.f_model(epsilon=epsilon_for_min_residual) f_obs = self.f_obs() f_obs_minus_f_calc = f_obs.phase_transfer(f_model).f_obs_minus_f_calc( 1/self.scale_factor, self.f_calc) return self._f_mask
def structure_factors(self, max_cycles=10): """P. van der Sluis and A. L. Spek, Acta Cryst. (1990). A46, 194-201.""" assert self.mask is not None if self.n_voids() == 0: return if self.use_set_completion: f_calc_set = self.complete_set else: f_calc_set = self.fo2.set() self.f_calc = f_calc_set.structure_factors_from_scatterers(self.xray_structure, algorithm="direct").f_calc() f_obs = self.f_obs() self.scale_factor = flex.sum(f_obs.data()) / flex.sum(flex.abs(self.f_calc.data())) f_obs_minus_f_calc = f_obs.f_obs_minus_f_calc(1 / self.scale_factor, self.f_calc) self.fft_scale = self.xray_structure.unit_cell().volume() / self.crystal_gridding.n_grid_points() epsilon_for_min_residual = 2 for i in range(max_cycles): self.diff_map = miller.fft_map(self.crystal_gridding, f_obs_minus_f_calc) self.diff_map.apply_volume_scaling() stats = self.diff_map.statistics() masked_diff_map = self.diff_map.real_map_unpadded().set_selected(self.mask.data.as_double() == 0, 0) n_solvent_grid_points = self.n_solvent_grid_points() for j in range(self.n_voids()): # exclude voids with negative electron counts from the masked map # set the electron density in those areas to be zero selection = self.mask.data == j + 2 if self.exclude_void_flags[j]: masked_diff_map.set_selected(selection, 0) continue diff_map_ = masked_diff_map.deep_copy().set_selected(~selection, 0) f_000 = flex.sum(diff_map_) * self.fft_scale f_000_s = f_000 * ( self.crystal_gridding.n_grid_points() / (self.crystal_gridding.n_grid_points() - n_solvent_grid_points) ) if f_000_s < 0: masked_diff_map.set_selected(selection, 0) f_000_s = 0 self.exclude_void_flags[j] = True self.f_000 = flex.sum(masked_diff_map) * self.fft_scale f_000_s = self.f_000 * (masked_diff_map.size() / (masked_diff_map.size() - self.n_solvent_grid_points())) if self.f_000_s is not None and approx_equal_relatively(self.f_000_s, f_000_s, 0.0001): break # we have reached convergence else: self.f_000_s = f_000_s masked_diff_map.add_selected( self.mask.data.as_double() > 0, self.f_000_s / self.xray_structure.unit_cell().volume() ) if 0: from crys3d import wx_map_viewer wx_map_viewer.display( title="masked diff_map", raw_map=masked_diff_map.as_double(), unit_cell=f_obs.unit_cell() ) self._f_mask = f_obs.structure_factors_from_map(map=masked_diff_map) self._f_mask *= self.fft_scale scales = [] residuals = [] min_residual = 1000 for epsilon in xfrange(epsilon_for_min_residual, 0.9, -0.2): f_model_ = self.f_model(epsilon=epsilon) scale = flex.sum(f_obs.data()) / flex.sum(flex.abs(f_model_.data())) residual = flex.sum( flex.abs(1 / scale * flex.abs(f_obs.data()) - flex.abs(f_model_.data())) ) / flex.sum(1 / scale * flex.abs(f_obs.data())) scales.append(scale) residuals.append(residual) min_residual = min(min_residual, residual) if min_residual == residual: scale_for_min_residual = scale epsilon_for_min_residual = epsilon self.scale_factor = scale_for_min_residual f_model = self.f_model(epsilon=epsilon_for_min_residual) f_obs = self.f_obs() f_obs_minus_f_calc = f_obs.phase_transfer(f_model).f_obs_minus_f_calc(1 / self.scale_factor, self.f_calc) return self._f_mask
def __init__(self, fo2, fc, scale_factor=None, outlier_cutoff_factor=None, probability_plot_slope=None): self.probability_plot_slope = probability_plot_slope assert fo2.is_xray_intensity_array() assert fc.is_complex_array() assert not fo2.space_group().is_centric() if scale_factor is None: scale_factor = fo2.scale_factor(fc) fc2 = fc.as_intensity_array() self.delta_fc2 = fc2.anomalous_differences() self.delta_fo2 = fo2.anomalous_differences() self.n_bijvoet_pairs = self.delta_fo2.size() if outlier_cutoff_factor is not None: cutoff_sel = flex.abs(self.delta_fo2.data()) > ( outlier_cutoff_factor * scale_factor) * flex.max( flex.abs(self.delta_fc2.data())) self.delta_fo2 = self.delta_fo2.select(~cutoff_sel) self.delta_fc2 = self.delta_fc2.select(~cutoff_sel) self.delta_fc2 = self.delta_fc2.customized_copy( data=self.delta_fc2.data() * scale_factor) if not self.delta_fo2.size(): raise Sorry("Absolute structure could not be determined") min_gamma = -10 max_gamma = 10 # quick and dirty to find better min, max gammas max_log_p_obs = -1e100 while True: # search for the maximum width = max_gamma - min_gamma if width < 0.0001: break middle = (min_gamma + max_gamma)/2 a = middle - width/4 b = middle + width/4 value_a = self.log_p_obs_given_gamma(a) value_b = self.log_p_obs_given_gamma(b) if value_a > value_b: max_gamma = middle elif value_a == value_b: min_gamma = a max_gamma = b else: min_gamma = middle max_log_p_obs = max([max_log_p_obs, value_a, value_b]) while True: # search for where the curve becomes close to zero on the left min_gamma = middle - width/2 if (width > 100 or self.log_p_obs_given_gamma(min_gamma) - max_log_p_obs < -10): break width *= 2 width = max_gamma - min_gamma while True: # search for where the curve becomes close to zero on the right max_gamma = middle + width/2 if (width > 100 or self.log_p_obs_given_gamma(max_gamma) - max_log_p_obs < -10): break width *= 2 n_steps = 500 d_gamma = (max_gamma - min_gamma)/n_steps # now do it properly log_p_obs_given_gammas = flex.double() for gamma in xfrange(min_gamma, max_gamma, d_gamma): log_p_obs_given_gammas.append(self.log_p_obs_given_gamma(gamma)) max_log_p_obs = flex.max(log_p_obs_given_gammas) G_numerator = 0 G_denominator = 0 p_u_gammas = flex.double() # Numerical integration using trapezoidal rule for i, gamma in enumerate(xfrange(min_gamma, max_gamma, d_gamma)): p_u_gamma = math.exp(log_p_obs_given_gammas[i] - max_log_p_obs) p_u_gammas.append(p_u_gamma) if i == 0: continue G_numerator += 0.5 * d_gamma * ( (gamma-d_gamma) * p_u_gammas[-2] + gamma * p_u_gammas[-1]) G_denominator += 0.5 * (p_u_gammas[-2] + p_u_gammas[-1]) * d_gamma self.G = G_numerator/G_denominator sigma_squared_G_numerator = 0 # Numerical integration using trapezoidal rule next_ = None for i, gamma in enumerate(xfrange(min_gamma, max_gamma, d_gamma)): previous = next_ next_ = math.pow((gamma - self.G), 2) * p_u_gammas[i] * d_gamma if i == 0: continue sigma_squared_G_numerator += 0.5 * (previous + next_) self.hooft_y = (1-self.G)/2 self.sigma_G = math.sqrt(sigma_squared_G_numerator/G_denominator) self.sigma_y = self.sigma_G/2 # Now calculate P2, P3 values log_p_obs_given_gamma_is_minus_1 = self.log_p_obs_given_gamma(-1) log_p_obs_given_gamma_is_0 = self.log_p_obs_given_gamma(0) log_p_obs_given_gamma_is_1 = self.log_p_obs_given_gamma(1) max_log_p_obs = max([log_p_obs_given_gamma_is_minus_1, log_p_obs_given_gamma_is_0, log_p_obs_given_gamma_is_1]) # all values normalised by max_log_p_obs for numerical stability log_p_obs_given_gamma_is_minus_1 -= max_log_p_obs log_p_obs_given_gamma_is_0 -= max_log_p_obs log_p_obs_given_gamma_is_1 -= max_log_p_obs p2_denominator = math.exp(log_p_obs_given_gamma_is_1) \ + math.exp(log_p_obs_given_gamma_is_minus_1) p3_denominator = math.exp(log_p_obs_given_gamma_is_1) \ + math.exp(log_p_obs_given_gamma_is_minus_1) \ + math.exp(log_p_obs_given_gamma_is_0) # if p2_denominator == 0: self.p2_true = self.p2_false = None else: self.p2_true = ( math.exp(log_p_obs_given_gamma_is_1)) / p2_denominator self.p2_false = ( math.exp(log_p_obs_given_gamma_is_minus_1)) / p2_denominator self.p3_true = ( math.exp(log_p_obs_given_gamma_is_1)) / p3_denominator self.p3_false = ( math.exp(log_p_obs_given_gamma_is_minus_1)) / p3_denominator self.p3_racemic_twin = ( math.exp(log_p_obs_given_gamma_is_0)) / p3_denominator
def __init__(self, fo2, fc, scale_factor=None, outlier_cutoff_factor=None, probability_plot_slope=None): self.probability_plot_slope = probability_plot_slope assert fo2.is_xray_intensity_array() assert fc.is_complex_array() assert not fo2.space_group().is_centric() if scale_factor is None: scale_factor = fo2.scale_factor(fc) fc2 = fc.as_intensity_array() self.delta_fc2 = fc2.anomalous_differences() self.delta_fo2 = fo2.anomalous_differences() self.n_bijvoet_pairs = self.delta_fo2.size() if outlier_cutoff_factor is not None: cutoff_sel = flex.abs(self.delta_fo2.data()) > ( outlier_cutoff_factor * scale_factor) * flex.max( flex.abs(self.delta_fc2.data())) self.delta_fo2 = self.delta_fo2.select(~cutoff_sel) self.delta_fc2 = self.delta_fc2.select(~cutoff_sel) self.delta_fc2 = self.delta_fc2.customized_copy( data=self.delta_fc2.data() * scale_factor) if not self.delta_fo2.size(): raise Sorry("Absolute structure could not be determined") min_gamma = -10 max_gamma = 10 # quick and dirty to find better min, max gammas max_log_p_obs = -1e100 while True: # search for the maximum width = max_gamma - min_gamma if width < 0.0001: break middle = (min_gamma + max_gamma)/2 a = middle - width/4 b = middle + width/4 value_a = self.log_p_obs_given_gamma(a) value_b = self.log_p_obs_given_gamma(b) if value_a > value_b: max_gamma = middle elif value_a == value_b: min_gamma = a max_gamma = b else: min_gamma = middle max_log_p_obs = max([max_log_p_obs, value_a, value_b]) while True: # search for where the curve becomes close to zero on the left min_gamma = middle - width/2 if (width > 100 or self.log_p_obs_given_gamma(min_gamma) - max_log_p_obs < -10): break width *= 2 width = max_gamma - min_gamma while True: # search for where the curve becomes close to zero on the right max_gamma = middle + width/2 if (width > 100 or self.log_p_obs_given_gamma(max_gamma) - max_log_p_obs < -10): break width *= 2 n_steps = 500 d_gamma = (max_gamma - min_gamma)/n_steps # now do it properly log_p_obs_given_gammas = flex.double() for gamma in xfrange(min_gamma, max_gamma, d_gamma): log_p_obs_given_gammas.append(self.log_p_obs_given_gamma(gamma)) max_log_p_obs = flex.max(log_p_obs_given_gammas) G_numerator = 0 G_denominator = 0 p_u_gammas = flex.double() # Numerical integration using trapezoidal rule for i, gamma in enumerate(xfrange(min_gamma, max_gamma, d_gamma)): p_u_gamma = math.exp(log_p_obs_given_gammas[i] - max_log_p_obs) p_u_gammas.append(p_u_gamma) if i == 0: continue G_numerator += 0.5 * d_gamma * ( (gamma-d_gamma) * p_u_gammas[-2] + gamma * p_u_gammas[-1]) G_denominator += 0.5 * (p_u_gammas[-2] + p_u_gammas[-1]) * d_gamma self.G = G_numerator/G_denominator sigma_squared_G_numerator = 0 # Numerical integration using trapezoidal rule next = None for i, gamma in enumerate(xfrange(min_gamma, max_gamma, d_gamma)): previous = next next = math.pow((gamma - self.G), 2) * p_u_gammas[i] * d_gamma if i == 0: continue sigma_squared_G_numerator += 0.5 * (previous + next) self.hooft_y = (1-self.G)/2 self.sigma_G = math.sqrt(sigma_squared_G_numerator/G_denominator) self.sigma_y = self.sigma_G/2 # Now calculate P2, P3 values log_p_obs_given_gamma_is_minus_1 = self.log_p_obs_given_gamma(-1) log_p_obs_given_gamma_is_0 = self.log_p_obs_given_gamma(0) log_p_obs_given_gamma_is_1 = self.log_p_obs_given_gamma(1) max_log_p_obs = max([log_p_obs_given_gamma_is_minus_1, log_p_obs_given_gamma_is_0, log_p_obs_given_gamma_is_1]) # all values normalised by max_log_p_obs for numerical stability log_p_obs_given_gamma_is_minus_1 -= max_log_p_obs log_p_obs_given_gamma_is_0 -= max_log_p_obs log_p_obs_given_gamma_is_1 -= max_log_p_obs p2_denominator = math.exp(log_p_obs_given_gamma_is_1) \ + math.exp(log_p_obs_given_gamma_is_minus_1) p3_denominator = math.exp(log_p_obs_given_gamma_is_1) \ + math.exp(log_p_obs_given_gamma_is_minus_1) \ + math.exp(log_p_obs_given_gamma_is_0) # if p2_denominator == 0: self.p2_true = self.p2_false = None else: self.p2_true = ( math.exp(log_p_obs_given_gamma_is_1)) / p2_denominator self.p2_false = ( math.exp(log_p_obs_given_gamma_is_minus_1)) / p2_denominator self.p3_true = ( math.exp(log_p_obs_given_gamma_is_1)) / p3_denominator self.p3_false = ( math.exp(log_p_obs_given_gamma_is_minus_1)) / p3_denominator self.p3_racemic_twin = ( math.exp(log_p_obs_given_gamma_is_0)) / p3_denominator