def create(cls, vertex_type="vector", edge_type="set"): return cls(graph=graph.adjacency_list( graph_type="undirected", vertex_type=vertex_type, edge_type=edge_type, ), )
def __init__(self, graph, source, sink): from boost_adaptbx import graph as graphmod dirgraph = graphmod.adjacency_list( graph_type="directed", vertex_type="vector", edge_type="vector", ) vertex_for = {} for vertex in graph.vertices(): vertex_for[vertex] = dirgraph.add_vertex(label=vertex) reverse_edge_map = {} for edge in graph.edges(): s = vertex_for[graph.source(edge=edge)] t = vertex_for[graph.target(edge=edge)] w = graph.edge_weight(edge=edge) (ed, success) = dirgraph.add_edge(vertex1=s, vertex2=t, weight=w) assert success (red, success) = dirgraph.add_edge(vertex1=t, vertex2=s, weight=w) assert success reverse_edge_map[ed] = red reverse_edge_map[red] = ed self.result = boykov_kolmogorov_max_flow( graph=dirgraph, reverse_edge_map=reverse_edge_map, source=vertex_for[source], sink=vertex_for[sink], )
def test_adjacency_list_undirected_list_vector(self): try: g = graph.adjacency_list( graph_type = "undirected", vertex_type = "list", edge_type = "vector", ) except NotImplementedError: pass else: reference = self.build_graph( g ) self.manipulation( g, reference = reference, maxiter = None, expected = self.full_count_with_weight, ) self.manipulation( g, reference = reference, maxiter = 24, expected = self.truncated_count_with_weight24, ) self.manipulation( g, reference = reference, maxiter = 27, expected = self.truncated_count_with_weight27, )
def __init__(self, graph, source, sink): from boost_adaptbx import graph as graphmod dirgraph = graphmod.adjacency_list( graph_type = "directed", vertex_type = "vector", edge_type = "vector", ) vertex_for = {} for vertex in graph.vertices(): vertex_for[ vertex ] = dirgraph.add_vertex( label = vertex ) reverse_edge_map = {} for edge in graph.edges(): s = vertex_for[ graph.source( edge = edge ) ] t = vertex_for[ graph.target( edge = edge ) ] w = graph.edge_weight( edge = edge ) ( ed, success ) = dirgraph.add_edge( vertex1 = s, vertex2 = t, weight = w ) assert success ( red, success ) = dirgraph.add_edge( vertex1 = t, vertex2 = s, weight = w ) assert success reverse_edge_map[ ed ] = red reverse_edge_map[ red ] = ed self.result = boykov_kolmogorov_max_flow( graph = dirgraph, reverse_edge_map = reverse_edge_map, source = vertex_for[ source ], sink = vertex_for[ sink ], )
def compatibility_graph( first, second, vertex_equality = operator.eq, edge_equality = operator.eq, output_graph_vertex = "vector", output_graph_edge = "vector", ): from boost_adaptbx import graph result = graph.adjacency_list( graph_type = "undirected", vertex_type = output_graph_vertex, edge_type = output_graph_edge, ) vertex_from = {} import itertools for ( left, right ) in itertools.product( first.vertices(), second.vertices() ): if vertex_equality( first.vertex_label( left ), second.vertex_label( right ) ): label = ( left, right ) vertex_from[ label ] = result.add_vertex( label = label ) edge_weight_first = dict( ( frozenset( [ first.source( edge = e ), first.target( edge = e ) ] ), first.edge_weight( edge = e ) ) for e in first.edges() ) edge_weight_second = dict( ( frozenset( [ second.source( edge = e ), second.target( edge = e ) ] ), second.edge_weight( edge = e ) ) for e in second.edges() ) for ( ( f_l, s_l ), ( f_r, s_r ) ) in itertools.combinations( vertex_from, 2 ): if f_l == f_r or s_l == s_r: continue id_f = frozenset( [ f_l, f_r ] ) id_s = frozenset( [ s_l, s_r ] ) present_f = id_f in edge_weight_first present_s = id_s in edge_weight_second if ( present_f and present_s and edge_equality( edge_weight_first[ id_f ], edge_weight_second[ id_s ] ) ): result.add_edge( vertex1 = vertex_from[ ( f_l, s_l ) ], vertex2 = vertex_from[ ( f_r, s_r ) ], ) elif not present_f and not present_s: result.add_edge( vertex1 = vertex_from[ ( f_l, s_l ) ], vertex2 = vertex_from[ ( f_r, s_r ) ], ) return result
def __init__(self, interaction_list,maxnum_residues_in_cluster=20,size=None): self.interaction_list = interaction_list self.g = graph.adjacency_list( graph_type="undirected", vertex_type="vector", edge_type="set") self.maxnum_residues_in_cluster=maxnum_residues_in_cluster self.size = size
def compatibility_graph( first, second, vertex_equality=operator.eq, edge_equality=operator.eq, output_graph_vertex="vector", output_graph_edge="vector", ): from boost_adaptbx import graph result = graph.adjacency_list( graph_type="undirected", vertex_type=output_graph_vertex, edge_type=output_graph_edge, ) vertex_from = {} import itertools for (left, right) in itertools.product(first.vertices(), second.vertices()): if vertex_equality(first.vertex_label(left), second.vertex_label(right)): label = (left, right) vertex_from[label] = result.add_vertex(label=label) edge_weight_first = dict( (frozenset([first.source( edge=e), first.target(edge=e)]), first.edge_weight(edge=e)) for e in first.edges()) edge_weight_second = dict( (frozenset([second.source( edge=e), second.target(edge=e)]), second.edge_weight(edge=e)) for e in second.edges()) for ((f_l, s_l), (f_r, s_r)) in itertools.combinations(vertex_from, 2): if f_l == f_r or s_l == s_r: continue id_f = frozenset([f_l, f_r]) id_s = frozenset([s_l, s_r]) present_f = id_f in edge_weight_first present_s = id_s in edge_weight_second if (present_f and present_s and edge_equality( edge_weight_first[id_f], edge_weight_second[id_s])): result.add_edge( vertex1=vertex_from[(f_l, s_l)], vertex2=vertex_from[(f_r, s_r)], ) elif not present_f and not present_s: result.add_edge( vertex1=vertex_from[(f_l, s_l)], vertex2=vertex_from[(f_r, s_r)], ) return result
def __init__(self, vertex_type="vector", edge_type="set"): self.graph = graph.adjacency_list( graph_type="undirected", vertex_type=vertex_type, edge_type=edge_type, ) self.atom_for = {} self.xyz_for = {}
def __init__(self, vertex_type = "vector", edge_type = "set"): self.graph = graph.adjacency_list( graph_type = "undirected", vertex_type = vertex_type, edge_type = edge_type, ) self.atom_for = {} self.xyz_for = {}
def create(cls, vertex_type = "vector", edge_type = "set"): return cls( graph = graph.adjacency_list( graph_type = "undirected", vertex_type = vertex_type, edge_type = edge_type, ), )
def test_adjacency_list_undirected_vector_vector(self): try: g = graph.adjacency_list(graph_type="undirected", vertex_type="vector", edge_type="vector") except NotImplementedError: pass else: self.manipulation(g)
def test_adjacency_list_undirected_list_vector(self): try: g1 = graph.adjacency_list( graph_type = "undirected", vertex_type = "list", edge_type = "vector", ) g2 = graph.adjacency_list( graph_type = "undirected", vertex_type = "list", edge_type = "vector", ) except NotImplementedError: pass else: self.manipulation( left = g1, right = g2 )
def test_adjacency_list_undirected_list_set(self): try: leu = graph.adjacency_list( graph_type = "undirected", vertex_type = "list", edge_type = "set", ) asn = graph.adjacency_list( graph_type = "undirected", vertex_type = "list", edge_type = "set", ) except NotImplementedError: pass else: self.manipulate( leu = leu, asn = asn, matchings = 13 )
def test_adjacency_list_undirected_list_vector(self): try: g1 = graph.adjacency_list( graph_type="undirected", vertex_type="list", edge_type="vector", ) g2 = graph.adjacency_list( graph_type="undirected", vertex_type="list", edge_type="vector", ) except NotImplementedError: pass else: self.manipulation(left=g1, right=g2)
def test_adjacency_list_directed_vector_vector(self): try: leu = graph.adjacency_list( graph_type = "directed", vertex_type = "vector", edge_type = "vector", ) asn = graph.adjacency_list( graph_type = "directed", vertex_type = "vector", edge_type = "vector", ) except NotImplementedError: pass else: self.manipulate( leu = leu, asn = asn, matchings = 8 )
def test_adjacency_list_undirected_list_set(self): try: g = graph.adjacency_list( graph_type = "undirected", vertex_type = "list", edge_type = "set", ) except NotImplementedError: pass else: self.manipulation( g, unique_edge = True, directed = False )
def test_adjacency_list_undirected_list_set(self): try: g = graph.adjacency_list( graph_type = "undirected", vertex_type = "list", edge_type = "set", ) except NotImplementedError: pass else: self.build_and_test( g, self.undirected_results() )
def test_adjacency_list_undirected_vector_vector(self): try: g = graph.adjacency_list( graph_type = "undirected", vertex_type = "vector", edge_type = "vector", ) except NotImplementedError: pass else: self.build_and_test( g, self.undirected_params() )
def test_adjacency_list_directed_vector_vector(self): try: g = graph.adjacency_list( graph_type="directed", vertex_type="vector", edge_type="vector", ) except NotImplementedError: pass else: self.manipulation(g, unique_edge=False, directed=True)
def test_adjacency_list_undirected_list_set(self): try: g = graph.adjacency_list( graph_type="undirected", vertex_type="list", edge_type="set", ) except NotImplementedError: pass else: self.manipulation(g, unique_edge=True, directed=False)
def test_adjacency_list_undirected_list_vector(self): try: g = graph.adjacency_list( graph_type="undirected", vertex_type="list", edge_type="vector", ) except NotImplementedError: pass else: self.build_and_test(g, self.undirected_params())
def test_adjacency_list_directed_vector_vector(self): try: g = graph.adjacency_list( graph_type="directed", vertex_type="vector", edge_type="vector", ) except NotImplementedError: pass else: self.build_and_test(g, self.directed_results())
def test_adjacency_list_undirected_vector_vector(self): try: g = graph.adjacency_list( graph_type="undirected", vertex_type="vector", edge_type="vector", ) except NotImplementedError: pass else: self.manipulation(g)
def test_adjacency_list_directed_vector_vector(self): try: g = graph.adjacency_list( graph_type = "directed", vertex_type = "vector", edge_type = "vector", ) except NotImplementedError: pass else: self.manipulation( g, unique_edge = False, directed = True )
def test_adjacency_list_undirected_list_vector(self): try: g = graph.adjacency_list( graph_type="undirected", vertex_type="list", edge_type="vector", ) except NotImplementedError: pass else: reference = self.build_graph(g) self.run_all_tests(g, reference=reference)
def test_adjacency_list_undirected_list_vector(self): try: g = graph.adjacency_list( graph_type = "undirected", vertex_type = "list", edge_type = "vector", ) except NotImplementedError: pass else: reference = self.build_graph( g ) self.run_all_tests(g, reference = reference )
def connected_components(miller_array: cctbx.miller.array, ) -> [{}]: """ Identify connected regions of missing reflections in the asymmetric unit. This is achieved by first generating the complete set of possible miller indices, then performing connected components analysis on a graph of nearest neighbours in the list of missing reflections. Args: miller_array: The input list of reflections. Returns: The list of miller sets for each connected region of missing reflections. The first item in the list will be the complete set of all possible miller indices. """ # Map to primitive setting for centred cells, otherwise true missing reflections # won't be identified as connected as a result of being separated by systematically # absent reflections. cb_op_to_primitive = miller_array.change_of_basis_op_to_primitive_setting() miller_array = miller_array.change_basis(cb_op_to_primitive) # First generate the missing_set of reflections. We want the full sphere of missing # reflections to allow us to find connected regions that cross the boundary of the # asu. unique = miller_array.unique_under_symmetry().map_to_asu() unique = unique.generate_bijvoet_mates() complete_set = unique.complete_set() missing_set = complete_set.lone_set(unique) missing_set = missing_set.expand_to_p1().customized_copy( crystal_symmetry=missing_set.crystal_symmetry()) if missing_set.size() == 0: return complete_set, [] # Now find the nearest neighbours. mi = missing_set.indices().as_vec3_double().as_double() k = 6 ann = AnnAdaptor(data=mi, dim=3, k=k) ann.query(mi) # Construct the graph of connected missing reflections g = graph.adjacency_list( graph_type="undirected", vertex_type="vector", edge_type="set", ) distance_cutoff = 2**0.5 for i in range(missing_set.size()): ik = i * k for i_ann in range(k): if ann.distances[ik + i_ann] <= distance_cutoff: j = ann.nn[ik + i_ann] g.add_edge(i, j) # Now do the connected components analysis, filtering out lone missing reflections components = [c for c in cca.connected_components(graph=g) if len(c) > 1] # Determine the unique miller indices for each component within the asu unique_mi = [] unique_ms = [] for i, c in enumerate(components): ms = (missing_set.select(flex.size_t(list(c))).customized_copy( crystal_symmetry=miller_array).as_non_anomalous_set().map_to_asu()) ms = ms.unique_under_symmetry() mi = set(ms.indices()) if mi not in unique_mi: unique_ms.append(ms) unique_mi.append(mi) # Sort connected regions by size unique_ms = sorted(unique_ms, key=lambda ms: ms.size(), reverse=True) # Map indices back to input setting cb_op_primitive_inp = cb_op_to_primitive.inverse() return ( unique.as_non_anomalous_set().complete_set().change_basis( cb_op_primitive_inp), [ms.change_basis(cb_op_primitive_inp) for ms in unique_ms], )
def __init__(self, pdb_hierarchy, crystal_symmetry, angular_difference_threshold_deg=5., sequence_identity_threshold=90., quiet=False): h = pdb_hierarchy superposition_threshold = 2 * sequence_identity_threshold - 100. n_atoms_all = h.atoms_size() s_str = "altloc ' ' and (protein or nucleotide)" h = h.select(h.atom_selection_cache().selection(s_str)) h1 = iotbx.pdb.hierarchy.root() h1.append_model(h.models()[0].detached_copy()) unit_cell = crystal_symmetry.unit_cell() result = {} if not quiet: print("Find groups of chains related by translational NCS") # double loop over chains to find matching pairs related by pure translation for c1 in h1.chains(): c1.parent().remove_chain(c1) nchains = len(h1.models()[0].chains()) if ([c1.is_protein(), c1.is_na()].count(True) == 0): continue r1 = list(c1.residues()) c1_seq = "".join(c1.as_sequence()) sc_1_tmp = c1.atoms().extract_xyz() h1_p1 = h1.expand_to_p1(crystal_symmetry=crystal_symmetry) for (ii, c2) in enumerate(h1_p1.chains()): orig_c2 = h1.models()[0].chains()[ii % nchains] r2 = list(c2.residues()) c2_seq = "".join(c2.as_sequence()) sites_cart_1, sites_cart_2 = None, None sc_2_tmp = c2.atoms().extract_xyz() # chains are identical if (c1_seq == c2_seq and sc_1_tmp.size() == sc_2_tmp.size()): sites_cart_1 = sc_1_tmp sites_cart_2 = sc_2_tmp p_identity = 100. # chains are not identical, do alignment else: align_obj = mmtbx.alignment.align(seq_a=c1_seq, seq_b=c2_seq) alignment = align_obj.extract_alignment() matches = alignment.matches() equal = matches.count("|") total = len(alignment.a) - alignment.a.count("-") p_identity = 100. * equal / max(1, total) if (p_identity > superposition_threshold): sites_cart_1 = flex.vec3_double() sites_cart_2 = flex.vec3_double() for i1, i2, match in zip(alignment.i_seqs_a, alignment.i_seqs_b, matches): if (i1 is not None and i2 is not None and match == "|"): r1i, r2i = r1[i1], r2[i2] assert r1i.resname == r2i.resname, [ r1i.resname, r2i.resname, i1, i2 ] for a1 in r1i.atoms(): for a2 in r2i.atoms(): if (a1.name == a2.name): sites_cart_1.append(a1.xyz) sites_cart_2.append(a2.xyz) break # superpose two sequence-aligned chains if ([sites_cart_1, sites_cart_2].count(None) == 0): lsq_fit_obj = superpose.least_squares_fit( reference_sites=sites_cart_1, other_sites=sites_cart_2) angle = lsq_fit_obj.r.rotation_angle() t_frac = unit_cell.fractionalize( (sites_cart_1 - sites_cart_2).mean()) t_frac = [math.modf(t)[0] for t in t_frac] # put into [-1,1] radius = flex.sum( flex.sqrt((sites_cart_1 - sites_cart_1.mean() ).dot())) / sites_cart_1.size() * 4. / 3. fracscat = min(c1.atoms_size(), c2.atoms_size()) / n_atoms_all result.setdefault(frozenset([c1, orig_c2]), []).append([ p_identity, [lsq_fit_obj.r, t_frac, angle, radius, fracscat] ]) else: result.setdefault(frozenset([c1, orig_c2]), []).append([p_identity, None]) # Build graph g = graph.adjacency_list() vertex_handle = {} for key in result: seqid = result[key][0][0] sup = min(result[key], key=lambda s: 0 if s[1] is None else s[1][2])[1] result[key] = [seqid, sup] if ((seqid > sequence_identity_threshold) and (sup[2] < angular_difference_threshold_deg)): (c1, c2) = key if (c1 not in vertex_handle): vertex_handle[c1] = g.add_vertex(label=c1) if (c2 not in vertex_handle): vertex_handle[c2] = g.add_vertex(label=c2) g.add_edge(vertex1=vertex_handle[c1], vertex2=vertex_handle[c2]) # Do connected component analysis and compose final tNCS pairs object components = connected_component_algorithm.connected_components(g) import itertools self.ncs_pairs = [] self.tncsresults = [0, "", [], 0.0] for (i, group) in enumerate(components): chains = [g.vertex_label(vertex=v) for v in group] fracscats = [] radii = [] for pair in itertools.combinations(chains, 2): sup = result[frozenset(pair)][1] fracscats.append(sup[-1]) radii.append(sup[-2]) fs = sum(fracscats) / len(fracscats) self.tncsresults[3] = fs # store fracscat in array rad = sum(radii) / len(radii) #import code, traceback; code.interact(local=locals(), banner="".join( traceback.format_stack(limit=10) ) ) maxorder = 1 vectors = [] previous_id = next(itertools.combinations(chains, 2))[0].id for pair in itertools.combinations(chains, 2): sup = result[frozenset(pair)][1] ncs_pair = ext.pair( r=sup[0], t=sup[1], radius=rad, radius_estimate=rad, fracscat=fs, rho_mn=flex.double( ), # rho_mn undefined, needs to be set later id=i) self.ncs_pairs.append(ncs_pair) # show tNCS pairs in group fmt = "group %d chains %s <> %s angle: %4.2f trans.vect.: (%s) fracscat: %5.3f" t = ",".join([("%6.3f" % t_).strip() for t_ in sup[1]]).strip() if not quiet: print(fmt % (i, pair[0].id, pair[1].id, sup[2], t, fs)) if pair[0].id == previous_id: maxorder += 1 orthoxyz = unit_cell.orthogonalize(sup[1]) vectors.append((sup[1], orthoxyz, sup[2])) else: previous_id = pair[0].id maxorder = 1 vectors = [] if maxorder > self.tncsresults[0]: self.tncsresults[0] = maxorder self.tncsresults[1] = previous_id self.tncsresults[2] = vectors if not quiet: print("Largest TNCS order, peptide chain, fracvector, orthvector, angle, fracscat = ", \ str(self.tncsresults))
def _InteractionGraphAABB(movers, extraAtomInfoMap, probeRadius=0.25): """Uses the overlap of the axis-aligned bounding boxes (AABBs) of all possible positions of all movable atoms in the set of movers passed in to construct the graph of which might overlap across all possible orientations of each. The use of bounding boxes makes this an overestimate but its time complexity is linear in the product of the number of movers times the number of atoms times the number of possible positions for each and quadratic in the number of Movers. :param movers: flex array of movers to add to the graph. Note that this list must not be modified after the graph has been constructed because that will change the index of its elements, making the graph point to the wrong elements (or to elements that no longer exist). :param extraAtomInfoMap: probe.ExtraAtomInfoMap that can be used to look up the information for atoms whose values need to be changed. Can be obtained by calling mmtbx.probe.Helpers.getExtraAtomInfo(). :param probeRadius: Radius of the probe to use to determine neighbor contact. If it is not set, the default value of 0.25 will be used. :returns An undirected Boost graph whose nodes are indices into the movers list and whose edges indicate which Movers might overlap in any of their states. Note that the mover list must not be modified after the graph has been constructed because that will change the index of its elements, making the graph point to the wrong elements (or to elements that no longer exist). """ pr = probeRadius # Add all of the Movers as nodes in the graph # Compute the axis-aligned bounding box for each Mover ret = graph.adjacency_list( vertex_type= "list", # List so that deletions do not invalidate iterators and descriptors ) AABBs = [] verts = [] for m in movers: verts.append(ret.add_vertex(m)) # Find all possible positions, coarse and fine. coarses = m.CoarsePositions() atoms = coarses.atoms coarsePositions = coarses.positions total = coarsePositions[:] for c in range(len(coarsePositions)): total.extend(m.FinePositions(c).positions) # Find the range of positions of all atoms in X, Y, and Z xRange = [1e10, -1e10] yRange = [1e10, -1e10] zRange = [1e10, -1e10] for pos in total: for i, atomLoc in enumerate(pos): # Find the radius of the atom, which is used to extend it in all directions # so that we catch all potential overlaps. r = extraAtomInfoMap.getMappingFor(atoms[i]).vdwRadius x = atomLoc[0] xRange[0] = min(xRange[0], x - r) xRange[1] = max(xRange[1], x + r) y = atomLoc[1] yRange[0] = min(yRange[0], y - r) yRange[1] = max(yRange[1], y + r) z = atomLoc[2] zRange[0] = min(zRange[0], z - r) zRange[1] = max(zRange[1], z + r) # Dilate the bounding box by the radius of the probe. # Because we're dilating each box by this radius, we're properly # checking to twice the probe radius between two Movers. xRange = [xRange[0] - pr, xRange[1] + pr] yRange = [yRange[0] - pr, yRange[1] + pr] zRange = [zRange[0] - pr, zRange[1] + pr] # Store the bounding boxes for this Mover AABBs.append([xRange, yRange, zRange]) # For each pair of Movers whose bounding boxes overlap, add an # edge to the graph. We add them based on their indices. for i in range(len(movers) - 1): for j in range(i + 1, len(movers)): if _AABBOverlap(AABBs[i], AABBs[j]): ret.add_edge(vertex1=verts[i], vertex2=verts[j]) return ret
def __init__(self, pdb_hierarchy, crystal_symmetry, angular_difference_threshold_deg=5., sequence_identity_threshold=90.): h = pdb_hierarchy superposition_threshold = 2*sequence_identity_threshold - 100. n_atoms_all = h.atoms_size() s_str = "altloc ' ' and (protein or nucleotide)" h = h.select(h.atom_selection_cache().selection(s_str)) h1 = iotbx.pdb.hierarchy.root() h1.append_model(h.models()[0].detached_copy()) unit_cell = crystal_symmetry.unit_cell() result = {} print "Find groups of chains related by translational NCS" # double loop over chains to find matching pairs related by pure translation for c1 in h1.chains(): c1.parent().remove_chain(c1) nchains = len(h1.models()[0].chains()) if([c1.is_protein(), c1.is_na()].count(True)==0): continue r1 = list(c1.residues()) c1_seq = "".join(c1.as_sequence()) sc_1_tmp = c1.atoms().extract_xyz() h1_p1 = h1.expand_to_p1(crystal_symmetry=crystal_symmetry) for (ii,c2) in enumerate(h1_p1.chains()): orig_c2 = h1.models()[0].chains()[ii%nchains] r2 = list(c2.residues()) c2_seq = "".join(c2.as_sequence()) sites_cart_1, sites_cart_2 = None,None sc_2_tmp = c2.atoms().extract_xyz() # chains are identical if(c1_seq==c2_seq and sc_1_tmp.size()==sc_2_tmp.size()): sites_cart_1 = sc_1_tmp sites_cart_2 = sc_2_tmp p_identity = 100. # chains are not identical, do alignment else: align_obj = mmtbx.alignment.align(seq_a = c1_seq, seq_b = c2_seq) alignment = align_obj.extract_alignment() matches = alignment.matches() equal = matches.count("|") total = len(alignment.a) - alignment.a.count("-") p_identity = 100.*equal/max(1,total) if(p_identity>superposition_threshold): sites_cart_1 = flex.vec3_double() sites_cart_2 = flex.vec3_double() for i1, i2, match in zip(alignment.i_seqs_a, alignment.i_seqs_b, matches): if(i1 is not None and i2 is not None and match=="|"): r1i, r2i = r1[i1], r2[i2] assert r1i.resname==r2i.resname, [r1i.resname,r2i.resname,i1,i2] for a1 in r1i.atoms(): for a2 in r2i.atoms(): if(a1.name == a2.name): sites_cart_1.append(a1.xyz) sites_cart_2.append(a2.xyz) break # superpose two sequence-aligned chains if([sites_cart_1,sites_cart_2].count(None)==0): lsq_fit_obj = superpose.least_squares_fit( reference_sites = sites_cart_1, other_sites = sites_cart_2) angle = lsq_fit_obj.r.rotation_angle() t_frac = unit_cell.fractionalize((sites_cart_1-sites_cart_2).mean()) t_frac = [math.modf(t)[0] for t in t_frac] # put into [-1,1] radius = flex.sum(flex.sqrt((sites_cart_1- sites_cart_1.mean()).dot()))/sites_cart_1.size()*4./3. fracscat = min(c1.atoms_size(),c2.atoms_size())/n_atoms_all result.setdefault( frozenset([c1,orig_c2]), [] ).append( [p_identity,[lsq_fit_obj.r, t_frac, angle, radius, fracscat]] ) else: result.setdefault( frozenset([c1,orig_c2]), [] ).append( [p_identity,None] ) # Build graph g = graph.adjacency_list() vertex_handle = {} for key in result: seqid = result[key][0][0] sup = min( result[key],key=lambda s:0 if s[1] is None else s[1][2])[1] result[key] = [seqid,sup] if ((seqid > sequence_identity_threshold) and (sup[2] < angular_difference_threshold_deg)): (c1,c2) = key if (c1 not in vertex_handle): vertex_handle[c1] = g.add_vertex(label=c1) if (c2 not in vertex_handle): vertex_handle[c2] = g.add_vertex(label=c2) g.add_edge(vertex1=vertex_handle[c1],vertex2=vertex_handle[c2]) # Do connected component analysis and compose final tNCS pairs object components = connected_component_algorithm.connected_components(g) import itertools self.ncs_pairs = [] for (i,group) in enumerate(components): chains = [g.vertex_label(vertex=v) for v in group] fracscats = [] radii = [] for pair in itertools.combinations(chains,2): sup = result[frozenset(pair)][1] fracscats.append(sup[-1]) radii.append(sup[-2]) fs = sum(fracscats)/len(fracscats) rad = sum(radii)/len(radii) for pair in itertools.combinations(chains,2): sup = result[frozenset(pair)][1] ncs_pair = ext.pair( r = sup[0], t = sup[1], radius = rad, radius_estimate = rad, fracscat = fs, rho_mn = flex.double(), # rho_mn undefined, needs to be set later id = i) self.ncs_pairs.append(ncs_pair) # show tNCS pairs in group fmt="group %d chains %s <> %s angle: %4.2f trans.vect.: (%s) fracscat: %5.3f" t = ",".join([("%6.3f"%t_).strip() for t_ in sup[1]]).strip() print fmt%(i, pair[0].id, pair[1].id, sup[2], t, fs)