def __init__(SMG, goniometer): from scitbx.array_family import flex import math SMG.goniometer = goniometer coords = flex.vec3_double() axis = flex.size_t() # FACE A: Sample holder # Defined as semi-circle of radius r(A) = 10 mm (centred on PHI axis) # with rectangle of size a(A) = 12.8 mm (x 20 mm) offsetA = 33.0 # semi-circle for phi=-90 ... +90 radiusA = 10.0 phi = flex.double_range(-90, 100, step=10) * math.pi / 180 x = flex.double(phi.size(), -offsetA) y = radiusA * flex.cos(phi) z = radiusA * flex.sin(phi) # corners of square sqdA = 12.8 # square depth nsteps = 10 for i in range(nsteps + 1): for sign in (+1, -1): x.append(-offsetA) y.append(i * -sqdA / nsteps) z.append(sign * radiusA) x.append(-offsetA) y.append(-sqdA) z.append(0) SMG.faceA = flex.vec3_double(x, y, z) # FACE B: Lower arm sx = -28.50 sy = -4.90 sz = 8.50 mx = -13.80 my = -26.00 nx = -27.50 ny = -29.50 px = -65.50 py = -29.50 SMG.faceB = flex.vec3_double( ((sx, sy, sz), (mx, my, 0), (nx, ny, 0), (px, py, 0))) # FACE E: Rim of sample holder # Defined as circle of radius r(E) = 6 mm (centred on PHI axis) at an # offset o(E) = 19 mm offsetE = 19.0 radiusE = 6.0 phi = flex.double_range(0, 360, step=15) * math.pi / 180 x = flex.double(phi.size(), -offsetE) y = radiusE * flex.cos(phi) z = radiusE * flex.sin(phi) SMG.faceE = flex.vec3_double(x, y, z)
def __init__(self, goniometer): # FACE A: Sample holder # Defined as semi-circle of radius r(A) = 10 mm (centred on PHI axis) # with rectangle of size a(A) = 12.8 mm (x 20 mm) offsetA = 33.0 # semi-circle for phi=-90 ... +90 radiusA = 10.0 phi = flex.double_range(-90, 100, step=10) * math.pi / 180 x = flex.double(phi.size(), -offsetA) y = radiusA * flex.cos(phi) z = radiusA * flex.sin(phi) # corners of square sqdA = 12.8 # square depth nsteps = 10 for i in range(nsteps + 1): for sign in (+1, -1): x.append(-offsetA) y.append(i * -sqdA / nsteps) z.append(sign * radiusA) x.append(-offsetA) y.append(-sqdA) z.append(0) self.faceA = flex.vec3_double(-x, -y, z) # FACE B: Lower arm sx = -28.50 sy = -4.90 sz = 8.50 mx = -13.80 my = -26.00 nx = -27.50 ny = -29.50 px = -65.50 py = -29.50 self.faceB = flex.vec3_double( ((-sx, -sy, sz), (-mx, -my, 0), (-nx, -ny, 0), (-px, -py, 0)) ) # FACE E: Rim of sample holder # Defined as circle of radius r(E) = 6 mm (centred on PHI axis) at an # offset o(E) = 19 mm offsetE = 19.0 radiusE = 6.0 phi = flex.double_range(0, 360, step=15) * math.pi / 180 x = flex.double(phi.size(), -offsetE) y = radiusE * flex.cos(phi) z = radiusE * flex.sin(phi) self.faceE = flex.vec3_double(-x, -y, z) extrema_at_datum = self.faceA.deep_copy() extrema_at_datum.extend(self.faceE) super().__init__( goniometer, extrema_at_datum, flex.size_t(extrema_at_datum.size(), 1) )
def __init__(self, goniometer): from scitbx.array_family import flex import math self.goniometer = goniometer coords = flex.vec3_double() axis = flex.size_t() # FACE A: Sample holder # Defined as semi-circle of radius r(A) = 10 mm (centred on PHI axis) # with rectangle of size a(A) = 12.8 mm (x 20 mm) offsetA = 33.0 radiusA = 10.0 sqdA = 12.8 # square depth phi = flex.double_range(-90, 100, step=10) * math.pi / 180 x = flex.double(phi.size(), -offsetA) y = radiusA * flex.cos(phi) z = radiusA * flex.sin(phi) x.extend(flex.double(5, -offsetA)) y.extend(flex.double((-sqdA / 2, -sqdA, -sqdA, -sqdA, -sqdA / 2))) z.extend(flex.double((radiusA, radiusA, 0, -radiusA, -radiusA))) self.faceA = flex.vec3_double(x, y, z) # FACE B: Lower arm sx = -28.50 sy = -4.90 sz = 8.50 mx = -13.80 my = -26.00 nx = -27.50 ny = -29.50 px = -65.50 py = -29.50 self.faceB = flex.vec3_double( ((sx, sy, sz), (mx, my, 0), (nx, ny, 0), (px, py, 0))) # FACE E: Rim of sample holder # Defined as circle of radius r(E) = 6 mm (centred on PHI axis) at an # offset o(E) = 19 mm offsetE = 19.0 radiusE = 6.0 phi = flex.double_range(0, 360, step=15) * math.pi / 180 x = flex.double(phi.size(), -offsetE) y = radiusE * flex.cos(phi) z = radiusE * flex.sin(phi) self.faceE = flex.vec3_double(x, y, z)
def __init__(self, goniometer): from scitbx.array_family import flex import math self.goniometer = goniometer coords = flex.vec3_double() axis = flex.size_t() # FACE A: Sample holder # Defined as semi-circle of radius r(A) = 10 mm (centred on PHI axis) # with rectangle of size a(A) = 12.8 mm (x 20 mm) offsetA = 33.0 radiusA = 10.0 sqdA = 12.8 # square depth phi = flex.double_range(-90, 100, step=10) * math.pi/180 x = flex.double(phi.size(), -offsetA) y = radiusA * flex.cos(phi) z = radiusA * flex.sin(phi) x.extend(flex.double(5, -offsetA)) y.extend(flex.double((-sqdA/2, -sqdA, -sqdA, -sqdA, -sqdA/2))) z.extend(flex.double((radiusA, radiusA, 0, -radiusA, -radiusA))) self.faceA = flex.vec3_double(x, y, z) # FACE B: Lower arm sx = -28.50 sy = -4.90 sz = 8.50 mx = -13.80 my = -26.00 nx = -27.50 ny = -29.50 px = -65.50 py = -29.50 self.faceB = flex.vec3_double(((sx,sy,sz),(mx,my,0),(nx,ny,0),(px,py,0))) # FACE E: Rim of sample holder # Defined as circle of radius r(E) = 6 mm (centred on PHI axis) at an # offset o(E) = 19 mm offsetE = 19.0 radiusE = 6.0 phi = flex.double_range(0, 360, step=15) * math.pi/180 x = flex.double(phi.size(), -offsetE) y = radiusE * flex.cos(phi) z = radiusE * flex.sin(phi) self.faceE = flex.vec3_double(x, y, z)
def get_goniometer_shadow_masker(self, goniometer=None): if goniometer is None: goniometer = self.get_goniometer() from dials.util.masking import GoniometerShadowMaskGenerator from scitbx.array_family import flex import math # Simple model of cone around goniometer phi axis # Exact values don't matter, only the ratio of height/radius height = 10 # mm cone_opening_angle = 2 * 38 * math.pi / 180 radius_height_ratio = math.tan(1 / 2 * cone_opening_angle) radius = radius_height_ratio * height # print 2 * math.atan(radius/height) * 180 / math.pi steps_per_degree = 1 theta = (flex.double([range(360 * steps_per_degree)]) * math.pi / 180 * 1 / steps_per_degree) x = radius * flex.cos(theta) # x z = radius * flex.sin(theta) # y y = flex.double(theta.size(), height) # z coords = flex.vec3_double(zip(x, y, z)) coords.extend(flex.vec3_double(zip(x, -y, z))) coords.insert(0, (0, 0, 0)) if goniometer is None: goniometer = self.get_goniometer() return GoniometerShadowMaskGenerator(goniometer, coords, flex.size_t(len(coords), 0))
def _construct_shadow_masker(goniometer): if request.param == "cpp": return GoniometerMaskerFactory.mini_kappa(goniometer) # Simple model of cone around goniometer phi axis # Exact values don't matter, only the ratio of height/radius height = 50 # mm radius = 20 # mm steps_per_degree = 1 theta = ( flex.double(range(360 * steps_per_degree)) * math.pi / 180 * 1 / steps_per_degree ) y = radius * flex.cos(-theta) z = radius * flex.sin(-theta) x = flex.double(theta.size(), height) coords = flex.vec3_double(zip(x, y, z)) coords.insert(0, (0, 0, 0)) return PyGoniometerShadowMasker(goniometer, coords, flex.size_t(len(coords), 0))
def parts(self,fpp): dano_summation = None Ddanocalc_Dp = [] for j,idx in enumerate(self.scatterer_idx): bool_array = self.xray_structure.by_index_selection([idx]) xrs_atom = self.xray_structure.select(bool_array) #xrs_atom.show_scatterers() f_calc_atom = self.f_calc.structure_factors_from_scatterers( xray_structure=xrs_atom, algorithm=algorithm).f_calc() adata = f_calc_atom.data().parts()[0] bdata = f_calc_atom.data().parts()[1] product_factor = bdata * flex.cos(self.phases.data()) - adata * flex.sin(self.phases.data()) # correspnds to -b cos(alpha) + a sin(alpha) #print list(xrs_atom.scattering_types()) #xrs_atom.scattering_type_registry().show_summary() #xrs_atom.scattering_type_registry().show() f_zero = xrs_atom.scattering_type_registry().sum_of_scattering_factors_at_diffraction_angle_0() #print f_zero Ddanocalc_Dp.append((-2./f_zero)*product_factor) term = (-2.*fpp[j]/f_zero)*product_factor if dano_summation is None: dano_summation = term else: dano_summation += term return dano_summation,Ddanocalc_Dp """
def parts(self, fpp): dano_summation = None Ddanocalc_Dp = [] for j, idx in enumerate(self.scatterer_idx): bool_array = self.xray_structure.by_index_selection([idx]) xrs_atom = self.xray_structure.select(bool_array) #xrs_atom.show_scatterers() f_calc_atom = self.f_calc.structure_factors_from_scatterers( xray_structure=xrs_atom, algorithm=algorithm).f_calc() adata = f_calc_atom.data().parts()[0] bdata = f_calc_atom.data().parts()[1] product_factor = bdata * flex.cos( self.phases.data()) - adata * flex.sin(self.phases.data()) # correspnds to -b cos(alpha) + a sin(alpha) #print list(xrs_atom.scattering_types()) #xrs_atom.scattering_type_registry().show_summary() #xrs_atom.scattering_type_registry().show() f_zero = xrs_atom.scattering_type_registry( ).sum_of_scattering_factors_at_diffraction_angle_0() #print f_zero Ddanocalc_Dp.append((-2. / f_zero) * product_factor) term = (-2. * fpp[j] / f_zero) * product_factor if dano_summation is None: dano_summation = term else: dano_summation += term return dano_summation, Ddanocalc_Dp """
def circ_mean(t, deg=True): assert (len(t) > 0) from scitbx.array_family import flex if (deg): t = math.pi * (t / 180) sx = flex.sum(flex.cos(t)) / len(t) sy = flex.sum(flex.sin(t)) / len(t) return math.degrees(math.atan2(sy, sx))
def circ_mean (t, deg=True) : assert (len(t) > 0) from scitbx.array_family import flex if (deg) : t = math.pi * (t/180) sx = flex.sum(flex.cos(t)) / len(t) sy = flex.sum(flex.sin(t)) / len(t) return math.degrees(math.atan2(sy, sx))
def circ_len (t, deg=True) : assert (len(t) > 0) from scitbx.array_family import flex if (deg) : t = math.pi * (t/180) sx = flex.sum(flex.cos(t)) / len(t) sy = flex.sum(flex.sin(t)) / len(t) return math.sqrt(sx**2 + sy**2)
def circ_len(t, deg=True): assert (len(t) > 0) from scitbx.array_family import flex if (deg): t = math.pi * (t / 180) sx = flex.sum(flex.cos(t)) / len(t) sy = flex.sum(flex.sin(t)) / len(t) return math.sqrt(sx**2 + sy**2)
def __init__(self,working_phil): self.working_phil = working_phil self.two_theta_experimental = flex.double([ 1.5114,3.0160,4.5289,6.0422,7.5575,9.0733,10.5922,12.1106,13.6320,15.1563,16.6836,18.2107]) # first 12 orders of silver behenate rings reported by Huang (1993) J Appl Cryst 26, 180-184. copper_Kalpha = 1.5418 # Angstroms d = flex.double(len(self.two_theta_experimental), copper_Kalpha/2.) self.experimental_d = d/flex.sin((math.pi/360.)*self.two_theta_experimental)
def compute_functional_and_gradients(self, vector): assert len(vector) == 3 two_pi_S_dot_v = 2 * math.pi * self.reciprocal_lattice_points.dot(vector) f = -flex.sum(flex.cos(two_pi_S_dot_v)) sin_part = flex.sin(two_pi_S_dot_v) g = flex.double( [flex.sum(2 * math.pi * self._xyz_parts[i] * sin_part) for i in range(3)] ) return f, g
def __init__(self, working_phil): self.working_phil = working_phil self.two_theta_experimental = flex.double([ 1.5114, 3.0160, 4.5289, 6.0422, 7.5575, 9.0733, 10.5922, 12.1106, 13.6320, 15.1563, 16.6836, 18.2107 ]) # first 12 orders of silver behenate rings reported by Huang (1993) J Appl Cryst 26, 180-184. copper_Kalpha = 1.5418 # Angstroms d = flex.double(len(self.two_theta_experimental), copper_Kalpha / 2.) self.experimental_d = d / flex.sin( (math.pi / 360.) * self.two_theta_experimental)
def get_goniometer_shadow_masker(self, goniometer=None): if goniometer is None: goniometer = self.get_goniometer() assert goniometer is not None # avoid a module-level import from the DIALS namespace that kills LABELIT from dials.util.masking import GoniometerShadowMaskGenerator if goniometer.get_names()[1] == "GON_CHI": # SmarGon from dxtbx.format.SmarGonShadowMask import SmarGonShadowMaskGenerator return SmarGonShadowMaskGenerator(goniometer) elif goniometer.get_names()[1] == "GON_KAPPA": # mini Kappa from dials.util.masking import GoniometerShadowMaskGenerator from scitbx.array_family import flex # Simple model of cone around goniometer phi axis # Exact values don't matter, only the ratio of height/radius height = 50 # mm radius = 20 # mm steps_per_degree = 1 theta = ( flex.double([range(360 * steps_per_degree)]) * math.pi / 180 * 1 / steps_per_degree ) y = radius * flex.cos(theta) # x z = radius * flex.sin(theta) # y x = flex.double(theta.size(), height) # z coords = flex.vec3_double(zip(x, y, z)) coords.insert(0, (0, 0, 0)) return GoniometerShadowMaskGenerator( goniometer, coords, flex.size_t(len(coords), 0) ) else: raise RuntimeError( "Don't understand this goniometer: %s" % list(goniometer.get_names()) )
def diamond_anvil_cell(goniometer, cone_opening_angle): radius_height_ratio = math.tan(1 / 2 * cone_opening_angle) height = 10 # mm radius = radius_height_ratio * height steps_per_degree = 1 theta = (flex.double([list(range(360 * steps_per_degree))]) * math.pi / 180 * 1 / steps_per_degree) x = radius * flex.cos(theta) # x z = radius * flex.sin(theta) # y y = flex.double(theta.size(), height) # z coords = flex.vec3_double(zip(x, y, z)) coords.extend(flex.vec3_double(zip(x, -y, z))) coords.insert(0, (0, 0, 0)) return GoniometerShadowMasker(goniometer, coords, flex.size_t(len(coords), 0), True)
def tst_sphere(): bli = intensity.block_integrator(50.0, 0.1, 1.0, 0.001) q = flex.double(range(1, 300)) / 1000.0 bli.setup_arrays(q) r = flex.double(range(500)) / 500.0 r = r pr = 6.0 * r * r * (2 - 3.0 * r + r * r * r) r = r * 50 #for rr, pp in zip(r,pr): # print rr, pp iii = bli.get_intensity(pr) iii = iii / 25.0 jjj = (flex.sin(25.0 * q) - 25.0 * q * flex.cos(q * 25.0)) / (1e-12 + q * q * q * 25 * 25 * 25) jjj = jjj * jjj jjj = jjj / jjj[0] for q, i, j in zip(q, iii, jjj): assert (abs(i - j) < 1e-2)
def get_goniometer_shadow_masker(self, goniometer=None): from dials.util.masking import GoniometerShadowMaskGenerator from scitbx.array_family import flex import math # Simple model of cone around goniometer phi axis # Exact values don't matter, only the ratio of height/radius height = 50 # mm radius = 20 # mm steps_per_degree = 1 theta = flex.double([range(360*steps_per_degree)]) * math.pi/180 * 1/steps_per_degree y = radius * flex.cos(theta) # x z = radius * flex.sin(theta) # y x = flex.double(theta.size(), height) # z coords = flex.vec3_double(zip(x, y, z)) coords.insert(0, (0,0,0)) if goniometer is None: goniometer = self.get_goniometer() return GoniometerShadowMaskGenerator( goniometer, coords, flex.size_t(len(coords), 0))
def mini_kappa(goniometer, cone_opening_angle=43.60281897270362): """Construct a GoniometerShadowMasker for a mini-kappa goniometer. This is modelled a simple cone with the opening angle specified by `cone_opening_angle`. Args: goniometer (`dxtbx.model.Goniometer`): The goniometer instance. cone_opening_angle (float): The opening angle of the cone (in degrees). Returns: `dxtbx.masking.GoniometerShadowMasker` """ assert isinstance(goniometer, MultiAxisGoniometer) assert len(goniometer.get_axes()) == 3 # Simple model of cone around goniometer phi axis # Exact values don't matter, only the ratio of height/radius height = 50 # mm radius_height_ratio = math.tan(1 / 2 * cone_opening_angle * math.pi / 180) radius = radius_height_ratio * height steps_per_degree = 1 theta = (flex.double(range(360 * steps_per_degree)) * math.pi / 180 * 1 / steps_per_degree) y = radius * flex.cos(-theta) # x z = radius * flex.sin(-theta) # y x = flex.double(theta.size(), height) # z coords = flex.vec3_double(zip(x, y, z)) coords.insert(0, (0, 0, 0)) return GoniometerShadowMasker(goniometer, coords, flex.size_t(len(coords), 0))
def get_sinc(self, q, r): sinc = flex.sin(r * q) / (r * q) return sinc
def run(args, imageset=None): # Parse input try: len(args) except Exception: params = args else: user_phil = [] for arg in args: if "=" in arg: try: user_phil.append(libtbx.phil.parse(arg)) except RuntimeError as e: raise Sorry("Unrecognized argument '%s' (error: %s)" % (arg, str(e))) else: try: user_phil.append( libtbx.phil.parse("""file_path=%s""" % arg)) except ValueError: raise Sorry("Unrecognized argument '%s'" % arg) params = master_phil.fetch(sources=user_phil).extract() if imageset is None: if (params.file_path is None or len(params.file_path) == 0 or not all(os.path.isfile(f) for f in params.file_path)): master_phil.show() raise Usage( "file_path must be defined (either file_path=XXX, or the path alone)." ) assert params.n_bins is not None assert params.verbose is not None assert params.output_bins is not None # Allow writing to a file instead of stdout if params.output_file is None: logger = sys.stdout else: logger = open(params.output_file, "w") logger.write("%s " % params.output_file) if params.show_plots: from matplotlib import pyplot as plt colormap = plt.cm.gist_ncar plt.gca().set_color_cycle( [colormap(i) for i in np.linspace(0, 0.9, len(params.file_path))]) if params.mask is not None: params.mask = easy_pickle.load(params.mask) if imageset is None: iterable = params.file_path def load_func(x): try: obj = dxtbx.datablock.DataBlockFactory.from_filenames( [x])[0].extract_imagesets()[0] except IndexError: try: obj = dxtbx.datablock.DataBlockFactory.from_json_file( x)[0].extract_imagesets()[0] except dxtbx.datablock.InvalidDataBlockError: obj = ExperimentListFactory.from_json_file(x)[0].imageset return obj else: iterable = [imageset] def load_func(x): return x # Iterate over each file provided for item in iterable: iset = load_func(item) n_images = len(iset) if params.image_number is None: if params.max_images is None: subiterable = range(n_images) else: subiterable = range(0, min(params.max_images, n_images)) else: subiterable = [params.image_number] for image_number in subiterable: beam = iset.get_beam(image_number) detector = iset.get_detector(image_number) s0 = col(beam.get_s0()) # Search the detector for the panel farthest from the beam. The # number of bins in the radial average will be equal to the # farthest point from the beam on the detector, in pixels, unless # overridden at the command line panel_res = [p.get_max_resolution_at_corners(s0) for p in detector] farthest_panel = detector[panel_res.index(min(panel_res))] size2, size1 = farthest_panel.get_image_size() corners = [(0, 0), (size1 - 1, 0), (0, size2 - 1), (size1 - 1, size2 - 1)] corners_lab = [ col(farthest_panel.get_pixel_lab_coord(c)) for c in corners ] corner_two_thetas = [ farthest_panel.get_two_theta_at_pixel(s0, c) for c in corners ] extent_two_theta = max(corner_two_thetas) max_corner = corners_lab[corner_two_thetas.index(extent_two_theta)] extent = int( math.ceil(max_corner.length() * math.sin(extent_two_theta) / max(farthest_panel.get_pixel_size()))) extent_two_theta *= 180 / math.pi if params.n_bins < extent: params.n_bins = extent # These arrays will store the radial average info sums = flex.double(params.n_bins) * 0 sums_sq = flex.double(params.n_bins) * 0 counts = flex.int(params.n_bins) * 0 all_data = iset[image_number] if not isinstance(all_data, tuple): all_data = (all_data, ) for tile, (panel, data) in enumerate(zip(detector, all_data)): if params.panel is not None and tile != params.panel: continue if params.mask is None: mask = flex.bool(flex.grid(data.focus()), True) else: mask = params.mask[tile] if hasattr(data, "as_double"): data = data.as_double() logger.flush() if params.verbose: logger.write("Average intensity tile %d: %9.3f\n" % (tile, flex.mean(data))) logger.write("N bins: %d\n" % params.n_bins) logger.flush() x1, y1, x2, y2 = ( 0, 0, panel.get_image_size()[1], panel.get_image_size()[0], ) bc = panel.get_beam_centre_px(beam.get_s0()) bc = int(round(bc[1])), int(round(bc[0])) # compute the average radial_average( data, mask, bc, sums, sums_sq, counts, panel.get_pixel_size()[0], panel.get_distance(), (x1, y1), (x2, y2), ) # average the results, avoiding division by zero results = sums.set_selected(counts <= 0, 0) results /= counts.set_selected(counts <= 0, 1).as_double() if params.median_filter_size is not None: logger.write( "WARNING, the median filter is not fully propagated to the variances\n" ) from scipy.ndimage.filters import median_filter results = flex.double( median_filter(results.as_numpy_array(), size=params.median_filter_size)) # calculate standard devations stddev_sel = ((sums_sq - sums * results) >= 0) & (counts > 0) std_devs = flex.double(len(sums), 0) std_devs.set_selected( stddev_sel, (sums_sq.select(stddev_sel) - sums.select(stddev_sel) * results.select(stddev_sel)) / counts.select(stddev_sel).as_double(), ) std_devs = flex.sqrt(std_devs) twotheta = (flex.double(range(len(results))) * extent_two_theta / params.n_bins) q_vals = (4 * math.pi * flex.sin(math.pi * twotheta / 360) / beam.get_wavelength()) # nlmbda = 2dsin(theta) resolution = flex.double(len(twotheta), 0) nonzero = twotheta > 0 resolution.set_selected( nonzero, beam.get_wavelength() / (2 * flex.asin( (math.pi / 180) * twotheta.select(nonzero) / 2)), ) if params.low_max_two_theta_limit is None: subset = results else: subset = results.select( twotheta >= params.low_max_two_theta_limit) max_result = flex.max(subset) if params.x_axis == "two_theta": xvals = twotheta max_x = twotheta[flex.first_index(results, max_result)] elif params.x_axis == "q": xvals = q_vals max_x = q_vals[flex.first_index(results, max_result)] elif params.x_axis == "resolution": xvals = resolution max_x = resolution[flex.first_index(results, max_result)] for i, r in enumerate(results): val = xvals[i] if params.output_bins and "%.3f" % r != "nan": # logger.write("%9.3f %9.3f\n"% (val,r)) #.xy format for Rex.cell. logger.write( "%9.3f %9.3f %9.3f\n" % (val, r, std_devs[i])) # .xye format for GSASII # logger.write("%.3f %.3f %.3f\n"%(val,r,ds[i])) # include calculated d spacings logger.write("Maximum %s: %f, value: %f\n" % (params.x_axis, max_x, max_result)) if params.show_plots: if params.plot_x_max is not None: results = results.select(xvals <= params.plot_x_max) xvals = xvals.select(xvals <= params.plot_x_max) if params.normalize: plt.plot( xvals.as_numpy_array(), (results / flex.max(results)).as_numpy_array(), "-", ) else: plt.plot(xvals.as_numpy_array(), results.as_numpy_array(), "-") if params.x_axis == "two_theta": plt.xlabel("2 theta") elif params.x_axis == "q": plt.xlabel("q") elif params.x_axis == "resolution": plt.xlabel("Resolution ($\\AA$)") plt.gca().set_xscale("log") plt.gca().invert_xaxis() plt.xlim(0, 50) plt.ylabel("Avg ADUs") if params.plot_y_max is not None: plt.ylim(0, params.plot_y_max) if params.show_plots: # plt.legend([os.path.basename(os.path.splitext(f)[0]) for f in params.file_path], ncol=2) plt.show() return xvals, results
def background(imageset, indx, n_bins, mask_params=None): from dials.array_family import flex from libtbx.phil import parse from scitbx import matrix if mask_params is None: # Default mask params for trusted range mask_params = phil_scope.fetch(parse("")).extract().masking from dials.util.masking import MaskGenerator mask_generator = MaskGenerator(mask_params) mask = mask_generator.generate(imageset) detector = imageset.get_detector() beam = imageset.get_beam() # Only working with single panel detector for now assert len(detector) == 1 panel = detector[0] mask = mask[0] 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") data = imageset.get_raw_data(indx) assert len(data) == 1 data = data[0] data = data.as_double() spot_params = spot_phil.fetch(source=parse("")).extract() threshold_function = SpotFinderFactory.configure_threshold(spot_params) peak_pixels = threshold_function.compute_threshold(data, mask) signal = data.select(peak_pixels.iselection()) background_pixels = mask & ~peak_pixels background = data.select(background_pixels.iselection()) # print some summary information print("Mean background: %.3f" % (flex.sum(background) / background.size())) if len(signal) > 0: print("Max/total signal pixels: %.0f / %.0f" % (flex.max(signal), flex.sum(signal))) 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 get_goniometer_shadow_masker(self, goniometer=None): if goniometer is None: goniometer = self.get_goniometer() assert goniometer is not None #avoid a module-level import from the DIALS namespace that kills LABELIT from dials.util.masking import GoniometerShadowMaskGenerator if goniometer.get_names()[1] == 'GON_CHI': # SmarGon class SmarGonShadowMaskGenerator(GoniometerShadowMaskGenerator): def __init__(SMG, goniometer): from scitbx.array_family import flex import math SMG.goniometer = goniometer coords = flex.vec3_double() axis = flex.size_t() # FACE A: Sample holder # Defined as semi-circle of radius r(A) = 10 mm (centred on PHI axis) # with rectangle of size a(A) = 12.8 mm (x 20 mm) offsetA = 33.0 # semi-circle for phi=-90 ... +90 radiusA = 10.0 phi = flex.double_range(-90, 100, step=10) * math.pi / 180 x = flex.double(phi.size(), -offsetA) y = radiusA * flex.cos(phi) z = radiusA * flex.sin(phi) # corners of square sqdA = 12.8 # square depth nsteps = 10 for i in range(nsteps + 1): for sign in (+1, -1): x.append(-offsetA) y.append(i * -sqdA / nsteps) z.append(sign * radiusA) x.append(-offsetA) y.append(-sqdA) z.append(0) SMG.faceA = flex.vec3_double(x, y, z) # FACE B: Lower arm sx = -28.50 sy = -4.90 sz = 8.50 mx = -13.80 my = -26.00 nx = -27.50 ny = -29.50 px = -65.50 py = -29.50 SMG.faceB = flex.vec3_double( ((sx, sy, sz), (mx, my, 0), (nx, ny, 0), (px, py, 0))) # FACE E: Rim of sample holder # Defined as circle of radius r(E) = 6 mm (centred on PHI axis) at an # offset o(E) = 19 mm offsetE = 19.0 radiusE = 6.0 phi = flex.double_range(0, 360, step=15) * math.pi / 180 x = flex.double(phi.size(), -offsetE) y = radiusE * flex.cos(phi) z = radiusE * flex.sin(phi) SMG.faceE = flex.vec3_double(x, y, z) def extrema_at_scan_angle(SMG, scan_angle): from scitbx.array_family import flex # Align end station coordinate system with ImgCIF coordinate system from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame from scitbx import matrix R = align_reference_frame(matrix.col((-1, 0, 0)), matrix.col((1, 0, 0)), matrix.col((0, -1, 0)), matrix.col((0, 1, 0))) faceA = R.elems * SMG.faceA faceE = R.elems * SMG.faceE axes = SMG.goniometer.get_axes() angles = SMG.goniometer.get_angles() scan_axis = SMG.goniometer.get_scan_axis() angles[scan_axis] = scan_angle extrema = flex.vec3_double() for coords in (faceA, faceE): coords = coords.deep_copy() for i, axis in enumerate(axes): if i == 0: continue # shadow doesn't change with phi setting sel = flex.bool(len(coords), True) rotation = matrix.col( axis).axis_and_angle_as_r3_rotation_matrix( angles[i], deg=True) coords.set_selected( sel, rotation.elems * coords.select(sel)) extrema.extend(coords) s = matrix.col(SMG.faceB[0]) mx, my, _ = SMG.faceB[1] nx, ny, _ = SMG.faceB[2] px, py, _ = SMG.faceB[3] Rchi = (R.inverse() * matrix.col(axes[1]) ).axis_and_angle_as_r3_rotation_matrix(angles[1], deg=True) sk = Rchi * s sxk, syk, szk = sk.elems coords = flex.vec3_double(( (sxk, syk, 0), (sxk, syk, szk), (sxk + mx / 2, syk + my / 2, szk), (sxk + mx, syk + my, szk), (sxk + (mx + nx) / 2, syk + (my + ny) / 2, szk), (sxk + nx, syk + ny, szk), (sxk + (nx + px) / 2, syk + (ny + py) / 2, szk), (sxk + px, syk + py, szk), (sxk + px, syk + py, 0), (sxk + px, syk + py, -szk), (sxk + (nx + px) / 2, syk + (ny + py) / 2, -szk), (sxk + nx, syk + ny, -szk), (sxk + (mx + nx) / 2, syk + (my + ny) / 2, -szk), (sxk + mx, syk + my, -szk), (sxk + mx / 2, syk + my / 2, -szk), (sxk, syk, -szk), )) coords = R.elems * coords Romega = matrix.col( axes[2]).axis_and_angle_as_r3_rotation_matrix( angles[2], deg=True) coords = Romega.elems * coords extrema.extend(coords) return extrema #------------------ finished defining SmarGonShadowMaskGenerator return SmarGonShadowMaskGenerator(goniometer) elif goniometer.get_names()[1] == 'GON_KAPPA': # mini Kappa from dials.util.masking import GoniometerShadowMaskGenerator from scitbx.array_family import flex import math # Simple model of cone around goniometer phi axis # Exact values don't matter, only the ratio of height/radius height = 50 # mm radius = 20 # mm steps_per_degree = 1 theta = flex.double([range(360 * steps_per_degree) ]) * math.pi / 180 * 1 / steps_per_degree y = radius * flex.cos(theta) # x z = radius * flex.sin(theta) # y x = flex.double(theta.size(), height) # z coords = flex.vec3_double(zip(x, y, z)) coords.insert(0, (0, 0, 0)) if goniometer is None: goniometer = self.get_goniometer() return GoniometerShadowMaskGenerator(goniometer, coords, flex.size_t(len(coords), 0)) else: raise RuntimeError("Don't understand this goniometer: %s" % list(goniometer.get_names()))
def sphere_data(q, d_max): r=d_max/2.0 a = r*r*r*( flex.sin(q*r)-q*r*flex.cos(q*r) )/( r*r*r*q*q*q ) return a*a
def get_goniometer_shadow_masker(self, goniometer=None): from dials.util.masking import GoniometerShadowMaskGenerator from scitbx.array_family import flex import math coords = flex.vec3_double(((0, 0, 0), )) alpha = flex.double_range(0, 190, step=10) * math.pi / 180 r = flex.double(alpha.size(), 40) x = flex.double(r.size(), 107.61) y = -r * flex.sin(alpha) z = -r * flex.cos(alpha) coords.extend(flex.vec3_double(x, y, z)) coords.extend( flex.vec3_double(( # fixed (107.49, 7.84, 39.49), (107.39, 15.69, 38.97), (107.27, 23.53, 38.46), (107.16, 31.37, 37.94), (101.76, 33.99, 36.25), (96.37, 36.63, 34.56), (90.98, 39.25, 33.00), (85.58, 41.88, 31.18), (80.89, 47.06, 31.00), (76.55, 51.51, 31.03), (72.90, 55.04, 31.18), (66.86, 60.46, 31.67), (62.10, 64.41, 32.25), ))) alpha = flex.double_range(180, 370, step=10) * math.pi / 180 r = flex.double(alpha.size(), 33) x = (flex.sqrt(flex.pow2(r * flex.sin(alpha)) + 89.02**2) * flex.cos((50 * math.pi / 180) - flex.atan(r / 89.02 * flex.sin(alpha)))) y = (flex.sqrt(flex.pow2(r * flex.sin(alpha)) + 89.02**2) * flex.sin((50 * math.pi / 180) - flex.atan(r / 89.02 * flex.sin(alpha)))) z = -r * flex.cos(alpha) coords.extend(flex.vec3_double(x, y, z)) coords.extend( flex.vec3_double(( # fixed (62.10, 64.41, -32.25), (66.86, 60.46, -31.67), (72.90, 55.04, -31.18), (76.55, 51.51, -31.03), (80.89, 47.06, -31.00), (85.58, 41.88, -31.18), (90.98, 39.25, -33.00), (96.37, 36.63, -34.56), (101.76, 33.99, -36.25), (107.16, 31.37, -37.94), (107.27, 23.53, -38.46), (107.39, 15.69, -38.97), (107.49, 7.84, -39.49), (107.61, 0.00, -40.00)))) # I23 end station coordinate system: # X-axis: positive direction is facing away from the storage ring (from # sample towards goniometer) # Y-axis: positive direction is vertically up # Z-axis: positive direction is in the direction of the beam (from # sample towards detector) # K-axis (kappa): at an angle of +50 degrees from the X-axis # K & phi rotation axes: clockwise rotation is positive (right hand # thumb rule) # Omega-axis: along the X-axis; clockwise rotation is positive # End station x-axis is parallel to ImgCIF x-axis # End station z-axis points in opposite direction to ImgCIF definition # (ImgCIF: The Z-axis is derived from the source axis which goes from # the sample to the source) # Consequently end station y-axis (to complete set following right hand # rule) points in opposite direction to ImgCIF y-axis. # Kappa arm aligned with -y in ImgCIF convention from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame from scitbx import matrix R = align_reference_frame(matrix.col((1, 0, 0)), matrix.col((1, 0, 0)), matrix.col((0, 1, 0)), matrix.col( (0, -1, 0))) coords = R.elems * coords if goniometer is None: goniometer = self.get_goniometer() return GoniometerShadowMaskGenerator(goniometer, coords, flex.size_t(len(coords), 1))
def get_sinc(self, q, x): r = 0.5 * (x + 1) * self.d_max sinc = flex.sin(r * q) / (r * q) return sinc
def example(): x_obs = (flex.double(range(100)) + 1.0) / 101.0 y_ideal = flex.sin(x_obs * 6.0 * 3.1415) + flex.exp(x_obs) y_obs = y_ideal + (flex.random_double(size=x_obs.size()) - 0.5) * 0.5 w_obs = flex.double(x_obs.size(), 1) print "Trying to determine the best number of terms " print " via cross validation techniques" print n_terms = chebyshev_lsq_fit.cross_validate_to_determine_number_of_terms( x_obs, y_obs, w_obs, min_terms=5, max_terms=20, n_goes=20, n_free=20) print "Fitting with", n_terms, "terms" print fit = chebyshev_lsq_fit.chebyshev_lsq_fit(n_terms, x_obs, y_obs) print "Least Squares residual: %7.6f" % (fit.f) print " R2-value : %7.6f" % (fit.f / flex.sum(y_obs * y_obs)) print fit_funct = chebyshev_polynome(n_terms, fit.low_limit, fit.high_limit, fit.coefs) y_fitted = fit_funct.f(x_obs) abs_deviation = flex.max(flex.abs((y_ideal - y_fitted))) print "Maximum deviation between fitted and error free data:" print " %4.3f" % (abs_deviation) abs_deviation = flex.mean(flex.abs((y_ideal - y_fitted))) print "Mean deviation between fitted and error free data:" print " %4.3f" % (abs_deviation) print abs_deviation = flex.max(flex.abs((y_obs - y_fitted))) print "Maximum deviation between fitted and observed data:" print " %4.3f" % (abs_deviation) abs_deviation = flex.mean(flex.abs((y_obs - y_fitted))) print "Mean deviation between fitted and observed data:" print " %4.3f" % (abs_deviation) print print "Showing 10 points" print " x y_obs y_ideal y_fit" for ii in range(10): print "%6.3f %6.3f %6.3f %6.3f" \ %(x_obs[ii*9], y_obs[ii*9], y_ideal[ii*9], y_fitted[ii*9]) try: from iotbx import data_plots except ImportError: pass else: print "Preparing output for loggraph in a file called" print " chebyshev.loggraph" chebyshev_plot = data_plots.plot_data(plot_title='Chebyshev fitting', x_label='x values', y_label='y values', x_data=x_obs, y_data=y_obs, y_legend='Observed y values', comments='Chebyshev fit') chebyshev_plot.add_data(y_data=y_ideal, y_legend='Error free y values') chebyshev_plot.add_data(y_data=y_fitted, y_legend='Fitted chebyshev approximation') output_logfile = open('chebyshev.loggraph', 'w') f = StringIO() data_plots.plot_data_loggraph(chebyshev_plot, f) output_logfile.write(f.getvalue())
def background(imageset, indx, n_bins): from dials.array_family import flex from libtbx.phil import parse from scitbx import matrix import math detector = imageset.get_detector() beam = imageset.get_beam() assert(len(detector) == 1) detector = detector[0] trusted = detector.get_trusted_range() n = matrix.col(detector.get_normal()).normalize() b = matrix.col(beam.get_s0()).normalize() wavelength = beam.get_wavelength() if math.fabs(b.dot(n)) < 0.95: from libtbx.utils import Sorry raise Sorry('Detector not perpendicular to beam') data = imageset.get_raw_data(indx) assert(len(data) == 1) data = data[0] negative = (data < 0) hot = (data > int(round(trusted[1]))) bad = negative | hot from dials.algorithms.spot_finding.factory import SpotFinderFactory from dials.algorithms.spot_finding.factory import phil_scope data = data.as_double() from dxtbx import datablock spot_params = phil_scope.fetch(source=parse("")).extract() threshold_function = SpotFinderFactory.configure_threshold( spot_params, datablock.DataBlock([imageset])) peak_pixels = threshold_function.compute_threshold(data, ~bad) signal = data.select(peak_pixels.iselection()) background = data.select((~bad & ~peak_pixels).iselection()) # print some summary information print('Mean background: %.3f' % (flex.sum(background) / background.size())) print('Max/total signal pixels: %.0f / %.0f' % (flex.max(signal), flex.sum(signal))) print('Peak/background/hot pixels: %d / %d / %d' % (peak_pixels.count(True), background.size(), hot.count(True))) # 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; flex.histogram does not allow weights so use # numpy.histogram to get the same effect... inspired by # method in PyFAI data = data.as_1d() two_theta_array = detector.get_two_theta_array(beam.get_s0()) two_theta_array.set_selected((bad | peak_pixels).iselection(), 0.0) data.set_selected((bad | peak_pixels).iselection(), 0.0) # new fangled flex.weighted_histogram :-) h0 = flex.weighted_histogram(two_theta_array, n_slots=n_bins) h1 = flex.weighted_histogram(two_theta_array, data, n_slots=n_bins) h2 = flex.weighted_histogram(two_theta_array, data * data, 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 example(): x_obs = (flex.double(range(100))+1.0)/101.0 y_ideal = flex.sin(x_obs*6.0*3.1415) + flex.exp(x_obs) y_obs = y_ideal + (flex.random_double(size=x_obs.size())-0.5)*0.5 w_obs = flex.double(x_obs.size(),1) print "Trying to determine the best number of terms " print " via cross validation techniques" print n_terms = chebyshev_lsq_fit.cross_validate_to_determine_number_of_terms( x_obs,y_obs,w_obs, min_terms=5 ,max_terms=20, n_goes=20,n_free=20) print "Fitting with", n_terms, "terms" print fit = chebyshev_lsq_fit.chebyshev_lsq_fit(n_terms,x_obs,y_obs) print "Least Squares residual: %7.6f" %(fit.f) print " R2-value : %7.6f" %(fit.f/flex.sum(y_obs*y_obs)) print fit_funct = chebyshev_polynome( n_terms, fit.low_limit, fit.high_limit, fit.coefs) y_fitted = fit_funct.f(x_obs) abs_deviation = flex.max( flex.abs( (y_ideal- y_fitted) ) ) print "Maximum deviation between fitted and error free data:" print " %4.3f" %(abs_deviation) abs_deviation = flex.mean( flex.abs( (y_ideal- y_fitted) ) ) print "Mean deviation between fitted and error free data:" print " %4.3f" %(abs_deviation) print abs_deviation = flex.max( flex.abs( (y_obs- y_fitted) ) ) print "Maximum deviation between fitted and observed data:" print " %4.3f" %(abs_deviation) abs_deviation = flex.mean( flex.abs( (y_obs- y_fitted) ) ) print "Mean deviation between fitted and observed data:" print " %4.3f" %(abs_deviation) print print "Showing 10 points" print " x y_obs y_ideal y_fit" for ii in range(10): print "%6.3f %6.3f %6.3f %6.3f" \ %(x_obs[ii*9], y_obs[ii*9], y_ideal[ii*9], y_fitted[ii*9]) try: from iotbx import data_plots except ImportError: pass else: print "Preparing output for loggraph in a file called" print " chebyshev.loggraph" chebyshev_plot = data_plots.plot_data(plot_title='Chebyshev fitting', x_label = 'x values', y_label = 'y values', x_data = x_obs, y_data = y_obs, y_legend = 'Observed y values', comments = 'Chebyshev fit') chebyshev_plot.add_data(y_data=y_ideal, y_legend='Error free y values') chebyshev_plot.add_data(y_data=y_fitted, y_legend='Fitted chebyshev approximation') output_logfile=open('chebyshev.loggraph','w') f = StringIO() data_plots.plot_data_loggraph(chebyshev_plot,f) output_logfile.write(f.getvalue())
def get_sinc(self, q, x ): r = 0.5*(x+1)*self.d_max sinc = flex.sin( r*q )/(r*q) return sinc
def background(imageset, indx, n_bins): from dials.array_family import flex from libtbx.phil import parse from scitbx import matrix import math detector = imageset.get_detector() beam = imageset.get_beam() assert(len(detector) == 1) detector = detector[0] trusted = detector.get_trusted_range() n = matrix.col(detector.get_normal()).normalize() b = matrix.col(beam.get_s0()).normalize() wavelength = beam.get_wavelength() if math.fabs(b.dot(n)) < 0.95: from libtbx.utils import Sorry raise Sorry('Detector not perpendicular to beam') data = imageset.get_raw_data(indx) assert(len(data) == 1) data = data[0] negative = (data < 0) hot = (data > int(round(trusted[1]))) bad = negative | hot from dials.algorithms.spot_finding.factory import SpotFinderFactory from dials.algorithms.spot_finding.factory import phil_scope data = data.as_double() from dxtbx import datablock spot_params = phil_scope.fetch(source=parse("")).extract() threshold_function = SpotFinderFactory.configure_threshold( spot_params, datablock.DataBlock([imageset])) peak_pixels = threshold_function.compute_threshold(data, ~bad) signal = data.select(peak_pixels.iselection()) background = data.select((~bad & ~peak_pixels).iselection()) # print some summary information print 'Mean background: %.3f' % (flex.sum(background) / background.size()) print 'Max/total signal pixels: %.0f / %.0f' % (flex.max(signal), flex.sum(signal)) print 'Peak/background/hot pixels: %d / %d / %d' % (peak_pixels.count(True), background.size(), hot.count(True)) # 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; flex.histogram does not allow weights so use # numpy.histogram to get the same effect... inspired by # method in PyFAI data = data.as_1d() two_theta_array = detector.get_two_theta_array(beam.get_s0()) two_theta_array.set_selected((bad | peak_pixels).iselection(), 0.0) data.set_selected((bad | peak_pixels).iselection(), 0.0) # new fangled flex.weighted_histogram :-) h0 = flex.weighted_histogram(two_theta_array, n_slots=n_bins) h1 = flex.weighted_histogram(two_theta_array, data, n_slots=n_bins) h2 = flex.weighted_histogram(two_theta_array, data * data, 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, image = None): from xfel import radial_average from scitbx.array_family import flex import os, sys import dxtbx # Parse input try: n = len(args) except Exception: params = args else: user_phil = [] for arg in args: if (not "=" in arg): try : user_phil.append(libtbx.phil.parse("""file_path=%s""" % arg)) except ValueError: raise Sorry("Unrecognized argument '%s'" % arg) else: try: user_phil.append(libtbx.phil.parse(arg)) except RuntimeError as e: raise Sorry("Unrecognized argument '%s' (error: %s)" % (arg, str(e))) params = master_phil.fetch(sources=user_phil).extract() if image is None: if params.file_path is None or len(params.file_path) == 0 or not all([os.path.isfile(f) for f in params.file_path]): master_phil.show() raise Usage("file_path must be defined (either file_path=XXX, or the path alone).") assert params.n_bins is not None assert params.verbose is not None assert params.output_bins is not None # Allow writing to a file instead of stdout if params.output_file is None: logger = sys.stdout else: logger = open(params.output_file, 'w') logger.write("%s "%params.output_file) if params.show_plots: from matplotlib import pyplot as plt import numpy as np colormap = plt.cm.gist_ncar plt.gca().set_color_cycle([colormap(i) for i in np.linspace(0, 0.9, len(params.file_path))]) if params.mask is not None: params.mask = easy_pickle.load(params.mask) if image is None: iterable = params.file_path load_func = lambda x: dxtbx.load(x) else: iterable = [image] load_func = lambda x: x # Iterate over each file provided for item in iterable: img = load_func(item) try: n_images = img.get_num_images() subiterable = xrange(n_images) except AttributeError: n_images = None subiterable = [0] for image_number in subiterable: if n_images is None: beam = img.get_beam() detector = img.get_detector() else: beam = img.get_beam(image_number) detector = img.get_detector(image_number) s0 = col(beam.get_s0()) # Search the detector for the panel farthest from the beam. The number of bins in the radial average will be # equal to the farthest point from the beam on the detector, in pixels, unless overridden at the command line panel_res = [p.get_max_resolution_at_corners(s0) for p in detector] farthest_panel = detector[panel_res.index(min(panel_res))] size2, size1 = farthest_panel.get_image_size() corners = [(0,0), (size1-1,0), (0,size2-1), (size1-1,size2-1)] corners_lab = [col(farthest_panel.get_pixel_lab_coord(c)) for c in corners] corner_two_thetas = [farthest_panel.get_two_theta_at_pixel(s0, c) for c in corners] extent_two_theta = max(corner_two_thetas) max_corner = corners_lab[corner_two_thetas.index(extent_two_theta)] extent = int(math.ceil(max_corner.length()*math.sin(extent_two_theta)/max(farthest_panel.get_pixel_size()))) extent_two_theta *= 180/math.pi if params.n_bins < extent: params.n_bins = extent # These arrays will store the radial average info sums = flex.double(params.n_bins) * 0 sums_sq = flex.double(params.n_bins) * 0 counts = flex.int(params.n_bins) * 0 if n_images is None: all_data = img.get_raw_data() else: all_data = img.get_raw_data(image_number) if not isinstance(all_data, tuple): all_data = (all_data,) for tile, (panel, data) in enumerate(zip(detector, all_data)): if params.mask is None: mask = flex.bool(flex.grid(data.focus()), True) else: mask = params.mask[tile] if hasattr(data,"as_double"): data = data.as_double() logger.flush() if params.verbose: logger.write("Average intensity tile %d: %9.3f\n"%(tile, flex.mean(data))) logger.write("N bins: %d\n"%params.n_bins) logger.flush() x1,y1,x2,y2 = 0,0,panel.get_image_size()[1],panel.get_image_size()[0] bc = panel.get_beam_centre_px(beam.get_s0()) bc = int(round(bc[1])), int(round(bc[0])) # compute the average radial_average(data,mask,bc,sums,sums_sq,counts,panel.get_pixel_size()[0],panel.get_distance(), (x1,y1),(x2,y2)) # average the results, avoiding division by zero results = sums.set_selected(counts <= 0, 0) results /= counts.set_selected(counts <= 0, 1).as_double() if params.median_filter_size is not None: logger.write("WARNING, the median filter is not fully propogated to the variances\n") from scipy.ndimage.filters import median_filter results = flex.double(median_filter(results.as_numpy_array(), size = params.median_filter_size)) # calculate standard devations stddev_sel = ((sums_sq-sums*results) >= 0) & (counts > 0) std_devs = flex.double(len(sums), 0) std_devs.set_selected(stddev_sel, (sums_sq.select(stddev_sel)-sums.select(stddev_sel)* \ results.select(stddev_sel))/counts.select(stddev_sel).as_double()) std_devs = flex.sqrt(std_devs) twotheta = flex.double(xrange(len(results)))*extent_two_theta/params.n_bins q_vals = 4*math.pi*flex.sin(math.pi*twotheta/360)/beam.get_wavelength() if params.low_max_two_theta_limit is None: subset = results else: subset = results.select(twotheta >= params.low_max_two_theta_limit) max_result = flex.max(subset) if params.x_axis == 'two_theta': xvals = twotheta max_x = twotheta[flex.first_index(results, max_result)] elif params.x_axis == 'q': xvals = q_vals max_x = q_vals[flex.first_index(results, max_result)] for i in xrange(len(results)): val = xvals[i] if params.output_bins and "%.3f"%results[i] != "nan": #logger.write("%9.3f %9.3f\n"% (val,results[i])) #.xy format for Rex.cell. logger.write("%9.3f %9.3f %9.3f\n"%(val,results[i],std_devs[i])) #.xye format for GSASII #logger.write("%.3f %.3f %.3f\n"%(val,results[i],ds[i])) # include calculated d spacings logger.write("Maximum %s: %f, value: %f\n"%(params.x_axis, max_x, max_result)) if params.show_plots: if params.plot_x_max is not None: results = results.select(xvals <= params.plot_x_max) xvals = xvals.select(xvals <= params.plot_x_max) if params.normalize: plt.plot(xvals.as_numpy_array(),(results/flex.max(results)).as_numpy_array(),'-') else: plt.plot(xvals.as_numpy_array(),results.as_numpy_array(),'-') if params.x_axis == 'two_theta': plt.xlabel("2 theta") elif params.x_axis == 'q': plt.xlabel("q") plt.ylabel("Avg ADUs") if params.plot_y_max is not None: plt.ylim(0, params.plot_y_max) if params.show_plots: #plt.legend([os.path.basename(os.path.splitext(f)[0]) for f in params.file_path], ncol=2) plt.show() return xvals, results
def get_goniometer_shadow_masker(self, goniometer=None): from dials.util.masking import GoniometerShadowMaskGenerator from scitbx.array_family import flex import math coords = flex.vec3_double(( (0,0,0), )) alpha = flex.double_range(0, 190, step=10) * math.pi / 180 r = flex.double(alpha.size(), 40) x = flex.double(r.size(), 107.61) y = -r*flex.sin(alpha) z = -r*flex.cos(alpha) coords.extend(flex.vec3_double(x, y, z)) coords.extend(flex.vec3_double(( # fixed (107.49, 7.84, 39.49), (107.39, 15.69, 38.97), (107.27, 23.53, 38.46), (107.16, 31.37, 37.94), (101.76, 33.99, 36.25), (96.37, 36.63, 34.56), (90.98, 39.25, 33.00), (85.58, 41.88, 31.18), (80.89, 47.06, 31.00), (76.55, 51.51, 31.03), (72.90, 55.04, 31.18), (66.86, 60.46, 31.67), (62.10, 64.41, 32.25), ))) alpha = flex.double_range(180, 370, step=10) * math.pi / 180 r = flex.double(alpha.size(), 33) x = (flex.sqrt(flex.pow2(r * flex.sin(alpha)) + 89.02**2) * flex.cos((50 * math.pi/180) - flex.atan(r/89.02 * flex.sin(alpha)))) y = (flex.sqrt(flex.pow2(r * flex.sin(alpha)) + 89.02**2) * flex.sin((50 * math.pi/180) - flex.atan(r/89.02 * flex.sin(alpha)))) z = -r*flex.cos(alpha) coords.extend(flex.vec3_double(x, y, z)) coords.extend(flex.vec3_double(( # fixed (62.10, 64.41, -32.25), (66.86, 60.46, -31.67), (72.90, 55.04, -31.18), (76.55, 51.51, -31.03), (80.89, 47.06, -31.00), (85.58, 41.88, -31.18), (90.98, 39.25, -33.00), (96.37, 36.63, -34.56), (101.76, 33.99, -36.25), (107.16, 31.37, -37.94), (107.27, 23.53, -38.46), (107.39, 15.69, -38.97), (107.49, 7.84, -39.49), (107.61, 0.00, -40.00) ))) # I23 end station coordinate system: # X-axis: positive direction is facing away from the storage ring (from # sample towards goniometer) # Y-axis: positive direction is vertically up # Z-axis: positive direction is in the direction of the beam (from # sample towards detector) # K-axis (kappa): at an angle of +50 degrees from the X-axis # K & phi rotation axes: clockwise rotation is positive (right hand # thumb rule) # Omega-axis: along the X-axis; clockwise rotation is positive # End station x-axis is parallel to ImgCIF x-axis # End station z-axis points in opposite direction to ImgCIF definition # (ImgCIF: The Z-axis is derived from the source axis which goes from # the sample to the source) # Consequently end station y-axis (to complete set following right hand # rule) points in opposite direction to ImgCIF y-axis. # Kappa arm aligned with -y in ImgCIF convention from rstbx.cftbx.coordinate_frame_helpers import align_reference_frame from scitbx import matrix R = align_reference_frame(matrix.col((1,0,0)), matrix.col((1,0,0)), matrix.col((0,1,0)), matrix.col((0,-1,0))) coords = R.elems * coords if goniometer is None: goniometer = self.get_goniometer() return GoniometerShadowMaskGenerator( goniometer, coords, flex.size_t(len(coords), 1))