def tst_crystal_with_scan_points(self): from dxtbx.model import Crystal, CrystalFactory from scitbx import matrix real_space_a = matrix.col( (35.2402102454, -7.60002142787, 22.080026774)) real_space_b = matrix.col( (22.659572494, 1.47163505925, -35.6586361881)) real_space_c = matrix.col( (5.29417246554, 38.9981792999, 4.97368666613)) c1 = Crystal(real_space_a=real_space_a, real_space_b=real_space_b, real_space_c=real_space_c, space_group_symbol="P 1 2/m 1") A = c1.get_A() c1.set_A_at_scan_points([A for i in range(5)]) d = c1.to_dict() c2 = CrystalFactory.from_dict(d) eps = 1e-9 for Acomp in (d['A_at_scan_points']): for e1, e2 in zip(A, Acomp): assert (abs(e1 - e2) <= eps) assert (c1 == c2) print 'OK'
def test_crystal(mosaic): from dxtbx.model import CrystalFactory from scitbx import matrix real_space_a = matrix.col((35.2402102454, -7.60002142787, 22.080026774)) real_space_b = matrix.col((22.659572494, 1.47163505925, -35.6586361881)) real_space_c = matrix.col((5.29417246554, 38.9981792999, 4.97368666613)) if mosaic: from dxtbx.model import MosaicCrystalKabsch2010 c1 = MosaicCrystalKabsch2010( real_space_a=real_space_a, real_space_b=real_space_b, real_space_c=real_space_c, space_group_symbol="P 1 2/m 1") c1.set_mosaicity(0.1) else: from dxtbx.model import Crystal c1 = Crystal( real_space_a=real_space_a, real_space_b=real_space_b, real_space_c=real_space_c, space_group_symbol="P 1 2/m 1") d = c1.to_dict() c2 = CrystalFactory.from_dict(d) eps = 1e-7 assert abs(matrix.col(d['real_space_a']) - real_space_a) <= eps assert abs(matrix.col(d['real_space_b']) - real_space_b) <= eps assert abs(matrix.col(d['real_space_c']) - real_space_c) <= eps assert d['space_group_hall_symbol'] == "-P 2y" if mosaic: assert d['mosaicity'] == 0.1 assert c1 == c2
def test_crystal_with_scan_points(example_crystal): c1 = Crystal(**example_crystal) A = c1.get_A() c1.set_A_at_scan_points([A for i in range(5)]) # Set the B covariance. The values are nonsense, just ensure they are # all different cov_B = flex.double(range(9 * 9)) * 1e-5 c1.set_B_covariance(cov_B) cov_B.reshape(flex.grid(1, 9, 9)) cov_B_array = flex.double(flex.grid(5, 9, 9)) for i in range(5): cov_B_array[i:(i + 1), :, :] = cov_B c1.set_B_covariance_at_scan_points(cov_B_array) cov_B = c1.get_B_covariance() d = c1.to_dict() c2 = CrystalFactory.from_dict(d) eps = 1e-9 for Acomp in d["A_at_scan_points"]: for e1, e2 in zip(A, Acomp): assert abs(e1 - e2) <= eps for covBcomp in d["B_covariance_at_scan_points"]: for e1, e2 in zip(cov_B, covBcomp): assert abs(e1 - e2) <= eps assert c1 == c2
def tst_crystal(self): from dxtbx.model import Crystal, CrystalFactory from scitbx import matrix real_space_a = matrix.col( (35.2402102454, -7.60002142787, 22.080026774)) real_space_b = matrix.col( (22.659572494, 1.47163505925, -35.6586361881)) real_space_c = matrix.col( (5.29417246554, 38.9981792999, 4.97368666613)) c1 = Crystal(real_space_a=real_space_a, real_space_b=real_space_b, real_space_c=real_space_c, space_group_symbol="P 1 2/m 1") c1.set_mosaicity(0.1) d = c1.to_dict() c2 = CrystalFactory.from_dict(d) eps = 1e-7 assert (abs(matrix.col(d['real_space_a']) - real_space_a) <= eps) assert (abs(matrix.col(d['real_space_b']) - real_space_b) <= eps) assert (abs(matrix.col(d['real_space_c']) - real_space_c) <= eps) assert (d['space_group_hall_symbol'] == "-P 2y") assert (d['mosaicity'] == 0.1) assert (c1 == c2) print 'OK'
def test_crystal(example_crystal): c1 = Crystal(**example_crystal) d = c1.to_dict() c2 = CrystalFactory.from_dict(d) for direction in ("real_space_a", "real_space_b", "real_space_c"): assert abs(matrix.col(d[direction]) - example_crystal[direction]) <= 1e-7 assert d["space_group_hall_symbol"] == "-P 2y" assert c1 == c2
def test_mosaic_crystal(example_crystal): c1 = MosaicCrystalKabsch2010(**example_crystal) c1.set_mosaicity(0.1) d = c1.to_dict() c2 = CrystalFactory.from_dict(d) for direction in ("real_space_a", "real_space_b", "real_space_c"): assert abs(matrix.col(d[direction]) - example_crystal[direction]) <= 1e-7 assert d["space_group_hall_symbol"] == "-P 2y" assert d["mosaicity"] == 0.1 assert c1 == c2
def crystal_model_from_mosflm_mat(mosflm_mat_lines, unit_cell, space_group): from scitbx import matrix from cctbx import uctbx if not isinstance(unit_cell, uctbx.unit_cell): unit_cell = uctbx.unit_cell(unit_cell) from dxtbx.model import CrystalFactory mosflm_matrix = matrix.sqr( [float(i) for line in mosflm_mat_lines[:3] for i in line.split()][:9]) crystal_model = CrystalFactory.from_mosflm_matrix(mosflm_matrix, unit_cell=unit_cell, space_group=space_group) return crystal_model
def crystal(self): crystal = None # dxtbx crystal description if self.Amatrix is not None: A = sqr(self.Amatrix).inverse().elems # is this always P-1 ? real_a = A[0], A[3], A[6] real_b = A[1], A[4], A[7] real_c = A[2], A[5], A[8] cryst_dict = {'__id__': 'crystal', 'real_space_a': real_a, 'real_space_b': real_b, 'real_space_c': real_c, 'space_group_hall_symbol': ' P 1'} crystal = CrystalFactory.from_dict(cryst_dict) return crystal
def test_crystal_model_from_mosflm_matrix(): mosflm_matrix = map( float, ''' -0.00495480 -0.01491776 0.00238445 0.01505572 -0.00661190 -0.00149401 0.00585043 0.00438127 0.00586415 0.000 0.000 0.000 -0.2932645 -0.8829514 0.3665960 0.8911171 -0.3913446 -0.2296951 0.3462750 0.2593185 0.9015806 57.7822 57.7822 150.0931 90.0000 90.0000 90.0000 0.000 0.000 0.000'''.split()) A = mosflm_matrix[:9] unit_cell = uctbx.unit_cell(mosflm_matrix[21:27]) cm = CrystalFactory.from_mosflm_matrix(A, unit_cell=unit_cell) assert approx_equal(cm.get_unit_cell().parameters(), unit_cell.parameters(), eps=1.0e-2)
def test_crystal_with_recalculated_cell(crystal_class, example_crystal): c1 = crystal_class(**example_crystal) uc = c1.get_unit_cell() c1.set_recalculated_unit_cell(uc) c1.set_recalculated_cell_parameter_sd((0.1, ) * 6) c1.set_recalculated_cell_volume_sd(0.001) d = c1.to_dict() c2 = CrystalFactory.from_dict(d) c3 = pickle.loads(pickle.dumps(c1)) for c in (c2, c3): assert c.get_recalculated_unit_cell() is not None assert c1.get_recalculated_unit_cell().is_similar_to( c.get_recalculated_unit_cell()) assert c1 == c assert c.get_recalculated_cell_parameter_sd() == (0.1, 0.1, 0.1, 0.1, 0.1, 0.1) assert c.get_recalculated_cell_volume_sd() == 0.001
def test_crystal_with_scan_points(): from dxtbx.model import Crystal, CrystalFactory from scitbx import matrix real_space_a = matrix.col((35.2402102454, -7.60002142787, 22.080026774)) real_space_b = matrix.col((22.659572494, 1.47163505925, -35.6586361881)) real_space_c = matrix.col((5.29417246554, 38.9981792999, 4.97368666613)) c1 = Crystal( real_space_a=real_space_a, real_space_b=real_space_b, real_space_c=real_space_c, space_group_symbol="P 1 2/m 1", ) A = c1.get_A() c1.set_A_at_scan_points([A for i in range(5)]) # Set the B covariance. The values are nonsense, just ensure they are # all different from scitbx.array_family import flex cov_B = flex.double(range((9 * 9))) * 1e-5 c1.set_B_covariance(cov_B) cov_B.reshape(flex.grid(1, 9, 9)) cov_B_array = flex.double(flex.grid(5, 9, 9)) for i in range(5): cov_B_array[i : (i + 1), :, :] = cov_B c1.set_B_covariance_at_scan_points(cov_B_array) cov_B = c1.get_B_covariance() d = c1.to_dict() c2 = CrystalFactory.from_dict(d) eps = 1e-9 for Acomp in d["A_at_scan_points"]: for e1, e2 in zip(A, Acomp): assert abs(e1 - e2) <= eps for covBcomp in d["B_covariance_at_scan_points"]: for e1, e2 in zip(cov_B, covBcomp): assert abs(e1 - e2) <= eps assert c1 == c2
def as_explist(self, fname=None, toggle_conventions=False): """ return experiment list for simulated image """ C = self.crystal if toggle_conventions: # switch to DIALS convention before writing CBF # also change basis of crystal CURRENT_CONV = self.beamcenter_convention FSO = sqr(self.fdet_vector + self.sdet_vector + self.pix0_vector_mm) self.beamcenter_convention = DIALS FSO2 = sqr(self.fdet_vector + self.sdet_vector + self.dials_origin_mm) xtal_transform = FSO.inverse() * FSO2 # transform the crystal vectors a, b, c = map(lambda x: xtal_transform * col(x), C.get_real_space_vectors()) Cdict = C.to_dict() Cdict['real_space_a'] = a Cdict['real_space_b'] = b Cdict['real_space_b'] = c C = CrystalFactory.from_dict(Cdict) exp = Experiment() exp.crystal = C exp.beam = self.beam exp.detector = self.detector exp.imageset = self.imageset explist = ExperimentList() explist.append(exp) if fname is not None: explist.as_file(fname) if toggle_conventions: self.beamcenter_convention = CURRENT_CONV return explist
def _crystal_from_dict(obj): """ Get the crystal from a dictionary. """ return CrystalFactory.from_dict(obj)
def _index(self): '''Actually index the diffraction pattern. Note well that this is not going to compute the matrix...''' # acknowledge this program Citations.cite('labelit') Citations.cite('distl') #self.reset() _images = [] for i in self._indxr_images: for j in i: if not j in _images: _images.append(j) _images.sort() images_str = '%d' % _images[0] for i in _images[1:]: images_str += ', %d' % i cell_str = None if self._indxr_input_cell: cell_str = '%.2f %.2f %.2f %.2f %.2f %.2f' % \ self._indxr_input_cell if self._indxr_sweep_name: # then this is a proper autoindexing run - describe this # to the journal entry #if len(self._fp_directory) <= 50: #dirname = self._fp_directory #else: #dirname = '...%s' % self._fp_directory[-46:] dirname = os.path.dirname(self.get_imageset().get_template()) Journal.block( 'autoindexing', self._indxr_sweep_name, 'labelit', { 'images': images_str, 'target cell': cell_str, 'target lattice': self._indxr_input_lattice, 'template': self.get_imageset().get_template(), 'directory': dirname }) if len(_images) > 4: raise RuntimeError('cannot use more than 4 images') from xia2.Wrappers.Labelit.LabelitIndex import LabelitIndex index = LabelitIndex() index.set_working_directory(self.get_working_directory()) auto_logfiler(index) #task = 'Autoindex from images:' #for i in _images: #task += ' %s' % self.get_image_name(i) #self.set_task(task) Debug.write('Indexing from images:') for i in _images: index.add_image(self.get_image_name(i)) Debug.write('%s' % self.get_image_name(i)) xsweep = self.get_indexer_sweep() if xsweep is not None: if xsweep.get_distance() is not None: index.set_distance(xsweep.get_distance()) #if self.get_wavelength_prov() == 'user': #index.set_wavelength(self.get_wavelength()) if xsweep.get_beam_centre() is not None: index.set_beam_centre(xsweep.get_beam_centre()) if self._refine_beam is False: index.set_refine_beam(False) else: index.set_refine_beam(True) index.set_beam_search_scope(self._beam_search_scope) if ((math.fabs(self.get_wavelength() - 1.54) < 0.01) or (math.fabs(self.get_wavelength() - 2.29) < 0.01)): index.set_Cu_KA_or_Cr_KA(True) #sweep = self.get_indexer_sweep_name() #FileHandler.record_log_file( #'%s INDEX' % (sweep), self.get_log_file()) try: index.run() except RuntimeError as e: if self._refine_beam is False: raise e # can we improve the situation? if self._beam_search_scope < 4.0: self._beam_search_scope += 4.0 # try repeating the indexing! self.set_indexer_done(False) return 'failed' # otherwise this is beyond redemption raise e self._solutions = index.get_solutions() # FIXME this needs to check the smilie status e.g. # ":)" or ";(" or " ". # FIXME need to check the value of the RMSD and raise an # exception if the P1 solution has an RMSD > 1.0... # Change 27/FEB/08 to support user assigned spacegroups # (euugh!) have to "ignore" solutions with higher symmetry # otherwise the rest of xia will override us. Bummer. for i, solution in self._solutions.iteritems(): if self._indxr_user_input_lattice: if (lattice_to_spacegroup(solution['lattice']) > lattice_to_spacegroup(self._indxr_input_lattice)): Debug.write('Ignoring solution: %s' % solution['lattice']) del self._solutions[i] # check the RMSD from the triclinic unit cell if self._solutions[1]['rmsd'] > 1.0 and False: # don't know when this is useful - but I know when it is not! raise RuntimeError('high RMSD for triclinic solution') # configure the "right" solution self._solution = self.get_solution() # now store also all of the other solutions... keyed by the # lattice - however these should only be added if they # have a smiley in the appropriate record, perhaps? for solution in self._solutions.keys(): lattice = self._solutions[solution]['lattice'] if lattice in self._indxr_other_lattice_cell: if self._indxr_other_lattice_cell[lattice]['goodness'] < \ self._solutions[solution]['metric']: continue self._indxr_other_lattice_cell[lattice] = { 'goodness': self._solutions[solution]['metric'], 'cell': self._solutions[solution]['cell'] } self._indxr_lattice = self._solution['lattice'] self._indxr_cell = tuple(self._solution['cell']) self._indxr_mosaic = self._solution['mosaic'] lms = LabelitMosflmScript() lms.set_working_directory(self.get_working_directory()) lms.set_solution(self._solution['number']) self._indxr_payload['mosflm_orientation_matrix'] = lms.calculate() # get the beam centre from the mosflm script - mosflm # may have inverted the beam centre and labelit will know # this! mosflm_beam_centre = lms.get_mosflm_beam() if mosflm_beam_centre: self._indxr_payload['mosflm_beam_centre'] = tuple( mosflm_beam_centre) import copy detector = copy.deepcopy(self.get_detector()) beam = copy.deepcopy(self.get_beam()) from dxtbx.model.detector_helpers import set_mosflm_beam_centre set_mosflm_beam_centre(detector, beam, mosflm_beam_centre) from xia2.Experts.SymmetryExpert import lattice_to_spacegroup_number from scitbx import matrix from cctbx import sgtbx, uctbx from dxtbx.model import CrystalFactory mosflm_matrix = matrix.sqr([ float(i) for line in lms.calculate() for i in line.replace("-", " -").split() ][:9]) space_group = sgtbx.space_group_info( lattice_to_spacegroup_number(self._solution['lattice'])).group() crystal_model = CrystalFactory.from_mosflm_matrix( mosflm_matrix, unit_cell=uctbx.unit_cell(tuple(self._solution['cell'])), space_group=space_group) from dxtbx.model import Experiment, ExperimentList experiment = Experiment( beam=beam, detector=detector, goniometer=self.get_goniometer(), scan=self.get_scan(), crystal=crystal_model, ) experiment_list = ExperimentList([experiment]) self.set_indexer_experiment_list(experiment_list) # also get an estimate of the resolution limit from the # labelit.stats_distl output... FIXME the name is wrong! lsd = LabelitStats_distl() lsd.set_working_directory(self.get_working_directory()) lsd.stats_distl() resolution = 1.0e6 for i in _images: stats = lsd.get_statistics(self.get_image_name(i)) resol = 0.5 * (stats['resol_one'] + stats['resol_two']) if resol < resolution: resolution = resol self._indxr_resolution_estimate = resolution return 'ok'
def _crystal_from_dict(obj): ''' Get the crystal from a dictionary. ''' from dxtbx.model import CrystalFactory return CrystalFactory.from_dict(obj)
def _index(self): """Actually index the diffraction pattern. Note well that this is not going to compute the matrix...""" # acknowledge this program if not self._indxr_images: raise RuntimeError("No good spots found on any images") Citations.cite("labelit") Citations.cite("distl") _images = [] for i in self._indxr_images: for j in i: if not j in _images: _images.append(j) _images.sort() images_str = "%d" % _images[0] for i in _images[1:]: images_str += ", %d" % i cell_str = None if self._indxr_input_cell: cell_str = "%.2f %.2f %.2f %.2f %.2f %.2f" % self._indxr_input_cell if self._indxr_sweep_name: # then this is a proper autoindexing run - describe this # to the journal entry if len(self._fp_directory) <= 50: dirname = self._fp_directory else: dirname = "...%s" % self._fp_directory[-46:] Journal.block( "autoindexing", self._indxr_sweep_name, "labelit", { "images": images_str, "target cell": cell_str, "target lattice": self._indxr_input_lattice, "template": self._fp_template, "directory": dirname, }, ) # auto_logfiler(self) from xia2.Wrappers.Labelit.LabelitIndex import LabelitIndex index = LabelitIndex() index.set_working_directory(self.get_working_directory()) auto_logfiler(index) # task = 'Autoindex from images:' # for i in _images: # task += ' %s' % self.get_image_name(i) # self.set_task(task) # self.add_command_line('--index_only') Debug.write("Indexing from images:") for i in _images: index.add_image(self.get_image_name(i)) Debug.write("%s" % self.get_image_name(i)) if self._primitive_unit_cell: index.set_primitive_unit_cell(self._primitive_unit_cell) if self._indxr_input_cell: index.set_max_cell(1.25 * max(self._indxr_input_cell[:3])) xsweep = self.get_indexer_sweep() if xsweep is not None: if xsweep.get_distance() is not None: index.set_distance(xsweep.get_distance()) # if self.get_wavelength_prov() == 'user': # index.set_wavelength(self.get_wavelength()) if xsweep.get_beam_centre() is not None: index.set_beam_centre(xsweep.get_beam_centre()) if self._refine_beam is False: index.set_refine_beam(False) else: index.set_refine_beam(True) index.set_beam_search_scope(self._beam_search_scope) if (math.fabs(self.get_wavelength() - 1.54) < 0.01) or (math.fabs(self.get_wavelength() - 2.29) < 0.01): index.set_Cu_KA_or_Cr_KA(True) try: index.run() except RuntimeError as e: if self._refine_beam is False: raise e # can we improve the situation? if self._beam_search_scope < 4.0: self._beam_search_scope += 4.0 # try repeating the indexing! self.set_indexer_done(False) return "failed" # otherwise this is beyond redemption raise e self._solutions = index.get_solutions() # FIXME this needs to check the smilie status e.g. # ":)" or ";(" or " ". # FIXME need to check the value of the RMSD and raise an # exception if the P1 solution has an RMSD > 1.0... # Change 27/FEB/08 to support user assigned spacegroups # (euugh!) have to "ignore" solutions with higher symmetry # otherwise the rest of xia will override us. Bummer. for i, solution in self._solutions.iteritems(): if self._indxr_user_input_lattice: if lattice_to_spacegroup( solution["lattice"]) > lattice_to_spacegroup( self._indxr_input_lattice): Debug.write("Ignoring solution: %s" % solution["lattice"]) del self._solutions[i] # configure the "right" solution self._solution = self.get_solution() # now store also all of the other solutions... keyed by the # lattice - however these should only be added if they # have a smiley in the appropriate record, perhaps? for solution in self._solutions.keys(): lattice = self._solutions[solution]["lattice"] if lattice in self._indxr_other_lattice_cell: if (self._indxr_other_lattice_cell[lattice]["goodness"] < self._solutions[solution]["metric"]): continue self._indxr_other_lattice_cell[lattice] = { "goodness": self._solutions[solution]["metric"], "cell": self._solutions[solution]["cell"], } self._indxr_lattice = self._solution["lattice"] self._indxr_cell = tuple(self._solution["cell"]) self._indxr_mosaic = self._solution["mosaic"] lms = LabelitMosflmMatrix() lms.set_working_directory(self.get_working_directory()) lms.set_solution(self._solution["number"]) self._indxr_payload["mosflm_orientation_matrix"] = lms.calculate() # get the beam centre from the mosflm script - mosflm # may have inverted the beam centre and labelit will know # this! mosflm_beam_centre = lms.get_mosflm_beam() if mosflm_beam_centre: self._indxr_payload["mosflm_beam_centre"] = tuple( mosflm_beam_centre) detector = copy.deepcopy(self.get_detector()) beam = copy.deepcopy(self.get_beam()) from dxtbx.model.detector_helpers import set_mosflm_beam_centre set_mosflm_beam_centre(detector, beam, mosflm_beam_centre) from xia2.Experts.SymmetryExpert import lattice_to_spacegroup_number from scitbx import matrix from cctbx import sgtbx, uctbx from dxtbx.model import CrystalFactory mosflm_matrix = matrix.sqr([ float(i) for line in lms.calculate() for i in line.replace("-", " -").split() ][:9]) space_group = sgtbx.space_group_info( lattice_to_spacegroup_number(self._solution["lattice"])).group() crystal_model = CrystalFactory.from_mosflm_matrix( mosflm_matrix, unit_cell=uctbx.unit_cell(tuple(self._solution["cell"])), space_group=space_group, ) from dxtbx.model import Experiment, ExperimentList experiment = Experiment( beam=beam, detector=detector, goniometer=self.get_goniometer(), scan=self.get_scan(), crystal=crystal_model, ) experiment_list = ExperimentList([experiment]) self.set_indexer_experiment_list(experiment_list) # also get an estimate of the resolution limit from the # labelit.stats_distl output... FIXME the name is wrong! lsd = LabelitStats_distl() lsd.set_working_directory(self.get_working_directory()) lsd.stats_distl() resolution = 1.0e6 for i in _images: stats = lsd.get_statistics(self.get_image_name(i)) resol = 0.5 * (stats["resol_one"] + stats["resol_two"]) if resol < resolution: resolution = resol self._indxr_resolution_estimate = resolution return "ok"
def test_experiment(): d = { "__id__": "crystal", "real_space_a": [14.963210089244596, -22.599814679318, 51.02946725220764], "real_space_b": [-19.963976860932235, -51.503385430151205, -16.955728379753463], "real_space_c": [135.29560393219694, -34.371677531924206, -54.89475471853507], "space_group_hall_symbol": " P 4", "A_at_scan_points": [[ 0.004481726844090139, -0.005980612987053365, 0.006013325470974739, -0.006768741824936281, -0.015428970379357122, -0.0015280122438480544, 0.01528745348419002, -0.005078101688718203, -0.0024394384982453095, ]], } crystal = CrystalFactory.from_dict(d) beam_d = { "direction": [-2.4882593300783137e-06, -0.0, 0.9999999999969044], "transmission": 1.0, "polarization_normal": [0.0, 1.0, 0.0], "divergence": 0.0, "polarization_fraction": 0.999, "flux": 0.0, "sigma_divergence": 0.0, "wavelength": 0.9762499999999994, } beam = BeamFactory.from_dict(beam_d) scan = Scan(image_range=[0, 1], oscillation=[0.0, 0.01]) detector_dict = { "hierarchy": { "origin": [0.0, 0.0, 0.0], "fast_axis": [1.0, 0.0, 0.0], "name": "", "raw_image_offset": [0, 0], "slow_axis": [0.0, 1.0, 0.0], "material": "", "mask": [], "thickness": 0.0, "mu": 0.0, "gain": 1.0, "trusted_range": [0.0, 0.0], "image_size": [0, 0], "px_mm_strategy": { "type": "SimplePxMmStrategy" }, "identifier": "", "type": "", "children": [{ "panel": 0 }], "pixel_size": [0.0, 0.0], }, "panels": [{ "origin": [-210.66631009735772, 205.7063614421482, -263.8386975038205], "fast_axis": [ 0.9999973940105483, -0.0016357501034268717, -0.0015925745544149894, ], "name": "Panel", "raw_image_offset": [0, 0], "slow_axis": [ -0.0016426481736367285, -0.999989234013669, -0.004339765400707805, ], "material": "Si", "mask": [ [488, 1, 494, 2527], [982, 1, 988, 2527], [1476, 1, 1482, 2527], [1970, 1, 1976, 2527], [1, 196, 2463, 212], [1, 408, 2463, 424], [1, 620, 2463, 636], [1, 832, 2463, 848], [1, 1044, 2463, 1060], [1, 1256, 2463, 1272], [1, 1468, 2463, 1484], [1, 1680, 2463, 1696], [1, 1892, 2463, 1908], [1, 2104, 2463, 2120], [1, 2316, 2463, 2332], ], "thickness": 0.32, "mu": 3.9220322752480934, "gain": 1.0, "trusted_range": [-1.0, 161977.0], "image_size": [2463, 2527], "px_mm_strategy": { "type": "ParallaxCorrectedPxMmStrategy" }, "identifier": "", "type": "SENSOR_PAD", "pixel_size": [0.17200000000000001, 0.17200000000000001], }], } detector = DetectorFactory.from_dict(detector_dict) expt = Experiment(beam=beam, crystal=crystal, scan=scan, detector=detector) return expt