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 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 refine_top_solutions_by_grid_search(self, old_solutions, ai): new_solutions = flex.Direction() final_target_grid = self.characteristic_grid / 100. for item in old_solutions: new_solutions.append( ai.refine_direction(candidate=item, current_grid=self.incr, target_grid=final_target_grid)) return new_solutions
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