def __call__(self, experiments, reflections, add_correction_column=False): result = flex.reflection_table() for expt_id, experiment in enumerate(experiments): refls = reflections.select(reflections['id'] == expt_id) beam = experiment.beam # Remove the need for pixel size within cxi.merge. Allows multipanel detector with dissimilar panels. # Relies on new frame extractor code called by dials.stills_process that writes s0, s1 and polarization normal # vectors all to the integration pickle. Future path (IE THIS CODE): use dials json and reflection file. s0_vec = matrix.col(beam.get_s0()).normalize() s0_polar_norm = beam.get_polarization_normal() s1_vec = refls['s1'] Ns1 = len(s1_vec) # project the s1_vector onto the plane normal to s0. Get result by subtracting the # projection of s1 onto s0, which is (s1.dot.s0_norm)s0_norm s0_norm = flex.vec3_double(Ns1,s0_vec) s1_proj = (s1_vec.dot(s0_norm))*s0_norm s1_in_normal_plane = s1_vec - s1_proj # Now want the polar angle between the projected s1 and the polarization normal s0_polar_norms = flex.vec3_double(Ns1,s0_polar_norm) dotprod = (s1_in_normal_plane.dot(s0_polar_norms)) costheta = dotprod/(s1_in_normal_plane.norms()) theta = flex.acos(costheta) cos_two_polar_angle = flex.cos(2.0*theta) # gives same as old answer to ~1% but not exact. Not sure why, should not matter. tt_vec = experiment.crystal.get_unit_cell().two_theta(miller_indices = refls['miller_index'], wavelength = beam.get_wavelength()) cos_tt_vec = flex.cos(tt_vec) sin_tt_vec = flex.sin(tt_vec) cos_sq_tt_vec = cos_tt_vec * cos_tt_vec sin_sq_tt_vec = sin_tt_vec * sin_tt_vec P_nought_vec = 0.5 * (1. + cos_sq_tt_vec) F_prime = -1.0 # Hard-coded value defines the incident polarization axis P_prime = 0.5 * F_prime * cos_two_polar_angle * sin_sq_tt_vec # added as a diagnostic #prange=P_nought_vec - P_prime #other_F_prime = 1.0 #otherP_prime = 0.5 * other_F_prime * cos_two_polar_angle * sin_sq_tt_vec #otherprange=P_nought_vec - otherP_prime #diff2 = flex.abs(prange - otherprange) #print >> out, "mean diff is",flex.mean(diff2), "range",flex.min(diff2), flex.max(diff2) # done correction = 1 / ( P_nought_vec - P_prime ) refls['intensity.sum.value'] = refls['intensity.sum.value'] * correction refls['intensity.sum.variance'] = refls['intensity.sum.variance'] * correction**2 # propagated error # This corrects observations for polarization assuming 100% polarization on # one axis (thus the F_prime = -1.0 rather than the perpendicular axis, 1.0) # Polarization model as described by Kahn, Fourme, Gadet, Janin, Dumas & Andre # (1982) J. Appl. Cryst. 15, 330-337, equations 13 - 15. if add_correction_column: refls['polarization_correction'] = correction result.extend(refls) return result
def test2(): """Test on simulated data""" # Get models for reflection prediction import dials.test.algorithms.refinement.setup_geometry as setup_geometry from libtbx.phil import parse overrides = """geometry.parameters.crystal.a.length.value = 77 geometry.parameters.crystal.b.length.value = 77 geometry.parameters.crystal.c.length.value = 37""" master_phil = parse( """ include scope dials.test.algorithms.refinement.geometry_phil """, process_includes=True, ) from dxtbx.model import Crystal models = setup_geometry.Extract(master_phil) crystal = Crystal( real_space_a=(2.62783398111729, -63.387215823567125, -45.751375737456975), real_space_b=(15.246640559660356, -44.48254330406616, 62.50501032727026), real_space_c=(-76.67246874451074, -11.01804131886244, 10.861322446352226), space_group_symbol="I 2 3", ) detector = models.detector goniometer = models.goniometer beam = models.beam # Build a mock scan for a 180 degree sweep from dxtbx.model import ScanFactory sf = ScanFactory() scan = sf.make_scan( image_range=(1, 1800), exposure_times=0.1, oscillation=(0, 0.1), epochs=range(1800), deg=True, ) # Build an experiment list from dxtbx.model.experiment_list import ExperimentList, Experiment experiments = ExperimentList() experiments.append( Experiment( beam=beam, detector=detector, goniometer=goniometer, scan=scan, crystal=crystal, imageset=None, )) # Generate all indices in a 1.5 Angstrom sphere from dials.algorithms.spot_prediction import IndexGenerator from cctbx.sgtbx import space_group, space_group_symbols resolution = 1.5 index_generator = IndexGenerator( crystal.get_unit_cell(), space_group(space_group_symbols(1).hall()).type(), resolution, ) indices = index_generator.to_array() # Predict rays within the sweep range from dials.algorithms.refinement.prediction import ScansRayPredictor sweep_range = scan.get_oscillation_range(deg=False) ray_predictor = ScansRayPredictor(experiments, sweep_range) obs_refs = ray_predictor(indices) # Take only those rays that intersect the detector from dials.algorithms.spot_prediction import ray_intersection intersects = ray_intersection(detector, obs_refs) obs_refs = obs_refs.select(intersects) # Make a reflection predictor and re-predict for all these reflections. The # result is the same, but we gain also the flags and xyzcal.px columns from dials.algorithms.refinement.prediction import ExperimentsPredictor ref_predictor = ExperimentsPredictor(experiments) obs_refs["id"] = flex.int(len(obs_refs), 0) obs_refs = ref_predictor(obs_refs) # Copy 'observed' centroids from the predicted ones, applying sinusoidal # offsets obs_x, obs_y, obs_z = obs_refs["xyzcal.mm"].parts() # obs_z is in range (0, pi). Calculate offsets for phi at twice that # frequency im_width = scan.get_oscillation(deg=False)[1] z_off = flex.sin(2 * obs_z) * im_width obs_z += z_off # Calculate offsets for x pixel_size = detector[0].get_pixel_size() x_off = flex.sin(20 * obs_z) * pixel_size[0] # Calculate offsets for y with a phase-shifted sine wave from math import pi y_off = flex.sin(4 * obs_z + pi / 6) * pixel_size[1] # Incorporate the offsets into the 'observed' centroids obs_z += z_off obs_x += x_off obs_y += y_off obs_refs["xyzobs.mm.value"] = flex.vec3_double(obs_x, obs_y, obs_z) # Now do centroid analysis of the residuals results = CentroidAnalyser(obs_refs, debug=True)() # FIXME this test shows that the suggested interval width heuristic is not # yet robust. This simulation function seems a useful direction to proceed # in though raise RuntimeError("test2 failed") print("OK") return
def plot_one_model(self, nrow, out): fig = plt.subplot(self.gs[nrow * self.ncols]) two_thetas = self.reduction.get_two_theta_deg() degrees = self.reduction.get_delta_psi_deg() if self.color_encoding == "conventional": positive = (self.reduction.i_sigi >= 0.) fig.plot(two_thetas.select(positive), degrees.select(positive), "bo") fig.plot(two_thetas.select(~positive), degrees.select(~positive), "r+") elif self.color_encoding == "I/sigma": positive = (self.reduction.i_sigi >= 0.) tt_selected = two_thetas.select(positive) dp_selected = degrees.select(positive) i_sigi_select = self.reduction.i_sigi.select(positive) order = flex.sort_permutation(i_sigi_select) tt_selected = tt_selected.select(order) dp_selected = dp_selected.select(order) i_sigi_selected = i_sigi_select.select(order) from matplotlib.colors import Normalize dnorm = Normalize() dcolors = i_sigi_selected.as_numpy_array() dnorm.autoscale(dcolors) N = len(dcolors) CMAP = plt.get_cmap("rainbow") if self.refined.get("partiality_array", None) is None: for n in xrange(N): fig.plot([tt_selected[n]], [dp_selected[n]], color=CMAP(dnorm(dcolors[n])), marker=".", markersize=10) else: partials = self.refined.get("partiality_array") partials_select = partials.select(positive) partials_selected = partials_select.select(order) assert len(partials) == len(positive) for n in xrange(N): fig.plot([tt_selected[n]], [dp_selected[n]], color=CMAP(dnorm(dcolors[n])), marker=".", markersize=20 * partials_selected[n]) # change the markersize to indicate partiality. negative = (self.reduction.i_sigi < 0.) fig.plot(two_thetas.select(negative), degrees.select(negative), "r+", linewidth=1) else: strong = (self.reduction.i_sigi >= 10.) positive = ((~strong) & (self.reduction.i_sigi >= 0.)) negative = (self.reduction.i_sigi < 0.) assert (strong.count(True) + positive.count(True) + negative.count(True) == len(self.reduction.i_sigi)) fig.plot(two_thetas.select(positive), degrees.select(positive), "bo") fig.plot(two_thetas.select(strong), degrees.select(strong), marker='.', linestyle='None', markerfacecolor='#00ee00', markersize=10) fig.plot(two_thetas.select(negative), degrees.select(negative), "r+") # indicate the imposed resolution filter wavelength = self.reduction.experiment.beam.get_wavelength() imposed_res_filter = self.reduction.get_imposed_res_filter(out) resolution_markers = [ a for a in [imposed_res_filter, self.reduction.measurements.d_min()] if a is not None ] for RM in resolution_markers: two_th = (180. / math.pi) * 2. * math.asin(wavelength / (2. * RM)) plt.plot([two_th, two_th], [self.AD1TF7B_MAXDP * -0.8, self.AD1TF7B_MAXDP * 0.8], 'k-') plt.text(two_th, self.AD1TF7B_MAXDP * -0.9, "%4.2f" % RM) #indicate the linefit mean = flex.mean(degrees) minplot = flex.min(two_thetas) plt.plot([0, minplot], [mean, mean], "k-") LR = flex.linear_regression(two_thetas, degrees) model_y = LR.slope() * two_thetas + LR.y_intercept() plt.plot(two_thetas, model_y, "k-") #Now let's take care of the red and green lines. half_mosaic_rotation_deg = self.refined["half_mosaic_rotation_deg"] mosaic_domain_size_ang = self.refined["mosaic_domain_size_ang"] red_curve_domain_size_ang = self.refined.get( "red_curve_domain_size_ang", mosaic_domain_size_ang) a_step = self.AD1TF7B_MAX2T / 50. a_range = flex.double([a_step * x for x in xrange(1, 50) ]) # domain two-theta array #Bragg law [d=L/2sinTH] d_spacing = (wavelength / (2. * flex.sin(math.pi * a_range / 360.))) # convert two_theta to a delta-psi. Formula for Deffective [Dpsi=d/2Deff] inner_phi_deg = flex.asin( (d_spacing / (2. * red_curve_domain_size_ang))) * (180. / math.pi) outer_phi_deg = flex.asin((d_spacing / (2.*mosaic_domain_size_ang)) + \ half_mosaic_rotation_deg*math.pi/180. )*(180./math.pi) plt.title("ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots\n%s" % (2. * half_mosaic_rotation_deg, mosaic_domain_size_ang, len(two_thetas), os.path.basename(self.reduction.filename))) plt.plot(a_range, inner_phi_deg, "r-") plt.plot(a_range, -inner_phi_deg, "r-") plt.plot(a_range, outer_phi_deg, "g-") plt.plot(a_range, -outer_phi_deg, "g-") plt.xlim([0, self.AD1TF7B_MAX2T]) plt.ylim([-self.AD1TF7B_MAXDP, self.AD1TF7B_MAXDP]) #second plot shows histogram fig = plt.subplot(self.gs[1 + nrow * self.ncols]) plt.xlim([-self.AD1TF7B_MAXDP, self.AD1TF7B_MAXDP]) nbins = 50 n, bins, patches = plt.hist( dp_selected, nbins, range=(-self.AD1TF7B_MAXDP, self.AD1TF7B_MAXDP), weights=self.reduction.i_sigi.select(positive), normed=0, facecolor="orange", alpha=0.75) #ersatz determine the median i_sigi point: isi_positive = self.reduction.i_sigi.select(positive) isi_order = flex.sort_permutation(isi_positive) reordered = isi_positive.select(isi_order) isi_median = reordered[int(len(isi_positive) * 0.9)] isi_top_half_selection = (isi_positive > isi_median) n, bins, patches = plt.hist( dp_selected.select(isi_top_half_selection), nbins, range=(-self.AD1TF7B_MAXDP, self.AD1TF7B_MAXDP), weights=isi_positive.select(isi_top_half_selection), normed=0, facecolor="#ff0000", alpha=0.75) plt.xlabel("(degrees)") plt.title("Weighted histogram of Delta-psi")
def compute_intensity_parameters(self): """ Create a new reflection table with all the derived parameters needed to apply corrections from RS postrefinement """ refls = self.scaler.ISIGI ct = self.scaler.crystal_table rx = flex.mat3_double() # crystal rotation around x ry = flex.mat3_double() # crystal rotation around y u = flex.mat3_double() # U matrix (orientation) b = flex.mat3_double() # B matrix (cell parameters) wavelength = flex.double() G = flex.double() # scaling gfactor B = flex.double() # wilson B factor s0 = flex.vec3_double() # beam vector deff = flex.double() # effective domain size eta = flex.double() # effective mosaic domain misorientation angle ex = col((1,0,0)) # crystal rotation x axis ey = col((0,1,0)) # crystal rotation y axis for i in xrange(len(ct)): # Need to copy crystal specific terms for each reflection. Equivalent to a JOIN in SQL. n_refl = ct['n_refl'][i] rx.extend(flex.mat3_double(n_refl, ex.axis_and_angle_as_r3_rotation_matrix(ct['thetax'][i]))) ry.extend(flex.mat3_double(n_refl, ey.axis_and_angle_as_r3_rotation_matrix(ct['thetay'][i]))) u.extend(flex.mat3_double(n_refl, ct['u_matrix'][i])) b.extend(flex.mat3_double(n_refl, ct['b_matrix'][i])) wavelength.extend(flex.double(n_refl, ct['wavelength'][i])) G.extend(flex.double(n_refl, ct['G'][i])) B.extend(flex.double(n_refl, ct['B'][i])) s0.extend(flex.vec3_double(n_refl, (0,0,-1)) * (1/ct['wavelength'][i])) deff.extend(flex.double(n_refl, ct['deff'][i])) eta.extend(flex.double(n_refl, ct['eta'][i])) iobs = refls['iobs'] h = refls['miller_index_original'].as_vec3_double() q = ry * rx * u * b * h # vector pointing from origin of reciprocal space to RLP qlen = q.norms() # length of q d = 1/q.norms() # resolution #rs = (1/deff)+(eta/(2*d)) # proper formulation of RS rs = 1/deff # assumes eta is zero rs_sq = rs*rs # square of rs s = (s0+q) # vector from center of Ewald sphere to RLP slen = s.norms() # length of s rh = slen-(1/wavelength) # distance from RLP to Ewald sphere p_n = rs_sq # numerator of partiality lorenzian expression p_d = (2. * (rh * rh)) + rs_sq # denominator of partiality lorenzian expression partiality = p_n/p_d theta = flex.asin(wavelength/(2*d)) epsilon = -8*B*(flex.sin(theta)/wavelength)**2 # exponential term in partiality eepsilon = flex.exp(epsilon) # e^epsilon D = partiality * G * eepsilon # denominator of partiality lorenzian expression thetah = flex.asin(wavelength/(2*d)) # reflecting angle sinthetah = flex.sin(thetah) er = sinthetah/wavelength # ratio term in epsilon # save all the columns r = flex.reflection_table() r['rx'] = rx r['ry'] = ry r['u'] = u r['b'] = b r['h'] = h r['q'] = q r['qlen'] = qlen r['D'] = D r['rs'] = rs r['eta'] = eta r['deff'] = deff r['d'] = d r['s'] = s r['slen'] = slen r['wavelength'] = wavelength r['p_n'] = p_n r['p_d'] = p_d r['partiality'] = partiality r['G'] = G r['B'] = B r['eepsilon'] = eepsilon r['thetah'] = thetah r['sinthetah'] = sinthetah r['er'] = er return r
def plot_one_model(self,nrow,out): fig = plt.subplot(self.gs[nrow*self.ncols]) two_thetas = self.reduction.get_two_theta_deg() degrees = self.reduction.get_delta_psi_deg() if self.color_encoding=="conventional": positive = (self.reduction.i_sigi>=0.) fig.plot(two_thetas.select(positive), degrees.select(positive), "bo") fig.plot(two_thetas.select(~positive), degrees.select(~positive), "r+") elif self.color_encoding=="I/sigma": positive = (self.reduction.i_sigi>=0.) tt_selected = two_thetas.select(positive) dp_selected = degrees.select(positive) i_sigi_select = self.reduction.i_sigi.select(positive) order = flex.sort_permutation(i_sigi_select) tt_selected = tt_selected.select(order) dp_selected = dp_selected.select(order) i_sigi_selected = i_sigi_select.select(order) from matplotlib.colors import Normalize dnorm = Normalize() dcolors = i_sigi_selected.as_numpy_array() dnorm.autoscale(dcolors) N = len(dcolors) CMAP = plt.get_cmap("rainbow") if self.refined.get("partiality_array",None) is None: for n in xrange(N): fig.plot([tt_selected[n]],[dp_selected[n]], color=CMAP(dnorm(dcolors[n])),marker=".", markersize=10) else: partials = self.refined.get("partiality_array") partials_select = partials.select(positive) partials_selected = partials_select.select(order) assert len(partials)==len(positive) for n in xrange(N): fig.plot([tt_selected[n]],[dp_selected[n]], color=CMAP(dnorm(dcolors[n])),marker=".", markersize=20*partials_selected[n]) # change the markersize to indicate partiality. negative = (self.reduction.i_sigi<0.) fig.plot(two_thetas.select(negative), degrees.select(negative), "r+", linewidth=1) else: strong = (self.reduction.i_sigi>=10.) positive = ((~strong) & (self.reduction.i_sigi>=0.)) negative = (self.reduction.i_sigi<0.) assert (strong.count(True)+positive.count(True)+negative.count(True) == len(self.reduction.i_sigi)) fig.plot(two_thetas.select(positive), degrees.select(positive), "bo") fig.plot(two_thetas.select(strong), degrees.select(strong), marker='.',linestyle='None', markerfacecolor='#00ee00', markersize=10) fig.plot(two_thetas.select(negative), degrees.select(negative), "r+") # indicate the imposed resolution filter wavelength = self.reduction.experiment.beam.get_wavelength() imposed_res_filter = self.reduction.get_imposed_res_filter(out) resolution_markers = [ a for a in [imposed_res_filter,self.reduction.measurements.d_min()] if a is not None] for RM in resolution_markers: two_th = (180./math.pi)*2.*math.asin(wavelength/(2.*RM)) plt.plot([two_th, two_th],[self.AD1TF7B_MAXDP*-0.8,self.AD1TF7B_MAXDP*0.8],'k-') plt.text(two_th,self.AD1TF7B_MAXDP*-0.9,"%4.2f"%RM) #indicate the linefit mean = flex.mean(degrees) minplot = flex.min(two_thetas) plt.plot([0,minplot],[mean,mean],"k-") LR = flex.linear_regression(two_thetas, degrees) model_y = LR.slope()*two_thetas + LR.y_intercept() plt.plot(two_thetas, model_y, "k-") #Now let's take care of the red and green lines. half_mosaic_rotation_deg = self.refined["half_mosaic_rotation_deg"] mosaic_domain_size_ang = self.refined["mosaic_domain_size_ang"] red_curve_domain_size_ang = self.refined.get("red_curve_domain_size_ang",mosaic_domain_size_ang) a_step = self.AD1TF7B_MAX2T / 50. a_range = flex.double([a_step*x for x in xrange(1,50)]) # domain two-theta array #Bragg law [d=L/2sinTH] d_spacing = (wavelength/(2.*flex.sin(math.pi*a_range/360.))) # convert two_theta to a delta-psi. Formula for Deffective [Dpsi=d/2Deff] inner_phi_deg = flex.asin((d_spacing / (2.*red_curve_domain_size_ang)) )*(180./math.pi) outer_phi_deg = flex.asin((d_spacing / (2.*mosaic_domain_size_ang)) + \ half_mosaic_rotation_deg*math.pi/180. )*(180./math.pi) plt.title("ML: mosaicity FW=%4.2f deg, Dsize=%5.0fA on %d spots\n%s"%( 2.*half_mosaic_rotation_deg, mosaic_domain_size_ang, len(two_thetas), os.path.basename(self.reduction.filename))) plt.plot(a_range, inner_phi_deg, "r-") plt.plot(a_range,-inner_phi_deg, "r-") plt.plot(a_range, outer_phi_deg, "g-") plt.plot(a_range, -outer_phi_deg, "g-") plt.xlim([0,self.AD1TF7B_MAX2T]) plt.ylim([-self.AD1TF7B_MAXDP,self.AD1TF7B_MAXDP]) #second plot shows histogram fig = plt.subplot(self.gs[1+nrow*self.ncols]) plt.xlim([-self.AD1TF7B_MAXDP,self.AD1TF7B_MAXDP]) nbins = 50 n,bins,patches = plt.hist(dp_selected, nbins, range=(-self.AD1TF7B_MAXDP,self.AD1TF7B_MAXDP), weights=self.reduction.i_sigi.select(positive), normed=0, facecolor="orange", alpha=0.75) #ersatz determine the median i_sigi point: isi_positive = self.reduction.i_sigi.select(positive) isi_order = flex.sort_permutation(isi_positive) reordered = isi_positive.select(isi_order) isi_median = reordered[int(len(isi_positive)*0.9)] isi_top_half_selection = (isi_positive>isi_median) n,bins,patches = plt.hist(dp_selected.select(isi_top_half_selection), nbins, range=(-self.AD1TF7B_MAXDP,self.AD1TF7B_MAXDP), weights=isi_positive.select(isi_top_half_selection), normed=0, facecolor="#ff0000", alpha=0.75) plt.xlabel("(degrees)") plt.title("Weighted histogram of Delta-psi")
def run(self, experiments, reflections): self.logger.log_step_time("POLARIZATION_CORRECTION") result = flex.reflection_table() for experiment in experiments: refls = reflections.select( reflections['exp_id'] == experiment.identifier) if len(refls) == 0: continue beam = experiment.beam # Remove the need for pixel size within cxi.merge. Allows multipanel detector with dissimilar panels. # Relies on new frame extractor code called by dials.stills_process that writes s0, s1 and polarization normal # vectors all to the integration pickle. Future path (IE THIS CODE): use dials json and reflection file. s0_vec = matrix.col(beam.get_s0()).normalize() s0_polar_norm = beam.get_polarization_normal() s1_vec = refls['s1'] Ns1 = len(s1_vec) # project the s1_vector onto the plane normal to s0. Get result by subtracting the # projection of s1 onto s0, which is (s1.dot.s0_norm)s0_norm s0_norm = flex.vec3_double(Ns1, s0_vec) s1_proj = (s1_vec.dot(s0_norm)) * s0_norm s1_in_normal_plane = s1_vec - s1_proj # Now want the polar angle between the projected s1 and the polarization normal s0_polar_norms = flex.vec3_double(Ns1, s0_polar_norm) dotprod = (s1_in_normal_plane.dot(s0_polar_norms)) costheta = dotprod / (s1_in_normal_plane.norms()) theta = flex.acos(costheta) cos_two_polar_angle = flex.cos(2.0 * theta) # gives same as old answer to ~1% but not exact. Not sure why, should not matter. tt_vec = experiment.crystal.get_unit_cell().two_theta( miller_indices=refls['miller_index'], wavelength=beam.get_wavelength()) cos_tt_vec = flex.cos(tt_vec) sin_tt_vec = flex.sin(tt_vec) cos_sq_tt_vec = cos_tt_vec * cos_tt_vec sin_sq_tt_vec = sin_tt_vec * sin_tt_vec P_nought_vec = 0.5 * (1. + cos_sq_tt_vec) F_prime = -1.0 # Hard-coded value defines the incident polarization axis P_prime = 0.5 * F_prime * cos_two_polar_angle * sin_sq_tt_vec # added as a diagnostic #prange=P_nought_vec - P_prime #other_F_prime = 1.0 #otherP_prime = 0.5 * other_F_prime * cos_two_polar_angle * sin_sq_tt_vec #otherprange=P_nought_vec - otherP_prime #diff2 = flex.abs(prange - otherprange) #print >> out, "mean diff is",flex.mean(diff2), "range",flex.min(diff2), flex.max(diff2) # done correction = 1 / (P_nought_vec - P_prime) refls['intensity.sum.value'] = refls[ 'intensity.sum.value'] * correction refls['intensity.sum.variance'] = refls[ 'intensity.sum.variance'] * correction**2 # propagated error # This corrects observations for polarization assuming 100% polarization on # one axis (thus the F_prime = -1.0 rather than the perpendicular axis, 1.0) # Polarization model as described by Kahn, Fourme, Gadet, Janin, Dumas & Andre # (1982) J. Appl. Cryst. 15, 330-337, equations 13 - 15. result.extend(refls) if len(reflections) > 0: self.logger.log( "Applied polarization correction. Mean intensity changed from %.2f to %.2f" % (flex.mean(reflections['intensity.sum.value']), flex.mean(result['intensity.sum.value']))) self.logger.log_step_time("POLARIZATION_CORRECTION", True) self.logger.log("Memory usage: %d MB" % get_memory_usage()) # Remove 's1' column from the reflection table from xfel.merging.application.reflection_table_utils import reflection_table_utils reflections = reflection_table_utils.prune_reflection_table_keys( reflections=result, keys_to_delete=['s1']) self.logger.log("Pruned reflection table") self.logger.log("Memory usage: %d MB" % get_memory_usage()) return experiments, reflections
def background(imageset, indx, n_bins, corrected=False, mask_params=None): if mask_params is None: # Default mask params for trusted range mask_params = phil_scope.fetch(parse("")).extract().masking detector = imageset.get_detector() beam = imageset.get_beam() # Only working with single panel detector for now assert len(detector) == 1 panel = detector[0] imageset_mask = imageset.get_mask(indx)[0] mask = dials.util.masking.generate_mask(imageset, mask_params)[0] mask = imageset_mask & mask n = matrix.col(panel.get_normal()).normalize() b = matrix.col(beam.get_s0()).normalize() wavelength = beam.get_wavelength() if math.fabs(b.dot(n)) < 0.95: raise Sorry("Detector not perpendicular to beam") # Use corrected data to determine signal and background regions corrected_data = imageset.get_corrected_data(indx) assert len(corrected_data) == 1 corrected_data = corrected_data[0].as_double() # Use choice of raw or corrected data to evaluate the background values if corrected: data = corrected_data else: data = imageset.get_raw_data(indx)[0].as_double() spot_params = spot_phil.fetch(source=parse("")).extract() threshold_function = SpotFinderFactory.configure_threshold(spot_params) peak_pixels = threshold_function.compute_threshold(corrected_data, mask) signal = data.select(peak_pixels.iselection()) background_pixels = mask & ~peak_pixels background = data.select(background_pixels.iselection()) # print some summary information print(f"Mean background: {flex.sum(background) / background.size():.3f}") if len(signal) > 0: print( f"Max/total signal pixels: {flex.max(signal):.0f} / {flex.sum(signal):.0f}" ) else: print("No signal pixels on this image") print("Peak/background/masked pixels: %d / %d / %d" % (peak_pixels.count(True), background.size(), mask.count(False))) # compute histogram of two-theta values, then same weighted # by pixel values, finally divide latter by former to get # the radial profile out, need to set the number of bins # sensibly; inspired by method in PyFAI two_theta_array = panel.get_two_theta_array(beam.get_s0()) two_theta_array = two_theta_array.as_1d().select( background_pixels.iselection()) # Use flex.weighted_histogram h0 = flex.weighted_histogram(two_theta_array, n_slots=n_bins) h1 = flex.weighted_histogram(two_theta_array, background, n_slots=n_bins) h2 = flex.weighted_histogram(two_theta_array, background * background, n_slots=n_bins) d0 = h0.slots() d1 = h1.slots() d2 = h2.slots() I = d1 / d0 I2 = d2 / d0 sig = flex.sqrt(I2 - flex.pow2(I)) tt = h0.slot_centers() d_spacings = wavelength / (2.0 * flex.sin(0.5 * tt)) return d_spacings, I, sig
def run(args): comm = MPI.COMM_WORLD rank = comm.Get_rank() # each process in MPI has a unique id, 0-indexed size = comm.Get_size() # size: number of processes running in this job if "-h" in args or "--help" in args: if rank == 0: print(help_str) return if rank == 0: from dxtbx.command_line.image_average import splitit filenames = [] for arg in sys.argv[1:]: filenames.extend(glob.glob(arg)) if not filenames: sys.exit("No data found") filenames = splitit(filenames, size) else: filenames = None filenames = comm.scatter(filenames, root=0) x, y = flex.double(), flex.double() det = None for fn in filenames: print(fn) try: refls = flex.reflection_table.from_file( fn.split('_strong.expt')[0] + "_strong.refl") except OSError: continue expts = ExperimentList.from_file(fn, check_format=False) for expt_id, expt in enumerate(expts): subset = refls.select(expt_id == refls['id']) if len(subset) > 200: continue det = expt.detector for panel_id, panel in enumerate(det): r = subset.select(subset['panel'] == panel_id) x_, y_, _ = r['xyzobs.px.value'].parts() pix = panel.pixel_to_millimeter(flex.vec2_double(x_, y_)) c = panel.get_lab_coord(pix) x.extend(c.parts()[0]) y.extend(c.parts()[1]) if det: z = flex.double(len(x), sum([p.get_origin()[2] for p in det]) / len(det)) coords = flex.vec3_double(x, y, z) two_theta = coords.angle((0, 0, -1)) d = expts[0].beam.get_wavelength() / 2 / flex.sin(two_theta / 2) azi = flex.vec3_double(x, y, flex.double(len(x), 0)).angle((0, 1, 0), deg=True) azi.set_selected(x < 0, 180 + (180 - azi.select(x < 0))) else: d = flex.double() azi = flex.double() if rank == 0: def saveit(): np.save(f, x.as_numpy_array()) np.save(f, y.as_numpy_array()) np.save(f, d.as_numpy_array()) np.save(f, azi.as_numpy_array()) import numpy as np with open('cake.npy', 'wb') as f: saveit() for i in range(1, size): print('waiting for', i) x, y, d, azi = comm.recv(source=i) saveit() else: print('rank', rank, 'sending') comm.send((x, y, d, azi), dest=0)