3 """@namespace IMP.pmi.tools
4 Miscellaneous utilities.
7 from __future__
import print_function, division
14 from collections.abc
import MutableSet
16 from collections
import MutableSet
22 from time
import process_time
24 from time
import clock
as process_time
27 from collections
import defaultdict, OrderedDict
32 def _get_system_for_hier(hier):
33 """Given a hierarchy, return the System that created it, or None"""
36 if hier
and not hasattr(hier,
'get_parent'):
43 if hasattr(hier,
'_pmi2_system'):
44 return hier._pmi2_system()
47 for ws
in IMP.pmi.topology.System._all_systems:
49 if s
and s.hier == hier:
52 hier = hier.get_parent()
55 def _all_protocol_outputs(hier):
56 """Iterate over all (ProtocolOutput, State) pairs for the
58 system = _get_system_for_hier(hier)
60 for state
in system.states:
61 for p
in state._protocol_output:
65 def _add_pmi_provenance(p):
66 """Tag the given particle as being created by the current version
71 location=
"https://integrativemodeling.org")
75 def _get_restraint_set_keys():
76 if not hasattr(_get_restraint_set_keys,
'pmi_rs_key'):
77 _get_restraint_set_keys.pmi_rs_key =
IMP.ModelKey(
"PMI restraints")
78 _get_restraint_set_keys.rmf_rs_key =
IMP.ModelKey(
"RMF restraints")
79 return (_get_restraint_set_keys.pmi_rs_key,
80 _get_restraint_set_keys.rmf_rs_key)
83 def _add_restraint_sets(model, mk, mk_rmf):
86 model.add_data(mk, rs)
87 model.add_data(mk_rmf, rs_rmf)
92 """Add a PMI restraint to the model.
93 Since Model.add_restraint() no longer exists (in modern IMP restraints
94 should be added to a ScoringFunction instead) store them instead in
95 a RestraintSet, and keep a reference to it in the Model.
97 If `add_to_rmf` is True, also add the restraint to a separate list
98 of restraints that will be written out to RMF files (by default, most
99 PMI restraints are not)."""
100 mk, mk_rmf = _get_restraint_set_keys()
101 if model.get_has_data(mk):
102 rs = IMP.RestraintSet.get_from(model.get_data(mk))
103 rs_rmf = IMP.RestraintSet.get_from(model.get_data(mk_rmf))
105 rs, rs_rmf = _add_restraint_sets(model, mk, mk_rmf)
106 rs.add_restraint(restraint)
108 rs_rmf.add_restraint(restraint)
112 """Get a RestraintSet containing all PMI restraints added to the model.
113 If `rmf` is True, return only the subset of these restraints that
114 should be written out to RMF files."""
115 mk, mk_rmf = _get_restraint_set_keys()
116 if not model.get_has_data(mk):
117 warnings.warn(
"no restraints added to model yet",
119 _add_restraint_sets(model, mk, mk_rmf)
121 return IMP.RestraintSet.get_from(model.get_data(mk_rmf))
123 return IMP.RestraintSet.get_from(model.get_data(mk))
127 """Collect timing information.
128 Add an instance of this class to outputobjects to get timing information
133 @param isdelta if True (the default) then report the time since the
134 last use of this class; if False, report cumulative time."""
135 self.starttime = process_time()
137 self.isdelta = isdelta
139 def set_label(self, labelstr):
140 self.label = labelstr
142 def get_output(self):
145 newtime = process_time()
146 output[
"Stopwatch_" + self.label +
"_delta_seconds"] \
147 = str(newtime - self.starttime)
148 self.starttime = newtime
150 output[
"Stopwatch_" + self.label +
"_elapsed_seconds"] \
151 = str(process_time() - self.starttime)
155 class SetupNuisance(object):
157 def __init__(self, m, initialvalue, minvalue, maxvalue, isoptimized=True,
165 nuisance.set_lower(minvalue)
167 nuisance.set_upper(maxvalue)
170 nuisance.set_is_optimized(nuisance.get_nuisance_key(), isoptimized)
171 self.nuisance = nuisance
173 def get_particle(self):
177 class SetupWeight(object):
179 def __init__(self, m, isoptimized=True, nweights_or_weights=None):
181 if isinstance(nweights_or_weights, int):
183 pw, nweights_or_weights
187 nweights_or_weights = list(nweights_or_weights)
189 pw, nweights_or_weights
193 self.weight.set_weights_are_optimized(isoptimized)
195 def get_particle(self):
199 class SetupSurface(object):
201 def __init__(self, m, center, normal, isoptimized=True):
204 self.surface.set_coordinates_are_optimized(isoptimized)
205 self.surface.set_normal_is_optimized(isoptimized)
207 def get_particle(self):
212 class ParticleToSampleList(object):
216 self.dictionary_particle_type = {}
217 self.dictionary_particle_transformation = {}
218 self.dictionary_particle_name = {}
221 def add_particle(self, particle, particle_type, particle_transformation,
223 if particle_type
not in [
"Rigid_Bodies",
"Floppy_Bodies",
"Nuisances",
224 "X_coord",
"Weights",
"Surfaces"]:
225 raise TypeError(
"not the right particle type")
227 self.dictionary_particle_type[particle] = particle_type
228 if particle_type ==
"Rigid_Bodies":
229 if (isinstance(particle_transformation, tuple)
230 and len(particle_transformation) == 2
231 and all(isinstance(x, float)
232 for x
in particle_transformation)):
233 self.dictionary_particle_transformation[
234 particle] = particle_transformation
235 self.dictionary_particle_name[particle] = name
238 "ParticleToSampleList: not the right transformation "
239 "format for Rigid_Bodies, should be a tuple of floats")
240 elif particle_type ==
"Surfaces":
241 if (isinstance(particle_transformation, tuple)
242 and len(particle_transformation) == 3
243 and all(isinstance(x, float)
244 for x
in particle_transformation)):
245 self.dictionary_particle_transformation[
246 particle] = particle_transformation
247 self.dictionary_particle_name[particle] = name
250 "ParticleToSampleList: not the right transformation "
251 "format for Surfaces, should be a tuple of floats")
253 if isinstance(particle_transformation, float):
254 self.dictionary_particle_transformation[
255 particle] = particle_transformation
256 self.dictionary_particle_name[particle] = name
259 "ParticleToSampleList: not the right transformation "
260 "format, should be a float")
262 def get_particles_to_sample(self):
264 for particle
in self.dictionary_particle_type:
265 key = self.dictionary_particle_type[particle] + \
266 "ParticleToSampleList_" + \
267 self.dictionary_particle_name[particle] +
"_" + self.label
270 self.dictionary_particle_transformation[particle])
275 def get_cross_link_data(directory, filename, dist, omega, sigma,
276 don=
None, doff=
None, prior=0, type_of_profile=
"gofr"):
278 (distmin, distmax, ndist) = dist
279 (omegamin, omegamax, nomega) = omega
280 (sigmamin, sigmamax, nsigma) = sigma
283 with open(filen)
as xlpot:
284 dictionary = ast.literal_eval(xlpot.readline())
286 xpot = dictionary[directory][filename][
"distance"]
287 pot = dictionary[directory][filename][type_of_profile]
289 dist_grid =
get_grid(distmin, distmax, ndist,
False)
290 omega_grid = get_log_grid(omegamin, omegamax, nomega)
291 sigma_grid = get_log_grid(sigmamin, sigmamax, nsigma)
293 if don
is not None and doff
is not None:
313 def get_grid(gmin, gmax, ngrid, boundaries):
315 dx = (gmax - gmin) / float(ngrid)
316 for i
in range(0, ngrid + 1):
317 if not boundaries
and i == 0:
319 if not boundaries
and i == ngrid:
321 grid.append(gmin + float(i) * dx)
325 def get_log_grid(gmin, gmax, ngrid):
327 for i
in range(0, ngrid + 1):
328 grid.append(gmin * math.exp(float(i) / ngrid * math.log(gmax / gmin)))
334 example '"{ID_Score}" > 28 AND "{Sample}" ==
335 "%10_1%" OR ":Sample}" == "%10_2%" OR ":Sample}"
336 == "%10_3%" OR ":Sample}" == "%8_1%" OR ":Sample}" == "%8_2%"'
339 import pyparsing
as pp
341 operator = pp.Regex(
">=|<=|!=|>|<|==|in").setName(
"operator")
342 value = pp.QuotedString(
344 r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?")
345 identifier = pp.Word(pp.alphas, pp.alphanums +
"_")
346 comparison_term = identifier | value
347 condition = pp.Group(comparison_term + operator + comparison_term)
349 expr = pp.operatorPrecedence(condition, [
350 (
"OR", 2, pp.opAssoc.LEFT, ),
351 (
"AND", 2, pp.opAssoc.LEFT, ),
354 parsedstring = str(expr.parseString(inputstring)) \
360 .replace(
"{",
"float(entry['") \
361 .replace(
"}",
"'])") \
362 .replace(
":",
"str(entry['") \
363 .replace(
"}",
"'])") \
364 .replace(
"AND",
"and") \
369 def open_file_or_inline_text(filename):
371 fl = open(filename,
"r")
373 fl = filename.split(
"\n")
377 def get_ids_from_fasta_file(fastafile):
379 with open(fastafile)
as ff:
382 ids.append(line[1:-1])
388 this function works with plain hierarchies, as read from the pdb,
389 no multi-scale hierarchies
396 atom_type=IMP.atom.AT_CA)
404 print(
"get_closest_residue_position: exiting while loop "
407 p = sel.get_selected_particles()
412 print(
"get_closest_residue_position: got NO residues for hierarchy "
413 "%s and residue %i" % (hier, resindex))
415 "get_closest_residue_position: got NO residues for hierarchy "
416 "%s and residue %i" % (hier, resindex))
419 "got multiple residues for hierarchy %s and residue %i; the list "
421 % (hier, resindex, str([pp.get_name()
for pp
in p])))
426 Return the residue index gaps and contiguous segments in the hierarchy.
428 @param hierarchy hierarchy to examine
429 @param start first residue index
430 @param end last residue index
432 @return A list of lists of the form
433 [[1,100,"cont"],[101,120,"gap"],[121,200,"cont"]]
436 for n, rindex
in enumerate(range(start, end + 1)):
438 atom_type=IMP.atom.AT_CA)
440 if len(sel.get_selected_particles()) == 0:
444 rindexcont = start - 1
445 if rindexgap == rindex - 1:
451 gaps.append([rindex, rindex,
"gap"])
457 rindexgap = start - 1
459 if rindexcont == rindex - 1:
466 gaps.append([rindex, rindex,
"cont"])
477 def set_map_element(self, xvalue, yvalue):
478 self.map[xvalue] = yvalue
480 def get_map_element(self, invalue):
481 if isinstance(invalue, float):
485 dist = (invalue - x) * (invalue - x)
494 return self.map[minx]
495 elif isinstance(invalue, str):
496 return self.map[invalue]
498 raise TypeError(
"wrong type for map")
502 """New tuple format: molname OR (start,stop,molname,copynum,statenum)
503 Copy and state are optional. Can also use 'None' for them which will
504 get all. You can also pass -1 for stop which will go to the end.
505 Returns the particles
508 kwds[
'resolution'] = resolution
509 if isinstance(tuple_selection, str):
510 kwds[
'molecule'] = tuple_selection
511 elif isinstance(tuple_selection, tuple):
512 rbegin = tuple_selection[0]
513 rend = tuple_selection[1]
514 kwds[
'molecule'] = tuple_selection[2]
516 copynum = tuple_selection[3]
517 if copynum
is not None:
518 kwds[
'copy_index'] = copynum
522 statenum = tuple_selection[4]
523 if statenum
is not None:
524 kwds[
'state_index'] = statenum
531 residue_indexes=range(1, rbegin),
533 return s.get_selected_particles()
535 kwds[
'residue_indexes'] = range(rbegin, rend+1)
537 return s.get_selected_particles()
540 def get_db_from_csv(csvfilename):
543 with open(csvfilename)
as fh:
544 csvr = csv.DictReader(fh)
546 outputlist.append(ls)
551 '''Return the component name provided a particle and a list of names'''
553 protname = root.get_name()
555 while protname
not in list_of_names:
556 root0 = root.get_parent()
559 protname = root0.get_name()
564 if "Beads" in protname:
567 return (protname, is_a_bead)
572 Retrieve the residue indexes for the given particle.
574 The particle must be an instance of Fragment,Residue, Atom or Molecule
575 or else returns an empty list
586 resind_tmp = IMP.pmi.tools.OrderedSet()
593 resind = list(resind_tmp)
599 def sort_by_residues(particles):
602 sorted_particles_residues = sorted(
604 key=
lambda tup: tup[1])
605 particles = [p[0]
for p
in sorted_particles_residues]
614 """Synchronize data over a parallel run"""
615 from mpi4py
import MPI
616 comm = MPI.COMM_WORLD
617 rank = comm.Get_rank()
618 number_of_processes = comm.size
621 comm.send(data, dest=0, tag=11)
624 for i
in range(1, number_of_processes):
625 data_tmp = comm.recv(source=i, tag=11)
626 if isinstance(data, list):
628 elif isinstance(data, dict):
629 data.update(data_tmp)
631 raise TypeError(
"data not supported, use list or dictionaries")
633 for i
in range(1, number_of_processes):
634 comm.send(data, dest=i, tag=11)
637 data = comm.recv(source=0, tag=11)
647 Yield all sublists of length >= lmin and <= lmax
653 for j
in range(i + lmin, min(n + 1, i + 1 + lmax)):
657 def flatten_list(ls):
658 return [item
for sublist
in ls
for item
in sublist]
662 """ Yield successive length-sized chunks from a list.
664 for i
in range(0, len(list), length):
665 yield list[i:i + length]
668 def chunk_list_into_segments(seq, num):
670 avg = len(seq) / float(num)
674 while last < len(seq):
675 out.append(seq[int(last):int(last + avg)])
683 ''' This class stores integers
684 in ordered compact lists eg:
686 the methods help splitting and merging the internal lists
688 s=Segments([1,2,3]) is [[1,2,3]]
689 s.add(4) is [[1,2,3,4]] (add right)
690 s.add(3) is [[1,2,3,4]] (item already existing)
691 s.add(7) is [[1,2,3,4],[7]] (new list)
692 s.add([8,9]) is [[1,2,3,4],[7,8,9]] (add item right)
693 s.add([5,6]) is [[1,2,3,4,5,6,7,8,9]] (merge)
694 s.remove(3) is [[1,2],[4,5,6,7,8,9]] (split)
699 '''index can be a integer or a list of integers '''
700 if isinstance(index, int):
701 self.segs = [[index]]
702 elif isinstance(index, list):
703 self.segs = [[index[0]]]
707 raise TypeError(
"index must be an int or list of ints")
710 '''index can be a integer or a list of integers '''
711 if isinstance(index, (int, numpy.int32, numpy.int64)):
714 for n, s
in enumerate(self.segs):
722 if mergeright
is None and mergeleft
is None:
723 self.segs.append([index])
724 if mergeright
is not None and mergeleft
is None:
725 self.segs[mergeright].append(index)
726 if mergeleft
is not None and mergeright
is None:
727 self.segs[mergeleft] = [index]+self.segs[mergeleft]
728 if mergeleft
is not None and mergeright
is not None:
729 self.segs[mergeright] = \
730 self.segs[mergeright]+[index]+self.segs[mergeleft]
731 del self.segs[mergeleft]
733 for n
in range(len(self.segs)):
736 self.segs.sort(key=
lambda tup: tup[0])
738 elif isinstance(index, list):
742 raise TypeError(
"index must be an int or list of ints")
745 '''index can be a integer'''
746 for n, s
in enumerate(self.segs):
751 self.segs[n] = s[:-1]
753 i = self.segs[n].index(index)
755 self.segs.append(s[i+1:])
756 for n
in range(len(self.segs)):
758 if len(self.segs[n]) == 0:
760 self.segs.sort(key=
lambda tup: tup[0])
763 ''' Returns a flatten list '''
764 return [item
for sublist
in self.segs
for item
in sublist]
768 for seg
in self.segs:
769 ret_tmp += str(seg[0])+
"-"+str(seg[-1])+
","
770 ret = ret_tmp[:-1]+
"]"
778 def normal_density_function(expected_value, sigma, x):
780 1 / math.sqrt(2 * math.pi) / sigma *
781 math.exp(-(x - expected_value) ** 2 / 2 / sigma / sigma)
785 def log_normal_density_function(expected_value, sigma, x):
787 1 / math.sqrt(2 * math.pi) / sigma / x *
788 math.exp(-(math.log(x / expected_value) ** 2 / 2 / sigma / sigma))
792 def print_multicolumn(list_of_strings, ncolumns=2, truncate=40):
798 for i
in range(len(ls) % cols):
801 split = [ls[i:i + len(ls) // cols]
802 for i
in range(0, len(ls), len(ls) // cols)]
803 for row
in zip(*split):
804 print(
"".join(str.ljust(i, truncate)
for i
in row))
808 '''Change color code to hexadecimal to rgb'''
810 self._NUMERALS =
'0123456789abcdefABCDEF'
811 self._HEXDEC = dict((v, int(v, 16))
for v
in
812 (x+y
for x
in self._NUMERALS
813 for y
in self._NUMERALS))
814 self.LOWERCASE, self.UPPERCASE =
'x',
'X'
816 def rgb(self, triplet):
817 return (float(self._HEXDEC[triplet[0:2]]),
818 float(self._HEXDEC[triplet[2:4]]),
819 float(self._HEXDEC[triplet[4:6]]))
821 def triplet(self, rgb, lettercase=None):
822 if lettercase
is None:
823 lettercase = self.LOWERCASE
824 return format(rgb[0] << 16 | rgb[1] << 8 | rgb[2],
'06'+lettercase)
828 class OrderedSet(MutableSet):
830 def __init__(self, iterable=None):
832 end += [
None, end, end]
834 if iterable
is not None:
840 def __contains__(self, key):
841 return key
in self.map
844 if key
not in self.map:
847 curr[2] = end[1] = self.map[key] = [key, curr, end]
849 def discard(self, key):
851 key, prev, next = self.map.pop(key)
858 while curr
is not end:
862 def __reversed__(self):
865 while curr
is not end:
869 def pop(self, last=True):
871 raise KeyError(
'set is empty')
881 return '%s()' % (self.__class__.__name__,)
882 return '%s(%r)' % (self.__class__.__name__, list(self))
884 def __eq__(self, other):
885 if isinstance(other, OrderedSet):
886 return len(self) == len(other)
and list(self) == list(other)
887 return set(self) == set(other)
891 """Store objects in order they were added, but with default type.
892 Source: http://stackoverflow.com/a/4127426/2608793
894 def __init__(self, *args, **kwargs):
896 self.default_factory =
None
898 if not (args[0]
is None or callable(args[0])):
899 raise TypeError(
'first argument must be callable or None')
900 self.default_factory = args[0]
902 super(OrderedDefaultDict, self).__init__(*args, **kwargs)
904 def __missing__(self, key):
905 if self.default_factory
is None:
907 self[key] = default = self.default_factory()
910 def __reduce__(self):
911 args = (self.default_factory,)
if self.default_factory
else ()
912 if sys.version_info[0] >= 3:
913 return self.__class__, args,
None,
None, self.items()
915 return self.__class__, args,
None,
None, self.iteritems()
921 """Extract frame from RMF file and fill coordinates. Must be identical
924 @param hier The (System) hierarchy to fill (e.g. after you've built it)
925 @param rmf_fn The file to extract from
926 @param frame_num The frame number to extract
928 rh = RMF.open_rmf_file_read_only(rmf_fn)
934 def input_adaptor(stuff, pmi_resolution=0, flatten=False, selection_tuple=None,
935 warn_about_slices=
True):
936 """Adapt things for PMI (degrees of freedom, restraints, ...)
937 Returns list of list of hierarchies, separated into Molecules if possible.
938 The input can be a list, or a list of lists (iterable of ^1 or
940 (iterable of ^2) Hierarchy -> returns input as list of list of hierarchies,
941 only one entry, not grouped by molecules.
942 (iterable of ^2) PMI::System/State/Molecule/TempResidue ->
943 returns residue hierarchies, grouped in molecules, at requested
946 @param stuff Can be one of the following inputs:
947 IMP Hierarchy, PMI System/State/Molecule/TempResidue, or a
948 list/set (of list/set) of them.
949 Must be uniform input, however. No mixing object types.
950 @param pmi_resolution For selecting, only does it if you pass PMI
951 objects. Set it to "all" if you want all resolutions!
952 @param flatten Set to True if you just want all hierarchies in one list.
953 @param warn_about_slices Print a warning if you are requesting only part
954 of a bead. Sometimes you just don't care!
955 @note since this relies on IMP::atom::Selection, this will not return
956 any objects if they weren't built! But there should be no problem
957 if you request unbuilt residues - they should be ignored.
963 if hasattr(stuff,
'__iter__'):
966 thelist = list(stuff)
969 if all(hasattr(el,
'__iter__')
for el
in thelist):
970 thelist = [i
for sublist
in thelist
for i
in sublist]
971 elif any(hasattr(el,
'__iter__')
for el
in thelist):
972 raise Exception(
'input_adaptor: input_object must be a list '
973 'or a list of lists')
982 except (NotImplementedError, TypeError):
994 if is_system
or is_state
or is_molecule
or is_temp_residue:
1000 for system
in stuff:
1001 for state
in system.get_states():
1002 mdict = state.get_molecules()
1003 for molname
in mdict:
1004 for copy
in mdict[molname]:
1005 indexes_per_mol[copy] += \
1006 [r.get_index()
for r
in copy.get_residues()]
1009 mdict = state.get_molecules()
1010 for molname
in mdict:
1011 for copy
in mdict[molname]:
1012 indexes_per_mol[copy] += [r.get_index()
1013 for r
in copy.get_residues()]
1015 for molecule
in stuff:
1016 indexes_per_mol[molecule] += [r.get_index()
1017 for r
in molecule.get_residues()]
1019 for tempres
in stuff:
1020 indexes_per_mol[tempres.get_molecule()].append(
1021 tempres.get_index())
1022 for mol
in indexes_per_mol:
1023 if pmi_resolution ==
'all':
1027 mol.get_hierarchy(), residue_indexes=indexes_per_mol[mol])
1030 resolution=pmi_resolution,
1031 residue_indexes=indexes_per_mol[mol])
1032 ps = sel.get_selected_particles()
1035 if warn_about_slices:
1036 rset = set(indexes_per_mol[mol])
1040 if not fset <= rset:
1046 resbreak = maxf
if minf == minset
else minset-1
1048 'You are trying to select only part of the '
1049 'bead %s:%i-%i. The residues you requested '
1050 'are %i-%i. You can fix this by: '
1051 '1) requesting the whole bead/none of it; or'
1052 '2) break the bead up by passing '
1053 'bead_extra_breaks=[\'%i\'] in '
1054 'molecule.add_representation()'
1055 % (mol.get_name(), minset, maxset, minf, maxf,
1061 if pmi_resolution ==
'all':
1067 h, resolution=pmi_resolution).get_selected_particles()
1070 hier_list = [hier_list]
1072 raise Exception(
'input_adaptor: you passed something of wrong type '
1073 'or a list with mixed types')
1075 if flatten
and pmi_input:
1076 return [h
for sublist
in hier_list
for h
in sublist]
1082 """Returns sequence-sorted segments array, each containing the first
1083 particle the last particle and the first residue index."""
1085 from operator
import itemgetter
1088 raise ValueError(
"only pass stuff from one Molecule, please")
1103 segs.append((start, end, startres))
1104 return sorted(segs, key=itemgetter(2))
1108 """Decorate the sequence-consecutive particles from a PMI2 molecule
1109 with a bond, so that they appear connected in the rmf file"""
1111 for x
in range(len(SortedSegments) - 1):
1113 last = SortedSegments[x][1]
1114 first = SortedSegments[x + 1][0]
1116 p1 = last.get_particle()
1117 p2 = first.get_particle()
1130 """ Just get the leaves from a list of hierarchies """
1131 lvs = list(itertools.chain.from_iterable(
1137 """Perform selection using the usual keywords but return ALL
1138 resolutions (BEADS and GAUSSIANS).
1139 Returns in flat list!
1144 if hier
is not None:
1147 warnings.warn(
"You passed nothing to select_at_all_resolutions()",
1155 raise Exception(
'select_at_all_resolutions: you have to pass '
1158 raise Exception(
'select_at_all_resolutions: you have to pass '
1160 if 'resolution' in kwargs
or 'representation_type' in kwargs:
1161 raise Exception(
"don't pass resolution or representation_type "
1164 representation_type=IMP.atom.BALLS,
1167 representation_type=IMP.atom.DENSITIES,
1169 ret |= OrderedSet(selB.get_selected_particles())
1170 ret |= OrderedSet(selD.get_selected_particles())
1179 """Utility to retrieve particles from a hierarchy within a
1180 zone around a set of ps.
1181 @param hier The hierarchy in which to look for neighbors
1182 @param target_ps The particles for zoning
1183 @param sel_zone The maximum distance
1184 @param entire_residues If True, will grab entire residues
1185 @param exclude_backbone If True, will only return sidechain particles
1189 backbone_types = [
'C',
'N',
'CB',
'O']
1190 if exclude_backbone:
1193 test_ps = test_sel.get_selected_particles()
1194 nn = IMP.algebra.NearestNeighbor3D([
IMP.core.XYZ(p).get_coordinates()
1197 for target
in target_ps:
1198 zone |= set(nn.get_in_ball(
IMP.core.XYZ(target).get_coordinates(),
1200 zone_ps = [test_ps[z]
for z
in zone]
1205 zone_ps = [h.get_particle()
for h
in final_ps]
1210 """Returns unique objects in original order"""
1214 if not hasattr(hiers,
'__iter__'):
1221 rbs_ordered.append(rb)
1226 rbs_ordered.append(rb)
1230 return rbs_ordered, beads
1234 "This function returns the parent molecule hierarchies of given objects"
1235 stuff =
input_adaptor(input_objects, pmi_resolution=
'all', flatten=
True)
1240 while not (is_molecule
or is_root):
1241 root = IMP.atom.get_root(h)
1248 return list(molecules)
1251 def get_molecules_dictionary(input_objects):
1252 moldict = defaultdict(list)
1254 name = mol.get_name()
1255 moldict[name].append(mol)
1262 def get_molecules_dictionary_by_copy(input_objects):
1263 moldict = defaultdict(dict)
1265 name = mol.get_name()
1267 moldict[name][c] = mol
1271 def get_selections_dictionary(input_objects):
1272 moldict = IMP.pmi.tools.get_molecules_dictionary(input_objects)
1273 seldict = defaultdict(list)
1274 for name, mols
in moldict.items():
1281 """Given a list of PMI objects, returns all density hierarchies within
1282 these objects. The output of this function can be inputted into
1283 things such as EM restraints. This function is intended to gather
1284 density particles appended to molecules (and not other hierarchies
1285 which might have been appended to the root node directly).
1294 i, representation_type=IMP.atom.DENSITIES).get_selected_particles()
1299 max_translation=300., max_rotation=2.0 * math.pi,
1300 avoidcollision_rb=
True, avoidcollision_fb=
False,
1301 cutoff=10.0, niterations=100,
1303 excluded_rigid_bodies=[],
1304 hierarchies_excluded_from_collision=[],
1305 hierarchies_included_in_collision=[],
1307 return_debug=
False):
1308 """Shuffle particles. Used to restart the optimization.
1309 The configuration of the system is initialized by placing each
1310 rigid body and each bead randomly in a box. If `bounding_box` is
1311 specified, the particles are placed inside this box; otherwise, each
1312 particle is displaced by up to max_translation angstroms, and randomly
1313 rotated. Effort is made to place particles far enough from each other to
1314 prevent any steric clashes.
1315 @param objects Can be one of the following inputs:
1316 IMP Hierarchy, PMI System/State/Molecule/TempResidue, or
1318 @param max_translation Max translation (rbs and flexible beads)
1319 @param max_rotation Max rotation (rbs only)
1320 @param avoidcollision_rb check if the particle/rigid body was
1321 placed close to another particle; uses the optional
1322 arguments cutoff and niterations
1323 @param avoidcollision_fb Advanced. Generally you want this False because
1324 it's hard to shuffle beads.
1325 @param cutoff Distance less than this is a collision
1326 @param niterations How many times to try avoiding collision
1327 @param bounding_box Only shuffle particles within this box.
1328 Defined by ((x1,y1,z1),(x2,y2,z2)).
1329 @param excluded_rigid_bodies Don't shuffle these rigid body objects
1330 @param hierarchies_excluded_from_collision Don't count collision
1332 @param hierarchies_included_in_collision Hierarchies that are not
1333 shuffled, but should be included in collision calculation
1335 @param verbose Give more output
1336 @note Best to only call this function after you've set up degrees
1338 For debugging purposes, returns: <shuffled indexes>,
1339 <collision avoided indexes>
1344 pmi_resolution=
'all',
1347 if len(rigid_bodies) > 0:
1348 mdl = rigid_bodies[0].get_model()
1349 elif len(flexible_beads) > 0:
1350 mdl = flexible_beads[0].get_model()
1352 raise Exception(
"Could not find any particles in the hierarchy")
1353 if len(rigid_bodies) == 0:
1354 print(
"shuffle_configuration: rigid bodies were not initialized")
1358 gcpf.set_distance(cutoff)
1362 hierarchies_excluded_from_collision, pmi_resolution=
'all',
1366 hierarchies_included_in_collision, pmi_resolution=
'all', flatten=
True)
1368 collision_excluded_idxs = set(
1370 for h
in collision_excluded_hierarchies
1373 collision_included_idxs = set(
1375 for h
in collision_included_hierarchies
1382 all_idxs.append(p.get_particle_index())
1384 collision_excluded_idxs.add(p.get_particle_index())
1386 if bounding_box
is not None:
1387 ((x1, y1, z1), (x2, y2, z2)) = bounding_box
1392 all_idxs = set(all_idxs) | collision_included_idxs
1393 all_idxs = all_idxs - collision_excluded_idxs
1395 print(
'shuffling', len(rigid_bodies),
'rigid bodies')
1396 for rb
in rigid_bodies:
1397 if rb
not in excluded_rigid_bodies:
1399 if avoidcollision_rb:
1400 rb_idxs = set(rb.get_member_particle_indexes()) - \
1401 collision_excluded_idxs
1402 other_idxs = all_idxs - rb_idxs
1404 debug.append([rb, other_idxs
if avoidcollision_rb
else set()])
1407 while niter < niterations:
1408 rbxyz = (rb.get_x(), rb.get_y(), rb.get_z())
1425 rbxyz, max_translation, max_rotation)
1430 if avoidcollision_rb
and other_idxs:
1432 npairs = len(gcpf.get_close_pairs(mdl,
1440 print(
"shuffle_configuration: rigid body placed "
1441 "close to other %d particles, trying "
1442 "again..." % npairs)
1443 print(
"shuffle_configuration: rigid body name: "
1445 if niter == niterations:
1447 "tried the maximum number of iterations to "
1448 "avoid collisions, increase the distance "
1453 print(
'shuffling', len(flexible_beads),
'flexible beads')
1454 for fb
in flexible_beads:
1456 if avoidcollision_fb:
1458 other_idxs = all_idxs - fb_idxs
1464 while niter < niterations:
1471 fbxyz, max_translation, max_rotation)
1476 xyz = memb.get_internal_coordinates()
1481 rf = memb.get_rigid_body().get_reference_frame()
1482 glob_to_int = rf.get_transformation_from()
1483 memb.set_internal_coordinates(
1484 glob_to_int.get_transformed(translation))
1486 xyz_transformed = transformation.get_transformed(xyz)
1487 memb.set_internal_coordinates(xyz_transformed)
1490 [xyz, other_idxs
if avoidcollision_fb
else set()])
1498 -d.get_coordinates())
1504 [d, other_idxs
if avoidcollision_fb
else set()])
1511 if avoidcollision_fb:
1513 npairs = len(gcpf.get_close_pairs(mdl,
1521 print(
"shuffle_configuration: floppy body placed close "
1522 "to other %d particles, trying again..." % npairs)
1523 if niter == niterations:
1525 "tried the maximum number of iterations to avoid "
1526 "collisions, increase the distance cutoff")
1533 class ColorHierarchy(object):
1535 def __init__(self, hier):
1536 import matplotlib
as mpl
1538 import matplotlib.pyplot
as plt
1542 hier.ColorHierarchy = self
1547 self.method = self.nochange
1555 def get_color(self, fl):
1558 def get_log_scale(self, fl):
1561 return math.log(fl+eps)
1563 def color_by_resid(self):
1564 self.method = self.color_by_resid
1565 self.scheme = self.mpl.cm.rainbow
1566 for mol
in self.mols:
1573 c = self.get_color(float(ri)/self.last)
1577 avr = sum(ris)/len(ris)
1578 c = self.get_color(float(avr)/self.last)
1581 def color_by_uncertainty(self):
1582 self.method = self.color_by_uncertainty
1583 self.scheme = self.mpl.cm.jet
1590 self.first = self.get_log_scale(1.0)
1591 self.last = self.get_log_scale(100.0)
1593 value = self.get_log_scale(unc_dict[p])
1594 if value >= self.last:
1596 if value <= self.first:
1598 c = self.get_color((value-self.first) / (self.last-self.first))
1601 def get_color_bar(self, filename):
1602 import matplotlib
as mpl
1604 import matplotlib.pyplot
as plt
1606 fig = plt.figure(figsize=(8, 3))
1607 ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15])
1610 norm = mpl.colors.Normalize(vmin=0.0, vmax=1.0)
1612 if self.method == self.color_by_uncertainty:
1613 angticks = [1.0, 2.5, 5.0, 10.0, 25.0, 50.0, 100.0]
1617 vvalue = (self.get_log_scale(at)-self.first) \
1618 / (self.last-self.first)
1619 if vvalue <= 1.0
and vvalue >= 0.0:
1620 vvalues.append(vvalue)
1621 marks.append(str(at))
1622 cb1 = mpl.colorbar.ColorbarBase(
1623 ax1, cmap=cmap, norm=norm, ticks=vvalues,
1624 orientation=
'horizontal')
1625 print(self.first, self.last, marks, vvalues)
1626 cb1.ax.set_xticklabels(marks)
1627 cb1.set_label(
'Angstorm')
1628 plt.savefig(filename, dpi=150, transparent=
True)
1633 """Given a Chimera color name or hex color value, return RGB"""
1634 d = {
'aquamarine': (0.4980392156862745, 1.0, 0.8313725490196079),
1635 'black': (0.0, 0.0, 0.0),
1636 'blue': (0.0, 0.0, 1.0),
1637 'brown': (0.6470588235, 0.16470588235294117, 0.16470588235294117),
1638 'chartreuse': (0.4980392156862745, 1.0, 0.0),
1639 'coral': (1.0, 0.4980392156862745, 0.3137254901960784),
1640 'cornflower blue': (0.39215686, 0.58431372549, 0.9294117647058824),
1641 'cyan': (0.0, 1.0, 1.0),
1642 'dark cyan': (0.0, 0.5450980392156862, 0.5450980392156862),
1643 'dark gray': (0.6627450980, 0.6627450980392157, 0.6627450980392157),
1644 'dark green': (0.0, 0.39215686274509803, 0.0),
1645 'dark khaki': (0.74117647, 0.7176470588235294, 0.4196078431372549),
1646 'dark magenta': (0.5450980392156862, 0.0, 0.5450980392156862),
1647 'dark olive green': (0.333333333, 0.419607843, 0.1843137254901961),
1648 'dark red': (0.5450980392156862, 0.0, 0.0),
1649 'dark slate blue': (0.28235294, 0.239215686, 0.5450980392156862),
1650 'dark slate gray': (0.1843137, 0.30980392, 0.30980392156862746),
1651 'deep pink': (1.0, 0.0784313725490196, 0.5764705882352941),
1652 'deep sky blue': (0.0, 0.7490196078431373, 1.0),
1653 'dim gray': (0.41176470, 0.4117647058823529, 0.4117647058823529),
1654 'dodger blue': (0.11764705882352941, 0.5647058823529412, 1.0),
1655 'firebrick': (0.6980392, 0.13333333333333333, 0.13333333333333333),
1656 'forest green': (0.13333333, 0.5450980392156862, 0.13333333333333333),
1657 'gold': (1.0, 0.8431372549019608, 0.0),
1658 'goldenrod': (0.85490196, 0.6470588235294118, 0.12549019607843137),
1659 'gray': (0.7450980392156863, 0.7450980392156863, 0.7450980392156863),
1660 'green': (0.0, 1.0, 0.0),
1661 'hot pink': (1.0, 0.4117647058823529, 0.7058823529411765),
1662 'khaki': (0.9411764705882353, 0.9019607843137255, 0.5490196078431373),
1663 'light blue': (0.67843137, 0.8470588235294118, 0.9019607843137255),
1664 'light gray': (0.82745098, 0.8274509803921568, 0.8274509803921568),
1665 'light green': (0.56470588, 0.9333333333333333, 0.5647058823529412),
1666 'light sea green': (0.125490, 0.6980392156862745, 0.6666666666666666),
1667 'lime green': (0.1960784, 0.803921568627451, 0.19607843137254902),
1668 'magenta': (1.0, 0.0, 1.0),
1669 'medium blue': (0.1960784, 0.19607843137254902, 0.803921568627451),
1670 'medium purple': (0.57647, 0.4392156862745098, 0.8588235294117647),
1671 'navy blue': (0.0, 0.0, 0.5019607843137255),
1672 'olive drab': (0.4196078, 0.5568627450980392, 0.13725490196078433),
1673 'orange red': (1.0, 0.27058823529411763, 0.0),
1674 'orange': (1.0, 0.4980392156862745, 0.0),
1675 'orchid': (0.85490196, 0.4392156862745098, 0.8392156862745098),
1676 'pink': (1.0, 0.7529411764705882, 0.796078431372549),
1677 'plum': (0.8666666666666667, 0.6274509803921569, 0.8666666666666667),
1678 'purple': (0.62745098, 0.12549019607843137, 0.9411764705882353),
1679 'red': (1.0, 0.0, 0.0),
1680 'rosy brown': (0.7372549, 0.5607843137254902, 0.5607843137254902),
1681 'salmon': (0.980392, 0.5019607843137255, 0.4470588235294118),
1682 'sandy brown': (0.956862745, 0.6431372549019608, 0.3764705882352941),
1683 'sea green': (0.18039, 0.5450980392156862, 0.3411764705882353),
1684 'sienna': (0.6274509, 0.3215686274509804, 0.17647058823529413),
1685 'sky blue': (0.52941176, 0.807843137254902, 0.9215686274509803),
1686 'slate gray': (0.439215686, 0.50196078, 0.5647058823529412),
1687 'spring green': (0.0, 1.0, 0.4980392156862745),
1688 'steel blue': (0.2745098, 0.50980392, 0.70588235),
1689 'tan': (0.8235294117647058, 0.7058823529411765, 0.5490196078431373),
1690 'turquoise': (0.25098039, 0.87843137, 0.81568627),
1691 'violet red': (0.81568627, 0.125490196, 0.56470588235),
1692 'white': (1.0, 1.0, 1.0),
1693 'yellow': (1.0, 1.0, 0.0)}
1694 if colorname.startswith(
'#'):
1695 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.
void add_particle(RMF::FileHandle fh, Particle *hs)
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)
def deprecated_object
Python decorator to mark a class as deprecated.
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 ...