def get_top_solutions(self, ai, input_directions, size, cutoff_divisor): # size was 30 in the Rossmann DPS paper kval_cutoff = ai.getXyzSize() / cutoff_divisor hemisphere_solutions = flex.Direction() hemisphere_solutions.reserve(size) for i in range(len(input_directions)): sampled_direction = ai.fft_result(input_directions[i]) if sampled_direction.kval > kval_cutoff: hemisphere_solutions.append(sampled_direction) if (hemisphere_solutions.size() < 3): return hemisphere_solutions kvals = flex.double([ hemisphere_solutions[x].kval for x in range(len(hemisphere_solutions)) ]) perm = flex.sort_permutation(kvals, True) # conventional algorithm; just take the top scoring hits. # use this for quick_grid, when it is known ahead of time # that many (hundreds) of directions will be retained hemisphere_solutions_sort = flex.Direction( [hemisphere_solutions[p] for p in perm[0:min(size, len(perm))]]) return hemisphere_solutions_sort
def find_basis_vectors(self, reciprocal_lattice_vectors): """Find a list of likely basis vectors. Args: reciprocal_lattice_vectors (scitbx.array_family.flex.vec3_double): The list of reciprocal lattice vectors to search for periodicity. """ used_in_indexing = flex.bool(reciprocal_lattice_vectors.size(), True) logger.info("Indexing from %i reflections" % used_in_indexing.count(True)) vectors, weights = self.score_vectors(reciprocal_lattice_vectors) perm = flex.sort_permutation(weights, reverse=True) vectors = vectors.select(perm) weights = weights.select(perm) groups = group_vectors(vectors, weights, max_groups=self._params.max_vectors) unique_vectors = [] unique_weights = [] for g in groups: idx = flex.max_index(flex.double(g.weights)) unique_vectors.append(g.vectors[idx]) unique_weights.append(g.weights[idx]) logger.info("Number of unique vectors: %i" % len(unique_vectors)) for v, w in zip(unique_vectors, unique_weights): logger.debug("%s %s %s" % (w, v.length(), str(v.elems))) return unique_vectors, used_in_indexing
def get_top_solutions(self,ai,input_directions,size,cutoff_divisor): # size was 30 in the Rossmann DPS paper kval_cutoff = ai.getXyzSize()/cutoff_divisor; hemisphere_solutions = flex.Direction(); hemisphere_solutions.reserve(size); for i in xrange(len(input_directions)): sampled_direction = ai.fft_result(input_directions[i]) if sampled_direction.kval > kval_cutoff: hemisphere_solutions.append(sampled_direction) if (hemisphere_solutions.size()<3): return hemisphere_solutions kvals = flex.double([ hemisphere_solutions[x].kval for x in xrange(len(hemisphere_solutions))]) perm = flex.sort_permutation(kvals,True) # conventional algorithm; just take the top scoring hits. # use this for quick_grid, when it is known ahead of time # that many (hundreds) of directions will be retained hemisphere_solutions_sort = flex.Direction( [hemisphere_solutions[p] for p in perm[0:min(size,len(perm))]]) return hemisphere_solutions_sort;
def restrict_target_angles_to_quick_winners(self, quick_sampling): # find which target_grid directions are near neighbors to # the quick_sampling winners from the first round of testing. # in the second round, restrict the calculation of FFTs to those directions self.restricted = flex.Direction() target = flex.double() for iz in self.angles: # fairly inefficient in Python; expect big improvement in C++ v = iz.dvec target.append(v[0]) target.append(v[1]) target.append(v[2]) kn = int(2 * self.second_round_sampling) #construct k-d tree for the reference set A = AnnAdaptor(data=target, dim=3, k=kn) query = flex.double() for j in quick_sampling: v = j.dvec query.append(v[0]) query.append(v[1]) query.append(v[2]) if abs((math.pi / 2.) - j.psi) < 0.0001: #take care of equatorial boundary query.append(-v[0]) query.append(-v[1]) query.append(-v[2]) A.query(query) #find nearest neighbors of query points neighbors = flex.sqrt(A.distances) neighborid = A.nn accept_flag = flex.bool(len(self.angles)) for idx in range(len(neighbors)): # use small angle approximation to test if target is within desired radius if neighbors[idx] < self.quick_grid: accept_flag[neighborid[idx]] = True #go through all of the original target angles for iz in range(len(self.angles)): if accept_flag[iz]: self.restricted.append(self.angles[iz]) self.angles = self.restricted
def restrict_target_angles_to_quick_winners(self,quick_sampling): # find which target_grid directions are near neighbors to # the quick_sampling winners from the first round of testing. # in the second round, restrict the calculation of FFTs to those directions self.restricted = flex.Direction() target = flex.double() for iz in self.angles: # fairly inefficient in Python; expect big improvement in C++ v = iz.dvec target.append(v[0]);target.append(v[1]);target.append(v[2]); kn = int(2 *self.second_round_sampling) #construct k-d tree for the reference set A = AnnAdaptor(data = target, dim = 3, k = kn) query = flex.double() for j in quick_sampling: v = j.dvec query.append(v[0]);query.append(v[1]); query.append(v[2]); if abs((math.pi/2.) - j.psi) < 0.0001: #take care of equatorial boundary query.append(-v[0]);query.append(-v[1]); query.append(-v[2]); A.query(query) #find nearest neighbors of query points neighbors = flex.sqrt(A.distances) neighborid = A.nn accept_flag = flex.bool(len(self.angles)) for idx in xrange(len(neighbors)): # use small angle approximation to test if target is within desired radius if neighbors[idx] < self.quick_grid: accept_flag[neighborid[idx]] = True #go through all of the original target angles for iz in xrange(len(self.angles)): if accept_flag[iz]: self.restricted.append(self.angles[iz]) self.angles = self.restricted
def get_top_solutions(self, ai, input_directions, size, cutoff_divisor, grid): kval_cutoff = ai.getXyzSize() / cutoff_divisor hemisphere_solutions = flex.Direction() hemisphere_solutions.reserve(size) #print "# of input directions", len(input_directions) for i in range(len(input_directions)): D = sampled_direction = ai.fft_result(input_directions[i]) #hardcoded parameter in for silicon example. Not sure at this point how #robust the algorithm is when this value is relaxed. if D.real < self.max_cell and sampled_direction.kval > kval_cutoff: if diagnostic: directional_show(D, "%5d" % i) hemisphere_solutions.append(sampled_direction) if (hemisphere_solutions.size() < 3): return hemisphere_solutions kvals = flex.double([ hemisphere_solutions[x].kval for x in range(len(hemisphere_solutions)) ]) perm = flex.sort_permutation(kvals, True) # need to be more clever than just taking the top 30. # one huge cluster around a strong basis direction could dominate the # whole hemisphere map, preventing the discovery of three basis vectors perm_idx = 0 unique_clusters = 0 hemisphere_solutions_sort = flex.Direction() while perm_idx < len(perm) and \ unique_clusters < size: test_item = hemisphere_solutions[perm[perm_idx]] direction_ok = True for list_item in hemisphere_solutions_sort: distance = math.sqrt( math.pow(list_item.dvec[0] - test_item.dvec[0], 2) + math.pow(list_item.dvec[1] - test_item.dvec[1], 2) + math.pow(list_item.dvec[2] - test_item.dvec[2], 2)) if distance < 0.087: #i.e., 5 degrees radius for clustering analysis direction_ok = False break if direction_ok: unique_clusters += 1 hemisphere_solutions_sort.append(test_item) perm_idx += 1 return hemisphere_solutions_sort
def get_top_solutions(self, ai, input_directions, size, cutoff_divisor, grid): # size was 30 in the Rossmann DPS paper kval_cutoff = ai.getXyzSize() / cutoff_divisor hemisphere_solutions = flex.Direction() hemisphere_solutions.reserve(size) for i in range(len(input_directions)): D = sampled_direction = ai.fft_result(input_directions[i]) if D.real < self.max_cell_input and sampled_direction.kval > kval_cutoff: #directional_show(D, "ddd %5d"%i) hemisphere_solutions.append(sampled_direction) if (hemisphere_solutions.size() < 3): return hemisphere_solutions kvals = flex.double([ hemisphere_solutions[x].kval for x in range(len(hemisphere_solutions)) ]) perm = flex.sort_permutation(kvals, True) # need to be more clever than just taking the top 30. # one huge cluster around a strong basis direction could dominate the # whole hemisphere map, preventing the discovery of three basis vectors perm_idx = 0 unique_clusters = 0 hemisphere_solutions_sort = flex.Direction() while perm_idx < len(perm) and \ unique_clusters < size: test_item = hemisphere_solutions[perm[perm_idx]] direction_ok = True for list_item in hemisphere_solutions_sort: distance = math.sqrt( math.pow(list_item.dvec[0] - test_item.dvec[0], 2) + math.pow(list_item.dvec[1] - test_item.dvec[1], 2) + math.pow(list_item.dvec[2] - test_item.dvec[2], 2)) if distance < 0.087: #i.e., 5 degrees direction_ok = False break if direction_ok: unique_clusters += 1 hemisphere_solutions_sort.append(test_item) perm_idx += 1 return hemisphere_solutions_sort
def get_top_solutions(self,ai,input_directions,size,cutoff_divisor,grid): kval_cutoff = ai.getXyzSize()/cutoff_divisor; hemisphere_solutions = flex.Direction(); hemisphere_solutions.reserve(size); #print "# of input directions", len(input_directions) for i in xrange(len(input_directions)): D = sampled_direction = ai.fft_result(input_directions[i]) #hardcoded parameter in for silicon example. Not sure at this point how #robust the algorithm is when this value is relaxed. if D.real < self.max_cell and sampled_direction.kval > kval_cutoff: if diagnostic: directional_show(D, "%5d"%i) hemisphere_solutions.append(sampled_direction) if (hemisphere_solutions.size()<3): return hemisphere_solutions kvals = flex.double([ hemisphere_solutions[x].kval for x in xrange(len(hemisphere_solutions))]) perm = flex.sort_permutation(kvals,True) # need to be more clever than just taking the top 30. # one huge cluster around a strong basis direction could dominate the # whole hemisphere map, preventing the discovery of three basis vectors perm_idx = 0 unique_clusters = 0 hemisphere_solutions_sort = flex.Direction() while perm_idx < len(perm) and \ unique_clusters < size: test_item = hemisphere_solutions[perm[perm_idx]] direction_ok = True for list_item in hemisphere_solutions_sort: distance = math.sqrt(math.pow(list_item.dvec[0]-test_item.dvec[0],2) + math.pow(list_item.dvec[1]-test_item.dvec[1],2) + math.pow(list_item.dvec[2]-test_item.dvec[2],2) ) if distance < 0.087: #i.e., 5 degrees radius for clustering analysis direction_ok=False break if direction_ok: unique_clusters+=1 hemisphere_solutions_sort.append(test_item) perm_idx+=1 return hemisphere_solutions_sort;
def score_vectors(self, reciprocal_lattice_vectors): """Compute the functional for the given directions. Args: directions: An iterable of the search directions. reciprocal_lattice_vectors (scitbx.array_family.flex.vec3_double): The list of reciprocal lattice vectors. Returns: A tuple containing the list of search vectors and their scores. """ vectors = flex.vec3_double() scores = flex.double() for i, v in enumerate(self.search_vectors): f = self.compute_functional(v.elems, reciprocal_lattice_vectors) vectors.append(v.elems) scores.append(f) return vectors, scores
def get_top_solutions(self,ai,input_directions,size,cutoff_divisor,grid): # size was 30 in the Rossmann DPS paper kval_cutoff = ai.getXyzSize()/cutoff_divisor; hemisphere_solutions = flex.Direction(); hemisphere_solutions.reserve(size); for i in xrange(len(input_directions)): D = sampled_direction = ai.fft_result(input_directions[i]) if D.real < self.max_cell_input and sampled_direction.kval > kval_cutoff: #directional_show(D, "ddd %5d"%i) hemisphere_solutions.append(sampled_direction) if (hemisphere_solutions.size()<3): return hemisphere_solutions kvals = flex.double([ hemisphere_solutions[x].kval for x in xrange(len(hemisphere_solutions))]) perm = flex.sort_permutation(kvals,True) # need to be more clever than just taking the top 30. # one huge cluster around a strong basis direction could dominate the # whole hemisphere map, preventing the discovery of three basis vectors perm_idx = 0 unique_clusters = 0 hemisphere_solutions_sort = flex.Direction() while perm_idx < len(perm) and \ unique_clusters < size: test_item = hemisphere_solutions[perm[perm_idx]] direction_ok = True for list_item in hemisphere_solutions_sort: distance = math.sqrt(math.pow(list_item.dvec[0]-test_item.dvec[0],2) + math.pow(list_item.dvec[1]-test_item.dvec[1],2) + math.pow(list_item.dvec[2]-test_item.dvec[2],2) ) if distance < 0.087: #i.e., 5 degrees direction_ok=False break if direction_ok: unique_clusters+=1 hemisphere_solutions_sort.append(test_item) perm_idx+=1 return hemisphere_solutions_sort;
def optimize_S0_local_scope(self): """Local scope: find the optimal S0 vector closest to the input S0 vector (local minimum, simple minimization)""" ############ Implement a direct beam check right here ######################### unique=0 # construct two vectors that are perpendicular to the beam. Gives a basis for refining beam beamr0 = self.S0_vector.cross(self.axis).normalize() beamr1 = beamr0.cross(self.S0_vector).normalize() beamr2 = beamr1.cross(self.S0_vector).normalize() assert approx_equal(self.S0_vector.dot(beamr1), 0.) assert approx_equal(self.S0_vector.dot(beamr2), 0.) assert approx_equal(beamr2.dot(beamr1), 0.) # so the orthonormal vectors are self.S0_vector, beamr1 and beamr2 grid = 10 # DO A SIMPLEX MINIMIZATION from scitbx.simplex import simplex_opt class test_simplex_method(object): def __init__(selfOO): selfOO.starting_simplex=[] selfOO.n = 2 for ii in range(selfOO.n+1): selfOO.starting_simplex.append(flex.random_double(selfOO.n)) selfOO.optimizer = simplex_opt( dimension=selfOO.n, matrix = selfOO.starting_simplex, evaluator = selfOO, tolerance=1e-7) selfOO.x = selfOO.optimizer.get_solution() def target(selfOO, vector): newvec = matrix.col(self.S0_vector) + vector[0]*0.0002*beamr1 + vector[1]*0.0002*beamr2 normal = newvec.normalize() * self.inv_wave return -self.get_S0_vector_score(normal,unique) # extended API MIN = test_simplex_method() #MIN = test_cma_es() print "MINIMUM=",list(MIN.x) newvec = matrix.col(self.S0_vector) + MIN.x[0]*0.0002*beamr1 + MIN.x[1]*0.0002*beamr2 new_S0_vector = newvec.normalize() * self.inv_wave print "old S0:",list(self.S0_vector.elems) print "new S0",list(new_S0_vector.elems) plot = False if plot: scores = flex.double() for x in range(-grid,grid+1): for y in range(-grid,grid+1): ref = matrix.col(self.S0_vector) newvec = ref + x*0.0002*beamr1 + y*0.0002*beamr2 normal = newvec.normalize() * self.inv_wave scores.append( self.get_S0_vector_score(normal,unique) ) # extended API def show_plot(grid,excursi): excursi.reshape(flex.grid(grid, grid)) from matplotlib import pyplot as plt plt.figure() CS = plt.contour([i*0.2 for i in range(grid)],[i*0.2 for i in range(grid)], excursi.as_numpy_array()) plt.clabel(CS, inline=1, fontsize=10, fmt="%6.3f") plt.title("Score as to beam likelihood") plt.scatter([0.1*(grid-1)],[0.1*(grid-1)],color='g',marker='o') plt.scatter([0.1*(grid-1)+0.2*MIN.x[0]] , [0.1*(grid-1)+0.2*MIN.x[1]],color='r',marker='*') plt.axes().set_aspect("equal") plt.show() show_plot(2 * grid + 1, scores) return new_S0_vector
def optimize_origin_offset_local_scope(self): """Local scope: find the optimal origin-offset closest to the current overall detector position (local minimum, simple minimization)""" # construct two vectors that are perpendicular to the beam. Gives a basis for refining beam if self.axis is None: beamr0 = self.S0_vector.cross(matrix.col((1,0,0))).normalize() else: beamr0 = self.S0_vector.cross(self.axis).normalize() beamr1 = beamr0.cross(self.S0_vector).normalize() beamr2 = beamr1.cross(self.S0_vector).normalize() assert approx_equal(self.S0_vector.dot(beamr1), 0.) assert approx_equal(self.S0_vector.dot(beamr2), 0.) assert approx_equal(beamr2.dot(beamr1), 0.) # so the orthonormal vectors are self.S0_vector, beamr1 and beamr2 # DO A SIMPLEX MINIMIZATION from scitbx.simplex import simplex_opt class test_simplex_method(object): def __init__(selfOO): selfOO.starting_simplex=[] selfOO.n = 2 for ii in range(selfOO.n+1): selfOO.starting_simplex.append(flex.random_double(selfOO.n)) selfOO.optimizer = simplex_opt( dimension=selfOO.n, matrix = selfOO.starting_simplex, evaluator = selfOO, tolerance=1e-7) selfOO.x = selfOO.optimizer.get_solution() def target(selfOO, vector): trial_origin_offset = vector[0]*0.2*beamr1 + vector[1]*0.2*beamr2 return -self.get_origin_offset_score(trial_origin_offset) MIN = test_simplex_method() trial_origin_offset = MIN.x[0]*0.2*beamr1 + MIN.x[1]*0.2*beamr2 #print "The Origin Offset best score is",self.get_origin_offset_score(trial_origin_offset) if self.horizon_phil.indexing.plot_search_scope: scope = self.horizon_phil.indexing.mm_search_scope plot_px_sz = self.detector[0].get_pixel_size()[0] grid = max(1,int(scope/plot_px_sz)) scores = flex.double() for y in range(-grid,grid+1): for x in range(-grid,grid+1): new_origin_offset = x*plot_px_sz*beamr1 + y*plot_px_sz*beamr2 scores.append( self.get_origin_offset_score(new_origin_offset) ) def show_plot(widegrid,excursi): excursi.reshape(flex.grid(widegrid, widegrid)) def igrid(x): return x - (widegrid//2) from matplotlib import pyplot as plt plt.figure() CS = plt.contour([igrid(i)*plot_px_sz for i in range(widegrid)], [igrid(i)*plot_px_sz for i in range(widegrid)], excursi.as_numpy_array()) plt.clabel(CS, inline=1, fontsize=10, fmt="%6.3f") plt.title("Wide scope search for detector origin offset") plt.scatter([0.0],[0.0],color='g',marker='o') plt.scatter([0.2*MIN.x[0]] , [0.2*MIN.x[1]],color='r',marker='*') plt.axes().set_aspect("equal") plt.xlabel("offset (mm) along beamr1 vector") plt.ylabel("offset (mm) along beamr2 vector") plt.show() show_plot(widegrid = 2 * grid + 1, excursi = scores) return dps_extended.get_new_detector(self.detector, trial_origin_offset)
def optimize_S0_local_scope(self): """Local scope: find the optimal S0 vector closest to the input S0 vector (local minimum, simple minimization)""" ############ Implement a direct beam check right here ######################### unique=0 # construct two vectors that are perpendicular to the beam. Gives a basis for refining beam beamr0 = self.S0_vector.cross(self.axis).normalize() beamr1 = beamr0.cross(self.S0_vector).normalize() beamr2 = beamr1.cross(self.S0_vector).normalize() assert approx_equal(self.S0_vector.dot(beamr1), 0.) assert approx_equal(self.S0_vector.dot(beamr2), 0.) assert approx_equal(beamr2.dot(beamr1), 0.) # so the orthonormal vectors are self.S0_vector, beamr1 and beamr2 grid = 10 # DO A SIMPLEX MINIMIZATION from scitbx.simplex import simplex_opt class test_simplex_method(object): def __init__(selfOO): selfOO.starting_simplex=[] selfOO.n = 2 for ii in range(selfOO.n+1): selfOO.starting_simplex.append(flex.random_double(selfOO.n)) selfOO.optimizer = simplex_opt( dimension=selfOO.n, matrix = selfOO.starting_simplex, evaluator = selfOO, tolerance=1e-7) selfOO.x = selfOO.optimizer.get_solution() def target(selfOO, vector): newvec = matrix.col(self.S0_vector) + vector[0]*0.0002*beamr1 + vector[1]*0.0002*beamr2 normal = newvec.normalize() * self.inv_wave return -self.get_S0_vector_score(normal,unique) # extended API MIN = test_simplex_method() #MIN = test_cma_es() print "MINIMUM=",list(MIN.x) newvec = matrix.col(self.S0_vector) + MIN.x[0]*0.0002*beamr1 + MIN.x[1]*0.0002*beamr2 new_S0_vector = newvec.normalize() * self.inv_wave print "old S0:",list(self.S0_vector.elems) print "new S0",list(new_S0_vector.elems) plot = False if plot: scores = flex.double() for x in xrange(-grid,grid+1): for y in xrange(-grid,grid+1): ref = matrix.col(self.S0_vector) newvec = ref + x*0.0002*beamr1 + y*0.0002*beamr2 normal = newvec.normalize() * self.inv_wave scores.append( self.get_S0_vector_score(normal,unique) ) # extended API def show_plot(grid,excursi): excursi.reshape(flex.grid(grid, grid)) from matplotlib import pyplot as plt plt.figure() CS = plt.contour([i*0.2 for i in xrange(grid)],[i*0.2 for i in xrange(grid)], excursi.as_numpy_array()) plt.clabel(CS, inline=1, fontsize=10, fmt="%6.3f") plt.title("Score as to beam likelihood") plt.scatter([0.1*(grid-1)],[0.1*(grid-1)],color='g',marker='o') plt.scatter([0.1*(grid-1)+0.2*MIN.x[0]] , [0.1*(grid-1)+0.2*MIN.x[1]],color='r',marker='*') plt.axes().set_aspect("equal") plt.show() show_plot(2 * grid + 1, scores) return new_S0_vector
def optimize_origin_offset_local_scope(self): """Local scope: find the optimal origin-offset closest to the current overall detector position (local minimum, simple minimization)""" # construct two vectors that are perpendicular to the beam. Gives a basis for refining beam if self.axis is None: beamr0 = self.S0_vector.cross(matrix.col((1,0,0))).normalize() else: beamr0 = self.S0_vector.cross(self.axis).normalize() beamr1 = beamr0.cross(self.S0_vector).normalize() beamr2 = beamr1.cross(self.S0_vector).normalize() assert approx_equal(self.S0_vector.dot(beamr1), 0.) assert approx_equal(self.S0_vector.dot(beamr2), 0.) assert approx_equal(beamr2.dot(beamr1), 0.) # so the orthonormal vectors are self.S0_vector, beamr1 and beamr2 # DO A SIMPLEX MINIMIZATION from scitbx.simplex import simplex_opt class test_simplex_method(object): def __init__(selfOO): selfOO.starting_simplex=[] selfOO.n = 2 for ii in range(selfOO.n+1): selfOO.starting_simplex.append(flex.random_double(selfOO.n)) selfOO.optimizer = simplex_opt( dimension=selfOO.n, matrix = selfOO.starting_simplex, evaluator = selfOO, tolerance=1e-7) selfOO.x = selfOO.optimizer.get_solution() def target(selfOO, vector): trial_origin_offset = vector[0]*0.2*beamr1 + vector[1]*0.2*beamr2 return -self.get_origin_offset_score(trial_origin_offset) MIN = test_simplex_method() trial_origin_offset = MIN.x[0]*0.2*beamr1 + MIN.x[1]*0.2*beamr2 #print "The Origin Offset best score is",self.get_origin_offset_score(trial_origin_offset) if self.horizon_phil.indexing.plot_search_scope: scope = self.horizon_phil.indexing.mm_search_scope plot_px_sz = self.detector[0].get_pixel_size()[0] grid = max(1,int(scope/plot_px_sz)) scores = flex.double() for y in xrange(-grid,grid+1): for x in xrange(-grid,grid+1): new_origin_offset = x*plot_px_sz*beamr1 + y*plot_px_sz*beamr2 scores.append( self.get_origin_offset_score(new_origin_offset) ) def show_plot(widegrid,excursi): excursi.reshape(flex.grid(widegrid, widegrid)) def igrid(x): return x - (widegrid//2) from matplotlib import pyplot as plt plt.figure() CS = plt.contour([igrid(i)*plot_px_sz for i in xrange(widegrid)], [igrid(i)*plot_px_sz for i in xrange(widegrid)], excursi.as_numpy_array()) plt.clabel(CS, inline=1, fontsize=10, fmt="%6.3f") plt.title("Wide scope search for detector origin offset") plt.scatter([0.0],[0.0],color='g',marker='o') plt.scatter([0.2*MIN.x[0]] , [0.2*MIN.x[1]],color='r',marker='*') plt.axes().set_aspect("equal") plt.xlabel("offset (mm) along beamr1 vector") plt.ylabel("offset (mm) along beamr2 vector") plt.show() show_plot(widegrid = 2 * grid + 1, excursi = scores) return dps_extended.get_new_detector(self.detector, trial_origin_offset)