3 """@namespace IMP.pmi.tools
4 Miscellaneous utilities.
12 from collections.abc
import MutableSet
16 from time
import process_time
19 from collections
import defaultdict, OrderedDict
24 def _get_system_for_hier(hier):
25 """Given a hierarchy, return the System that created it, or None"""
28 if hier
and not hasattr(hier,
'get_parent'):
35 if hasattr(hier,
'_pmi2_system'):
36 h = hier._pmi2_system()
41 for s
in IMP.pmi.topology.System._all_systems:
45 hier = hier.get_parent()
48 def _all_protocol_outputs(hier):
49 """Iterate over all (ProtocolOutput, State) pairs for the
51 system = _get_system_for_hier(hier)
53 for state
in system.states:
54 for p
in state._protocol_output:
58 def _add_pmi_provenance(p):
59 """Tag the given particle as being created by the current version
64 location=
"https://integrativemodeling.org")
68 def _get_restraint_set_keys():
69 if not hasattr(_get_restraint_set_keys,
'pmi_rs_key'):
70 _get_restraint_set_keys.pmi_rs_key =
IMP.ModelKey(
"PMI restraints")
71 _get_restraint_set_keys.rmf_rs_key =
IMP.ModelKey(
"RMF restraints")
72 return (_get_restraint_set_keys.pmi_rs_key,
73 _get_restraint_set_keys.rmf_rs_key)
76 def _add_restraint_sets(model, mk, mk_rmf):
79 model.add_data(mk, rs)
80 model.add_data(mk_rmf, rs_rmf)
85 """Add a PMI restraint to the model.
86 Since Model.add_restraint() no longer exists (in modern IMP restraints
87 should be added to a ScoringFunction instead) store them instead in
88 a RestraintSet, and keep a reference to it in the Model.
90 If `add_to_rmf` is True, also add the restraint to a separate list
91 of restraints that will be written out to RMF files (by default, most
92 PMI restraints are not)."""
93 mk, mk_rmf = _get_restraint_set_keys()
94 if model.get_has_data(mk):
95 rs = IMP.RestraintSet.get_from(model.get_data(mk))
96 rs_rmf = IMP.RestraintSet.get_from(model.get_data(mk_rmf))
98 rs, rs_rmf = _add_restraint_sets(model, mk, mk_rmf)
99 rs.add_restraint(restraint)
101 rs_rmf.add_restraint(restraint)
105 """Get a RestraintSet containing all PMI restraints added to the model.
106 If `rmf` is True, return only the subset of these restraints that
107 should be written out to RMF files."""
108 mk, mk_rmf = _get_restraint_set_keys()
109 if not model.get_has_data(mk):
110 warnings.warn(
"no restraints added to model yet",
112 _add_restraint_sets(model, mk, mk_rmf)
114 return IMP.RestraintSet.get_from(model.get_data(mk_rmf))
116 return IMP.RestraintSet.get_from(model.get_data(mk))
120 """Collect timing information.
121 Add an instance of this class to outputobjects to get timing information
126 @param isdelta if True (the default) then report the time since the
127 last use of this class; if False, report cumulative time."""
128 self.starttime = process_time()
130 self.isdelta = isdelta
132 def set_label(self, labelstr):
133 self.label = labelstr
135 def get_output(self):
138 newtime = process_time()
139 output[
"Stopwatch_" + self.label +
"_delta_seconds"] \
140 = str(newtime - self.starttime)
141 self.starttime = newtime
143 output[
"Stopwatch_" + self.label +
"_elapsed_seconds"] \
144 = str(process_time() - self.starttime)
150 def __init__(self, m, initialvalue, minvalue, maxvalue, isoptimized=True,
158 nuisance.set_lower(minvalue)
160 nuisance.set_upper(maxvalue)
163 nuisance.set_is_optimized(nuisance.get_nuisance_key(), isoptimized)
164 self.nuisance = nuisance
166 def get_particle(self):
172 def __init__(self, m, isoptimized=True, nweights_or_weights=None):
174 if isinstance(nweights_or_weights, int):
176 pw, nweights_or_weights
180 nweights_or_weights = list(nweights_or_weights)
182 pw, nweights_or_weights
186 self.weight.set_weights_are_optimized(isoptimized)
188 def get_particle(self):
194 def __init__(self, m, center, normal, isoptimized=True):
197 self.surface.set_coordinates_are_optimized(isoptimized)
198 self.surface.set_normal_is_optimized(isoptimized)
200 def get_particle(self):
204 def get_cross_link_data(directory, filename, dist, omega, sigma,
205 don=
None, doff=
None, prior=0, type_of_profile=
"gofr"):
207 (distmin, distmax, ndist) = dist
208 (omegamin, omegamax, nomega) = omega
209 (sigmamin, sigmamax, nsigma) = sigma
212 with open(filen)
as xlpot:
213 dictionary = ast.literal_eval(xlpot.readline())
215 xpot = dictionary[directory][filename][
"distance"]
216 pot = dictionary[directory][filename][type_of_profile]
218 dist_grid =
get_grid(distmin, distmax, ndist,
False)
219 omega_grid = get_log_grid(omegamin, omegamax, nomega)
220 sigma_grid = get_log_grid(sigmamin, sigmamax, nsigma)
222 if don
is not None and doff
is not None:
242 def get_grid(gmin, gmax, ngrid, boundaries):
244 dx = (gmax - gmin) / float(ngrid)
245 for i
in range(0, ngrid + 1):
246 if not boundaries
and i == 0:
248 if not boundaries
and i == ngrid:
250 grid.append(gmin + float(i) * dx)
254 def get_log_grid(gmin, gmax, ngrid):
256 for i
in range(0, ngrid + 1):
257 grid.append(gmin * math.exp(float(i) / ngrid * math.log(gmax / gmin)))
263 example '"{ID_Score}" > 28 AND "{Sample}" ==
264 "%10_1%" OR ":Sample}" == "%10_2%" OR ":Sample}"
265 == "%10_3%" OR ":Sample}" == "%8_1%" OR ":Sample}" == "%8_2%"'
268 import pyparsing
as pp
270 operator = pp.Regex(
">=|<=|!=|>|<|==|in").setName(
"operator")
271 value = pp.QuotedString(
273 r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?")
274 identifier = pp.Word(pp.alphas, pp.alphanums +
"_")
275 comparison_term = identifier | value
276 condition = pp.Group(comparison_term + operator + comparison_term)
278 expr = pp.operatorPrecedence(condition, [
279 (
"OR", 2, pp.opAssoc.LEFT, ),
280 (
"AND", 2, pp.opAssoc.LEFT, ),
283 parsedstring = str(expr.parseString(inputstring)) \
289 .replace(
"{",
"float(entry['") \
290 .replace(
"}",
"'])") \
291 .replace(
":",
"str(entry['") \
292 .replace(
"}",
"'])") \
293 .replace(
"AND",
"and") \
298 def open_file_or_inline_text(filename):
300 fl = open(filename,
"r")
302 fl = filename.split(
"\n")
306 def get_ids_from_fasta_file(fastafile):
308 with open(fastafile)
as ff:
311 ids.append(line[1:-1])
317 this function works with plain hierarchies, as read from the pdb,
318 no multi-scale hierarchies
325 atom_type=IMP.atom.AT_CA)
333 print(
"get_closest_residue_position: exiting while loop "
336 p = sel.get_selected_particles()
341 print(
"get_closest_residue_position: got NO residues for hierarchy "
342 "%s and residue %i" % (hier, resindex))
344 "get_closest_residue_position: got NO residues for hierarchy "
345 "%s and residue %i" % (hier, resindex))
348 "got multiple residues for hierarchy %s and residue %i; the list "
350 % (hier, resindex, str([pp.get_name()
for pp
in p])))
355 Return the residue index gaps and contiguous segments in the hierarchy.
357 @param hierarchy hierarchy to examine
358 @param start first residue index
359 @param end last residue index
361 @return A list of lists of the form
362 [[1,100,"cont"],[101,120,"gap"],[121,200,"cont"]]
365 for n, rindex
in enumerate(range(start, end + 1)):
367 atom_type=IMP.atom.AT_CA)
369 if len(sel.get_selected_particles()) == 0:
373 rindexcont = start - 1
374 if rindexgap == rindex - 1:
380 gaps.append([rindex, rindex,
"gap"])
386 rindexgap = start - 1
388 if rindexcont == rindex - 1:
395 gaps.append([rindex, rindex,
"cont"])
406 def set_map_element(self, xvalue, yvalue):
407 self.map[xvalue] = yvalue
409 def get_map_element(self, invalue):
410 if isinstance(invalue, float):
414 dist = (invalue - x) * (invalue - x)
423 return self.map[minx]
424 elif isinstance(invalue, str):
425 return self.map[invalue]
427 raise TypeError(
"wrong type for map")
431 """New tuple format: molname OR (start,stop,molname,copynum,statenum)
432 Copy and state are optional. Can also use 'None' for them which will
433 get all. You can also pass -1 for stop which will go to the end.
434 Returns the particles
437 kwds[
'resolution'] = resolution
438 if isinstance(tuple_selection, str):
439 kwds[
'molecule'] = tuple_selection
440 elif isinstance(tuple_selection, tuple):
441 rbegin = tuple_selection[0]
442 rend = tuple_selection[1]
443 kwds[
'molecule'] = tuple_selection[2]
445 copynum = tuple_selection[3]
446 if copynum
is not None:
447 kwds[
'copy_index'] = copynum
451 statenum = tuple_selection[4]
452 if statenum
is not None:
453 kwds[
'state_index'] = statenum
460 residue_indexes=range(1, rbegin),
462 return s.get_selected_particles()
464 kwds[
'residue_indexes'] = range(rbegin, rend+1)
466 return s.get_selected_particles()
469 def get_db_from_csv(csvfilename, encoding=None):
472 with open(csvfilename, encoding=encoding)
as fh:
473 csvr = csv.DictReader(fh)
475 outputlist.append(ls)
480 '''Return the component name provided a particle and a list of names'''
482 protname = root.get_name()
484 while protname
not in list_of_names:
485 root0 = root.get_parent()
488 protname = root0.get_name()
493 if "Beads" in protname:
496 return (protname, is_a_bead)
501 Retrieve the residue indexes for the given particle.
503 The particle must be an instance of Fragment,Residue, Atom or Molecule
504 or else returns an empty list
515 resind_tmp = IMP.pmi.tools.OrderedSet()
522 resind = list(resind_tmp)
528 def sort_by_residues(particles):
531 sorted_particles_residues = sorted(
533 key=
lambda tup: tup[1])
534 particles = [p[0]
for p
in sorted_particles_residues]
543 """Synchronize data over a parallel run"""
544 from mpi4py
import MPI
545 comm = MPI.COMM_WORLD
546 rank = comm.Get_rank()
547 number_of_processes = comm.size
550 comm.send(data, dest=0, tag=11)
553 for i
in range(1, number_of_processes):
554 data_tmp = comm.recv(source=i, tag=11)
555 if isinstance(data, list):
557 elif isinstance(data, dict):
558 data.update(data_tmp)
560 raise TypeError(
"data not supported, use list or dictionaries")
562 for i
in range(1, number_of_processes):
563 comm.send(data, dest=i, tag=11)
566 data = comm.recv(source=0, tag=11)
576 Yield all sublists of length >= lmin and <= lmax
582 for j
in range(i + lmin, min(n + 1, i + 1 + lmax)):
586 def flatten_list(ls):
587 return [item
for sublist
in ls
for item
in sublist]
591 """ Yield successive length-sized chunks from a list.
593 for i
in range(0, len(list), length):
594 yield list[i:i + length]
597 def chunk_list_into_segments(seq, num):
599 avg = len(seq) / float(num)
603 while last < len(seq):
604 out.append(seq[int(last):int(last + avg)])
612 ''' This class stores integers
613 in ordered compact lists eg:
615 the methods help splitting and merging the internal lists
617 s=Segments([1,2,3]) is [[1,2,3]]
618 s.add(4) is [[1,2,3,4]] (add right)
619 s.add(3) is [[1,2,3,4]] (item already existing)
620 s.add(7) is [[1,2,3,4],[7]] (new list)
621 s.add([8,9]) is [[1,2,3,4],[7,8,9]] (add item right)
622 s.add([5,6]) is [[1,2,3,4,5,6,7,8,9]] (merge)
623 s.remove(3) is [[1,2],[4,5,6,7,8,9]] (split)
628 '''index can be a integer or a list of integers '''
629 if isinstance(index, int):
630 self.segs = [[index]]
631 elif isinstance(index, list):
632 self.segs = [[index[0]]]
636 raise TypeError(
"index must be an int or list of ints")
639 '''index can be a integer or a list of integers '''
640 if isinstance(index, numbers.Integral):
643 for n, s
in enumerate(self.segs):
651 if mergeright
is None and mergeleft
is None:
652 self.segs.append([index])
653 if mergeright
is not None and mergeleft
is None:
654 self.segs[mergeright].append(index)
655 if mergeleft
is not None and mergeright
is None:
656 self.segs[mergeleft] = [index]+self.segs[mergeleft]
657 if mergeleft
is not None and mergeright
is not None:
658 self.segs[mergeright] = \
659 self.segs[mergeright]+[index]+self.segs[mergeleft]
660 del self.segs[mergeleft]
662 for n
in range(len(self.segs)):
665 self.segs.sort(key=
lambda tup: tup[0])
667 elif isinstance(index, list):
671 raise TypeError(
"index must be an int or list of ints")
674 '''index can be a integer'''
675 for n, s
in enumerate(self.segs):
680 self.segs[n] = s[:-1]
682 i = self.segs[n].index(index)
684 self.segs.append(s[i+1:])
685 for n
in range(len(self.segs)):
687 if len(self.segs[n]) == 0:
689 self.segs.sort(key=
lambda tup: tup[0])
692 ''' Returns a flatten list '''
693 return [item
for sublist
in self.segs
for item
in sublist]
697 for seg
in self.segs:
698 ret_tmp += str(seg[0])+
"-"+str(seg[-1])+
","
699 ret = ret_tmp[:-1]+
"]"
707 def normal_density_function(expected_value, sigma, x):
709 1 / math.sqrt(2 * math.pi) / sigma *
710 math.exp(-(x - expected_value) ** 2 / 2 / sigma / sigma)
714 def log_normal_density_function(expected_value, sigma, x):
716 1 / math.sqrt(2 * math.pi) / sigma / x *
717 math.exp(-(math.log(x / expected_value) ** 2 / 2 / sigma / sigma))
721 def print_multicolumn(list_of_strings, ncolumns=2, truncate=40):
727 for i
in range(len(ls) % cols):
730 split = [ls[i:i + len(ls) // cols]
731 for i
in range(0, len(ls), len(ls) // cols)]
732 for row
in zip(*split):
733 print(
"".join(str.ljust(i, truncate)
for i
in row))
737 '''Change color code to hexadecimal to rgb'''
739 self._NUMERALS =
'0123456789abcdefABCDEF'
740 self._HEXDEC = dict((v, int(v, 16))
for v
in
741 (x+y
for x
in self._NUMERALS
742 for y
in self._NUMERALS))
743 self.LOWERCASE, self.UPPERCASE =
'x',
'X'
745 def rgb(self, triplet):
746 return (float(self._HEXDEC[triplet[0:2]]),
747 float(self._HEXDEC[triplet[2:4]]),
748 float(self._HEXDEC[triplet[4:6]]))
750 def triplet(self, rgb, lettercase=None):
751 if lettercase
is None:
752 lettercase = self.LOWERCASE
753 return format(rgb[0] << 16 | rgb[1] << 8 | rgb[2],
'06'+lettercase)
757 class OrderedSet(MutableSet):
759 def __init__(self, iterable=None):
761 end += [
None, end, end]
763 if iterable
is not None:
769 def __contains__(self, key):
770 return key
in self.map
773 if key
not in self.map:
776 curr[2] = end[1] = self.map[key] = [key, curr, end]
778 def discard(self, key):
780 key, prev, next = self.map.pop(key)
787 while curr
is not end:
791 def __reversed__(self):
794 while curr
is not end:
798 def pop(self, last=True):
800 raise KeyError(
'set is empty')
810 return '%s()' % (self.__class__.__name__,)
811 return '%s(%r)' % (self.__class__.__name__, list(self))
813 def __eq__(self, other):
814 if isinstance(other, OrderedSet):
815 return len(self) == len(other)
and list(self) == list(other)
816 return set(self) == set(other)
820 """Store objects in order they were added, but with default type.
821 Source: http://stackoverflow.com/a/4127426/2608793
823 def __init__(self, *args, **kwargs):
825 self.default_factory =
None
827 if not (args[0]
is None or callable(args[0])):
828 raise TypeError(
'first argument must be callable or None')
829 self.default_factory = args[0]
831 super().__init__(*args, **kwargs)
833 def __missing__(self, key):
834 if self.default_factory
is None:
836 self[key] = default = self.default_factory()
839 def __reduce__(self):
840 args = (self.default_factory,)
if self.default_factory
else ()
841 return self.__class__, args,
None,
None, self.items()
847 """Extract frame from RMF file and fill coordinates. Must be identical
850 @param hier The (System) hierarchy to fill (e.g. after you've built it)
851 @param rmf_fn The file to extract from
852 @param frame_num The frame number to extract
854 rh = RMF.open_rmf_file_read_only(rmf_fn)
860 def input_adaptor(stuff, pmi_resolution=0, flatten=False, selection_tuple=None,
861 warn_about_slices=
True):
862 """Adapt things for PMI (degrees of freedom, restraints, ...)
863 Returns list of list of hierarchies, separated into Molecules if possible.
864 The input can be a list, or a list of lists (iterable of ^1 or
866 (iterable of ^2) Hierarchy -> returns input as list of list of hierarchies,
867 only one entry, not grouped by molecules.
868 (iterable of ^2) PMI::System/State/Molecule/TempResidue ->
869 returns residue hierarchies, grouped in molecules, at requested
872 @param stuff Can be one of the following inputs:
873 IMP Hierarchy, PMI System/State/Molecule/TempResidue, or a
874 list/set (of list/set) of them.
875 Must be uniform input, however. No mixing object types.
876 @param pmi_resolution For selecting, only does it if you pass PMI
877 objects. Set it to "all" if you want all resolutions!
878 @param flatten Set to True if you just want all hierarchies in one list.
879 @param warn_about_slices Print a warning if you are requesting only part
880 of a bead. Sometimes you just don't care!
881 @note since this relies on IMP::atom::Selection, this will not return
882 any objects if they weren't built! But there should be no problem
883 if you request unbuilt residues - they should be ignored.
889 if hasattr(stuff,
'__iter__'):
892 thelist = list(stuff)
895 if all(hasattr(el,
'__iter__')
for el
in thelist):
896 thelist = [i
for sublist
in thelist
for i
in sublist]
897 elif any(hasattr(el,
'__iter__')
for el
in thelist):
898 raise Exception(
'input_adaptor: input_object must be a list '
899 'or a list of lists')
908 except (NotImplementedError, TypeError):
920 if is_system
or is_state
or is_molecule
or is_temp_residue:
927 for state
in system.get_states():
928 mdict = state.get_molecules()
929 for molname
in mdict:
930 for copy
in mdict[molname]:
931 indexes_per_mol[copy] += \
932 [r.get_index()
for r
in copy.get_residues()]
935 mdict = state.get_molecules()
936 for molname
in mdict:
937 for copy
in mdict[molname]:
938 indexes_per_mol[copy] += [r.get_index()
939 for r
in copy.get_residues()]
941 for molecule
in stuff:
942 indexes_per_mol[molecule] += [r.get_index()
943 for r
in molecule.get_residues()]
945 for tempres
in stuff:
946 indexes_per_mol[tempres.get_molecule()].append(
948 for mol
in indexes_per_mol:
949 if pmi_resolution ==
'all':
953 mol.get_hierarchy(), residue_indexes=indexes_per_mol[mol])
956 resolution=pmi_resolution,
957 residue_indexes=indexes_per_mol[mol])
958 ps = sel.get_selected_particles()
961 if warn_about_slices:
962 rset = set(indexes_per_mol[mol])
972 resbreak = maxf
if minf == minset
else minset-1
974 'You are trying to select only part of the '
975 'bead %s:%i-%i. The residues you requested '
976 'are %i-%i. You can fix this by: '
977 '1) requesting the whole bead/none of it; or'
978 '2) break the bead up by passing '
979 'bead_extra_breaks=[\'%i\'] in '
980 'molecule.add_representation()'
981 % (mol.get_name(), minset, maxset, minf, maxf,
987 if pmi_resolution ==
'all':
993 h, resolution=pmi_resolution).get_selected_particles()
996 hier_list = [hier_list]
998 raise Exception(
'input_adaptor: you passed something of wrong type '
999 'or a list with mixed types')
1001 if flatten
and pmi_input:
1002 return [h
for sublist
in hier_list
for h
in sublist]
1008 """Returns sequence-sorted segments array, each containing the first
1009 particle the last particle and the first residue index."""
1011 from operator
import itemgetter
1014 raise ValueError(
"only pass stuff from one Molecule, please")
1029 segs.append((start, end, startres))
1030 return sorted(segs, key=itemgetter(2))
1034 """Decorate the sequence-consecutive particles from a PMI2 molecule
1035 with a bond, so that they appear connected in the rmf file"""
1037 for x
in range(len(SortedSegments) - 1):
1039 last = SortedSegments[x][1]
1040 first = SortedSegments[x + 1][0]
1042 p1 = last.get_particle()
1043 p2 = first.get_particle()
1056 """ Just get the leaves from a list of hierarchies """
1057 lvs = list(itertools.chain.from_iterable(
1063 """Perform selection using the usual keywords but return ALL
1064 resolutions (BEADS and GAUSSIANS).
1065 Returns in flat list!
1070 if hier
is not None:
1073 warnings.warn(
"You passed nothing to select_at_all_resolutions()",
1081 raise Exception(
'select_at_all_resolutions: you have to pass '
1084 raise Exception(
'select_at_all_resolutions: you have to pass '
1086 if 'resolution' in kwargs
or 'representation_type' in kwargs:
1087 raise Exception(
"don't pass resolution or representation_type "
1090 representation_type=IMP.atom.BALLS,
1093 representation_type=IMP.atom.DENSITIES,
1095 ret |= OrderedSet(selB.get_selected_particles())
1096 ret |= OrderedSet(selD.get_selected_particles())
1105 """Utility to retrieve particles from a hierarchy within a
1106 zone around a set of ps.
1107 @param hier The hierarchy in which to look for neighbors
1108 @param target_ps The particles for zoning
1109 @param sel_zone The maximum distance
1110 @param entire_residues If True, will grab entire residues
1111 @param exclude_backbone If True, will only return sidechain particles
1115 backbone_types = [
'C',
'N',
'CB',
'O']
1116 if exclude_backbone:
1119 test_ps = test_sel.get_selected_particles()
1120 nn = IMP.algebra.NearestNeighbor3D([
IMP.core.XYZ(p).get_coordinates()
1123 for target
in target_ps:
1124 zone |= set(nn.get_in_ball(
IMP.core.XYZ(target).get_coordinates(),
1126 zone_ps = [test_ps[z]
for z
in zone]
1131 zone_ps = [h.get_particle()
for h
in final_ps]
1136 """Returns unique objects in original order"""
1140 if not hasattr(hiers,
'__iter__'):
1147 rbs_ordered.append(rb)
1152 rbs_ordered.append(rb)
1156 return rbs_ordered, beads
1160 "This function returns the parent molecule hierarchies of given objects"
1161 stuff =
input_adaptor(input_objects, pmi_resolution=
'all', flatten=
True)
1166 while not (is_molecule
or is_root):
1167 root = IMP.atom.get_root(h)
1174 return list(molecules)
1177 def get_molecules_dictionary(input_objects):
1178 moldict = defaultdict(list)
1180 name = mol.get_name()
1181 moldict[name].append(mol)
1188 def get_molecules_dictionary_by_copy(input_objects):
1189 moldict = defaultdict(dict)
1191 name = mol.get_name()
1193 moldict[name][c] = mol
1197 def get_selections_dictionary(input_objects):
1198 moldict = IMP.pmi.tools.get_molecules_dictionary(input_objects)
1199 seldict = defaultdict(list)
1200 for name, mols
in moldict.items():
1207 """Given a list of PMI objects, returns all density hierarchies within
1208 these objects. The output of this function can be inputted into
1209 things such as EM restraints. This function is intended to gather
1210 density particles appended to molecules (and not other hierarchies
1211 which might have been appended to the root node directly).
1220 i, representation_type=IMP.atom.DENSITIES).get_selected_particles()
1225 max_translation=300., max_rotation=2.0 * math.pi,
1226 avoidcollision_rb=
True, avoidcollision_fb=
False,
1227 cutoff=10.0, niterations=100,
1229 excluded_rigid_bodies=[],
1230 hierarchies_excluded_from_collision=[],
1231 hierarchies_included_in_collision=[],
1233 return_debug=
False):
1234 """Shuffle particles. Used to restart the optimization.
1235 The configuration of the system is initialized by placing each
1236 rigid body and each bead randomly in a box. If `bounding_box` is
1237 specified, the particles are placed inside this box; otherwise, each
1238 particle is displaced by up to max_translation angstroms, and randomly
1239 rotated. Effort is made to place particles far enough from each other to
1240 prevent any steric clashes.
1241 @param objects Can be one of the following inputs:
1242 IMP Hierarchy, PMI System/State/Molecule/TempResidue, or
1244 @param max_translation Max translation (rbs and flexible beads)
1245 @param max_rotation Max rotation (rbs only)
1246 @param avoidcollision_rb check if the particle/rigid body was
1247 placed close to another particle; uses the optional
1248 arguments cutoff and niterations
1249 @param avoidcollision_fb Advanced. Generally you want this False because
1250 it's hard to shuffle beads.
1251 @param cutoff Distance less than this is a collision
1252 @param niterations How many times to try avoiding collision
1253 @param bounding_box Only shuffle particles within this box.
1254 Defined by ((x1,y1,z1),(x2,y2,z2)).
1255 @param excluded_rigid_bodies Don't shuffle these rigid body objects
1256 @param hierarchies_excluded_from_collision Don't count collision
1258 @param hierarchies_included_in_collision Hierarchies that are not
1259 shuffled, but should be included in collision calculation
1261 @param verbose Give more output
1262 @note Best to only call this function after you've set up degrees
1264 For debugging purposes, returns: <shuffled indexes>,
1265 <collision avoided indexes>
1270 pmi_resolution=
'all',
1273 if len(rigid_bodies) > 0:
1274 mdl = rigid_bodies[0].get_model()
1275 elif len(flexible_beads) > 0:
1276 mdl = flexible_beads[0].get_model()
1278 raise Exception(
"Could not find any particles in the hierarchy")
1279 if len(rigid_bodies) == 0:
1280 print(
"shuffle_configuration: rigid bodies were not initialized")
1284 gcpf.set_distance(cutoff)
1288 hierarchies_excluded_from_collision, pmi_resolution=
'all',
1292 hierarchies_included_in_collision, pmi_resolution=
'all', flatten=
True)
1294 collision_excluded_idxs = set(
1296 for h
in collision_excluded_hierarchies
1299 collision_included_idxs = set(
1301 for h
in collision_included_hierarchies
1308 all_idxs.append(p.get_particle_index())
1310 collision_excluded_idxs.add(p.get_particle_index())
1312 if bounding_box
is not None:
1313 ((x1, y1, z1), (x2, y2, z2)) = bounding_box
1318 all_idxs = set(all_idxs) | collision_included_idxs
1319 all_idxs = all_idxs - collision_excluded_idxs
1321 print(
'shuffling', len(rigid_bodies),
'rigid bodies')
1322 for rb
in rigid_bodies:
1323 if rb
not in excluded_rigid_bodies:
1325 if avoidcollision_rb:
1326 rb_idxs = set(rb.get_member_particle_indexes()) - \
1327 collision_excluded_idxs
1328 other_idxs = all_idxs - rb_idxs
1330 debug.append([rb, other_idxs
if avoidcollision_rb
else set()])
1333 while niter < niterations:
1334 rbxyz = (rb.get_x(), rb.get_y(), rb.get_z())
1351 rbxyz, max_translation, max_rotation)
1356 if avoidcollision_rb
and other_idxs:
1358 npairs = len(gcpf.get_close_pairs(mdl,
1366 print(
"shuffle_configuration: rigid body placed "
1367 "close to other %d particles, trying "
1368 "again..." % npairs)
1369 print(
"shuffle_configuration: rigid body name: "
1371 if niter == niterations:
1373 "tried the maximum number of iterations to "
1374 "avoid collisions, increase the distance "
1379 print(
'shuffling', len(flexible_beads),
'flexible beads')
1380 for fb
in flexible_beads:
1382 if avoidcollision_fb:
1384 other_idxs = all_idxs - fb_idxs
1390 while niter < niterations:
1397 fbxyz, max_translation, max_rotation)
1402 xyz = memb.get_internal_coordinates()
1407 rf = memb.get_rigid_body().get_reference_frame()
1408 glob_to_int = rf.get_transformation_from()
1409 memb.set_internal_coordinates(
1410 glob_to_int.get_transformed(translation))
1412 xyz_transformed = transformation.get_transformed(xyz)
1413 memb.set_internal_coordinates(xyz_transformed)
1416 [xyz, other_idxs
if avoidcollision_fb
else set()])
1424 -d.get_coordinates())
1430 [d, other_idxs
if avoidcollision_fb
else set()])
1437 if avoidcollision_fb:
1439 npairs = len(gcpf.get_close_pairs(mdl,
1447 print(
"shuffle_configuration: floppy body placed close "
1448 "to other %d particles, trying again..." % npairs)
1449 if niter == niterations:
1451 "tried the maximum number of iterations to avoid "
1452 "collisions, increase the distance cutoff")
1459 class ColorHierarchy:
1461 def __init__(self, hier):
1462 import matplotlib
as mpl
1464 import matplotlib.pyplot
as plt
1468 hier.ColorHierarchy = self
1473 self.method = self.nochange
1481 def get_color(self, fl):
1484 def get_log_scale(self, fl):
1487 return math.log(fl+eps)
1489 def color_by_resid(self):
1490 self.method = self.color_by_resid
1491 self.scheme = self.mpl.cm.rainbow
1492 for mol
in self.mols:
1499 c = self.get_color(float(ri)/self.last)
1503 avr = sum(ris)/len(ris)
1504 c = self.get_color(float(avr)/self.last)
1507 def color_by_uncertainty(self):
1508 self.method = self.color_by_uncertainty
1509 self.scheme = self.mpl.cm.jet
1516 self.first = self.get_log_scale(1.0)
1517 self.last = self.get_log_scale(100.0)
1519 value = self.get_log_scale(unc_dict[p])
1520 if value >= self.last:
1522 if value <= self.first:
1524 c = self.get_color((value-self.first) / (self.last-self.first))
1527 def get_color_bar(self, filename):
1528 import matplotlib
as mpl
1530 import matplotlib.pyplot
as plt
1532 fig = plt.figure(figsize=(8, 3))
1533 ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
1536 norm = mpl.colors.Normalize(vmin=0.0, vmax=1.0)
1538 if self.method == self.color_by_uncertainty:
1539 angticks = [1.0, 2.5, 5.0, 10.0, 25.0, 50.0, 100.0]
1543 vvalue = (self.get_log_scale(at)-self.first) \
1544 / (self.last-self.first)
1545 if vvalue <= 1.0
and vvalue >= 0.0:
1546 vvalues.append(vvalue)
1547 marks.append(str(at))
1548 cb1 = mpl.colorbar.ColorbarBase(
1549 ax1, cmap=cmap, norm=norm, ticks=vvalues,
1550 orientation=
'horizontal')
1551 print(self.first, self.last, marks, vvalues)
1552 cb1.ax.set_xticklabels(marks)
1553 cb1.set_label(
'Angstorm')
1554 plt.savefig(filename, dpi=150, transparent=
True)
1559 """Given a Chimera color name or hex color value, return RGB"""
1560 d = {
'aquamarine': (0.4980392156862745, 1.0, 0.8313725490196079),
1561 'black': (0.0, 0.0, 0.0),
1562 'blue': (0.0, 0.0, 1.0),
1563 'brown': (0.6470588235, 0.16470588235294117, 0.16470588235294117),
1564 'chartreuse': (0.4980392156862745, 1.0, 0.0),
1565 'coral': (1.0, 0.4980392156862745, 0.3137254901960784),
1566 'cornflower blue': (0.39215686, 0.58431372549, 0.9294117647058824),
1567 'cyan': (0.0, 1.0, 1.0),
1568 'dark cyan': (0.0, 0.5450980392156862, 0.5450980392156862),
1569 'dark gray': (0.6627450980, 0.6627450980392157, 0.6627450980392157),
1570 'dark green': (0.0, 0.39215686274509803, 0.0),
1571 'dark khaki': (0.74117647, 0.7176470588235294, 0.4196078431372549),
1572 'dark magenta': (0.5450980392156862, 0.0, 0.5450980392156862),
1573 'dark olive green': (0.333333333, 0.419607843, 0.1843137254901961),
1574 'dark red': (0.5450980392156862, 0.0, 0.0),
1575 'dark slate blue': (0.28235294, 0.239215686, 0.5450980392156862),
1576 'dark slate gray': (0.1843137, 0.30980392, 0.30980392156862746),
1577 'deep pink': (1.0, 0.0784313725490196, 0.5764705882352941),
1578 'deep sky blue': (0.0, 0.7490196078431373, 1.0),
1579 'dim gray': (0.41176470, 0.4117647058823529, 0.4117647058823529),
1580 'dodger blue': (0.11764705882352941, 0.5647058823529412, 1.0),
1581 'firebrick': (0.6980392, 0.13333333333333333, 0.13333333333333333),
1582 'forest green': (0.13333333, 0.5450980392156862, 0.13333333333333333),
1583 'gold': (1.0, 0.8431372549019608, 0.0),
1584 'goldenrod': (0.85490196, 0.6470588235294118, 0.12549019607843137),
1585 'gray': (0.7450980392156863, 0.7450980392156863, 0.7450980392156863),
1586 'green': (0.0, 1.0, 0.0),
1587 'hot pink': (1.0, 0.4117647058823529, 0.7058823529411765),
1588 'khaki': (0.9411764705882353, 0.9019607843137255, 0.5490196078431373),
1589 'light blue': (0.67843137, 0.8470588235294118, 0.9019607843137255),
1590 'light gray': (0.82745098, 0.8274509803921568, 0.8274509803921568),
1591 'light green': (0.56470588, 0.9333333333333333, 0.5647058823529412),
1592 'light sea green': (0.125490, 0.6980392156862745, 0.6666666666666666),
1593 'lime green': (0.1960784, 0.803921568627451, 0.19607843137254902),
1594 'magenta': (1.0, 0.0, 1.0),
1595 'medium blue': (0.1960784, 0.19607843137254902, 0.803921568627451),
1596 'medium purple': (0.57647, 0.4392156862745098, 0.8588235294117647),
1597 'navy blue': (0.0, 0.0, 0.5019607843137255),
1598 'olive drab': (0.4196078, 0.5568627450980392, 0.13725490196078433),
1599 'orange red': (1.0, 0.27058823529411763, 0.0),
1600 'orange': (1.0, 0.4980392156862745, 0.0),
1601 'orchid': (0.85490196, 0.4392156862745098, 0.8392156862745098),
1602 'pink': (1.0, 0.7529411764705882, 0.796078431372549),
1603 'plum': (0.8666666666666667, 0.6274509803921569, 0.8666666666666667),
1604 'purple': (0.62745098, 0.12549019607843137, 0.9411764705882353),
1605 'red': (1.0, 0.0, 0.0),
1606 'rosy brown': (0.7372549, 0.5607843137254902, 0.5607843137254902),
1607 'salmon': (0.980392, 0.5019607843137255, 0.4470588235294118),
1608 'sandy brown': (0.956862745, 0.6431372549019608, 0.3764705882352941),
1609 'sea green': (0.18039, 0.5450980392156862, 0.3411764705882353),
1610 'sienna': (0.6274509, 0.3215686274509804, 0.17647058823529413),
1611 'sky blue': (0.52941176, 0.807843137254902, 0.9215686274509803),
1612 'slate gray': (0.439215686, 0.50196078, 0.5647058823529412),
1613 'spring green': (0.0, 1.0, 0.4980392156862745),
1614 'steel blue': (0.2745098, 0.50980392, 0.70588235),
1615 'tan': (0.8235294117647058, 0.7058823529411765, 0.5490196078431373),
1616 'turquoise': (0.25098039, 0.87843137, 0.81568627),
1617 'violet red': (0.81568627, 0.125490196, 0.56470588235),
1618 'white': (1.0, 1.0, 1.0),
1619 'yellow': (1.0, 1.0, 0.0)}
1620 if colorname.startswith(
'#'):
1621 return tuple(int(colorname[i:i+2], 16) / 255.
for i
in (1, 3, 5))
static bool get_is_setup(const IMP::ParticleAdaptor &p)
static bool get_is_setup(const IMP::ParticleAdaptor &p)
A decorator to associate a particle with a part of a protein/DNA/RNA.
Extends the functionality of IMP.atom.Molecule.
def add_script_provenance
Tag the given particle with the current Python script.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Set of Python classes to create a multi-state, multi-resolution IMP hierarchy.
static Weight setup_particle(Model *m, ParticleIndex pi)
Set up an empty Weight.
A decorator for a particle which has bonds.
Rotation3D get_random_rotation_3d(const Rotation3D ¢er, double distance)
Pick a rotation at random near the provided one.
An exception for an invalid usage of IMP.
std::string get_module_version()
Return the version of this module, as a string.
static Surface setup_particle(Model *m, ParticleIndex pi)
Add uncertainty to a particle.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
static bool get_is_setup(const IMP::ParticleAdaptor &p)
GenericHierarchies get_leaves(Hierarchy mhd)
Get all the leaves of the bit of hierarchy.
Represent the root node of the global IMP.atom.Hierarchy.
def add_imp_provenance
Tag the given particle as being created by the current version of IMP.
Vector3D get_random_vector_in(const Cylinder3D &c)
Generate a random vector in a cylinder with uniform density.
Bond create_bond(Bonded a, Bonded b, Bond o)
Connect the two wrapped particles by a custom bond.
Object used to hold a set of restraints.
Stores a named protein chain.
static bool get_is_setup(Model *m, ParticleIndex pi)
def add_software_provenance
Tag the given particle with the software used to create it.
A decorator for keeping track of copies of a molecule.
ParticleIndexPairs get_indexes(const ParticlePairsTemp &ps)
Get the indexes from a list of particle pairs.
The standard decorator for manipulating molecular structures.
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
A decorator for a particle representing an atom.
void transform(XYZ a, const algebra::Transformation3D &tr)
Apply a transformation to the particle.
static Bonded setup_particle(Model *m, ParticleIndex pi)
void load_frame(RMF::FileConstHandle file, RMF::FrameID frame)
Load the given RMF frame into the state of the linked objects.
A decorator for a particle with x,y,z coordinates.
static Scale setup_particle(Model *m, ParticleIndex pi)
A decorator for a particle that is part of a rigid body but not rigid.
Find all nearby pairs by testing all pairs.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
A decorator for a residue.
DensityGrid get_grid(IMP::em::DensityMap *in)
Return a dense grid containing the voxels of the passed density map.
General purpose algebraic and geometric methods that are expected to be used by a wide variety of IMP...
static bool get_is_setup(const IMP::ParticleAdaptor &p)
static bool get_is_setup(Model *m, ParticleIndex p)
Check if the particle has the needed attributes for a cast to succeed.
The general base class for IMP exceptions.
Rotation3D get_identity_rotation_3d()
Return a rotation that does not do anything.
void link_hierarchies(RMF::FileConstHandle fh, const atom::Hierarchies &hs)
Class to handle individual particles of a Model object.
Bond get_bond(Bonded a, Bonded b)
Get the bond between two particles.
Stores a list of Molecules all with the same State index.
std::string get_data_path(std::string file_name)
Return the full path to one of this module's data files.
int get_copy_index(Hierarchy h)
Walk up the hierarchy to find the current copy index.
Python classes to represent, score, sample and analyze models.
static bool get_is_setup(Model *m, ParticleIndex pi)
A decorator for a rigid body.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Hierarchies get_leaves(const Selection &h)
A decorator for a molecule.
Select hierarchy particles identified by the biological name.
Support for the RMF file format for storing hierarchical molecular data and markup.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Warning for probably incorrect input parameters.
Transformation3D get_random_local_transformation(Vector3D origin, double max_translation=5., double max_angle_in_rad=0.26)
Get a local transformation.
Temporarily stores residue information, even without structure available.
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...