6 from collections
import defaultdict
17 """Take iterable of TempResidues and return compatified string"""
20 idxs = [r.get_index()
for r
in res]
23 cur_range = [idxs[0], idxs[0]]
25 if idx != cur_range[1]+1:
26 all_ranges.append(cur_range)
27 cur_range = [idx, idx]
29 all_ranges.append(cur_range)
31 for nr, r
in enumerate(all_ranges):
32 ret +=
'%i-%i' % (r[0], r[1])
33 if nr < len(all_ranges)-1:
38 def _select_ca_or_p(hiers, **kwargs):
39 """Select all CA (amino acids) or P (nucleic acids) as appropriate"""
41 ps = sel_p.get_selected_particles()
49 atom_type=_AT_HET_CA, **kwargs)
50 return sel.get_selected_particles()
53 def get_structure(model, pdb_fn, chain_id, res_range=None, offset=0,
54 model_num=
None, ca_only=
False):
55 """read a structure from a PDB file and return a list of residues
56 @param model The IMP model
57 @param pdb_fn The file to read (in mmCIF, BinaryCIF, or legacy PDB format)
58 @param chain_id Chain ID to read
59 @param res_range Add only a specific set of residues.
60 res_range[0] is the starting and res_range[1] is the ending
62 The ending residue can be "END", that will take everything
63 to the end of the sequence.
65 @param offset Apply an offset to the residue indexes of the PDB file
66 @param model_num Read multi-model PDB and return that model (0-based index)
67 @param ca_only Read only CA atoms (by default, all non-waters are read)
70 if pdb_fn.endswith(
'.cif'):
71 read_file = IMP.atom.read_mmcif
72 read_multi_file = IMP.atom.read_multimodel_mmcif
73 elif pdb_fn.endswith(
'.bcif'):
74 read_file = IMP.atom.read_bcif
75 read_multi_file = IMP.atom.read_multimodel_bcif
77 read_file = IMP.atom.read_pdb
78 read_multi_file = IMP.atom.read_multimodel_pdb
84 reader = read_file
if model_num
is None else read_multi_file
86 if model_num
is not None:
89 if res_range == []
or res_range
is None:
90 ps = _select_ca_or_p(mh, chain=chain_id)
96 mh.get_children()[0].get_children()[-1]).
get_index()
97 ps = _select_ca_or_p(mh, chain=chain_id,
98 residue_indexes=range(start, end+1))
103 res.set_index(res.get_index() + offset)
107 "no residues selected from %s in range %s" % (pdb_fn, res_range),
112 def build_bead(model, residues, input_coord=None):
113 """Generates a single bead"""
121 if ds_frag[0] == ds_frag[-1]:
122 rt = residues[0].get_residue_type()
124 h.set_name(
'%i_bead' % (ds_frag[0]))
125 prt.set_name(
'%i_bead' % (ds_frag[0]))
132 ptem.set_radius(radius)
135 h.set_name(
'%i-%i_bead' % (ds_frag[0], ds_frag[-1]))
136 prt.set_name(
'%i-%i_bead' % (ds_frag[0], ds_frag[-1]))
137 h.set_residue_indexes(range(ds_frag[0], ds_frag[-1] + 1))
139 radius = 0.8 * (3.0 / 4.0 / math.pi * volume) ** (1.0 / 3.0)
140 ptem.set_radius(radius)
144 if tuple(input_coord)
is not None:
145 ptem.set_coordinates(input_coord)
151 def build_necklace(model, residues, resolution, input_coord=None):
152 """Generates a string of beads with given length"""
156 out_hiers.append(build_bead(model, chunk, input_coord=input_coord))
160 def build_ca_centers(model, residues):
161 """Create a bead on the CA position with coarsened size and mass"""
163 for tempres
in residues:
164 residue = tempres.get_hierarchy()
166 rp1.set_name(
"Residue_%i" % residue.get_index())
167 rt = residue.get_residue_type()
180 atom_types=[IMP.atom.AT_CA, _AT_HET_CA]).get_selected_particles()
182 residue, atom_type=IMP.atom.AT_P).get_selected_particles()
185 central_atom = calpha[0]
190 "build_ca_centers: weird selection (no CA, no "
191 "nucleotide P or ambiguous selection found)")
197 out_hiers.append(this_res)
201 def setup_bead_as_gaussian(mh):
202 """Setup bead as spherical gaussian, using radius as variance"""
203 p = mh.get_particle()
213 def show_representation(node):
217 resolutions = repr.get_resolutions()
218 for r
in resolutions:
219 print(
'---- resolution %i ----' % r)
226 def _get_color_for_representation(rep):
227 """Return an IMP.display.Color object (or None) for the given
229 if rep.color
is not None:
230 if isinstance(rep.color, float):
232 elif isinstance(rep.color, str):
234 elif hasattr(rep.color,
'__iter__')
and len(rep.color) == 3:
239 raise TypeError(
"Color must be Chimera color name, a hex "
240 "string, a float or (r,g,b) tuple")
243 def _add_fragment_provenance(fragment, first_residue, rephandler):
244 """Track the original source of a fragment's structure.
245 If the residues in the given fragment were extracted from a PDB
246 file, add suitable provenance information to the Model (the name
247 of that file, chain ID, and residue index offset)."""
248 pdb_element = rephandler.pdb_for_residue.get(first_residue.get_index())
250 m = fragment.get_model()
253 p, pdb_element.filename, pdb_element.chain_id, pdb_element.offset)
258 def build_representation(parent, rep, coord_finder, rephandler):
259 """Create requested representation.
260 For beads, identifies continuous segments and sets up as Representation.
261 If any volume-based representations (e.g.,densities) are requested,
262 will instead create a single Representation node.
263 All reps are added as children of the passed parent.
264 @param parent The Molecule to which we'll add representations
265 @param rep What to build. An instance of pmi::topology::_Representation
266 @param coord_finder A _FindCloseStructure object to help localize beads
271 model = parent.hier.get_model()
272 _start_model = parent._start_model
273 color = _get_color_for_representation(rep)
277 primary_resolution = min(rep.bead_resolutions)
284 if rep.density_residues_per_component:
286 num_components = math.ceil(
287 len(rep.residues) / rep.density_residues_per_component)
288 rep_dict = defaultdict(list)
291 segp, primary_resolution)
292 built_reps.append(root_representation)
293 res_nums = [r.get_index()
for r
in rep.residues]
297 density_frag.get_particle().set_name(
298 "Densities %i" % rep.density_residues_per_component)
301 if os.path.exists(rep.density_prefix +
'.txt') \
302 and not rep.density_force_compute:
304 rep.density_prefix +
'.txt', density_ps, model)
305 if (len(density_ps) != num_components
306 or not os.path.exists(rep.density_prefix +
'.txt')
307 or rep.density_force_compute):
310 for r
in rep.residues:
322 mass_multiplier=total_mass)
325 rep.density_prefix +
'.txt')
326 if rep.density_voxel_size > 0.0:
328 density_ps, rep.density_prefix +
'.mrc',
329 rep.density_voxel_size, fast=
True)
331 for n, d
in enumerate(density_ps):
332 d.set_name(
'Density #%d' % n)
333 density_frag.add_child(d)
334 root_representation.add_representation(
335 density_frag, IMP.atom.DENSITIES,
336 rep.density_residues_per_component)
340 rsort = sorted(list(rep.residues), key=
lambda r: r.get_index())
342 prev_structure = rsort[0].get_has_structure()
345 for nr, r
in enumerate(rsort):
346 if (r.get_index() != prev_idx+1
347 or r.get_has_structure() != prev_structure
or force_break):
348 segments.append(cur_seg)
352 prev_idx = r.get_index()
353 prev_structure = r.get_has_structure()
354 if r.get_index()-1
in rep.bead_extra_breaks:
357 segments.append(cur_seg)
362 for frag_res
in segments:
363 res_nums = [r.get_index()
for r
in frag_res]
364 rrange =
"%i-%i" % (res_nums[0], res_nums[-1])
365 name =
"Frag_" + rrange
367 name_all += rrange +
','
368 elif name_count == 3:
375 segp, primary_resolution)
376 built_reps.append(this_representation)
377 for resolution
in rep.bead_resolutions:
380 this_resolution.set_name(
"%s: Res %i" % (name, resolution))
381 if frag_res[0].get_has_structure():
382 pdb_element = _add_fragment_provenance(
383 this_resolution, frag_res[0], rephandler)
384 if pdb_element
is not None:
385 prov_dict[resolution] = pdb_element
387 if resolution == atomic_res:
388 for residue
in frag_res:
389 this_resolution.add_child(residue.get_hierarchy(model))
390 elif resolution == ca_res
and rep.bead_ca_centers:
391 beads = build_ca_centers(model, frag_res)
393 this_resolution.add_child(bead)
397 for residue
in frag_res:
398 tempc.add_child(residue.hier)
400 tempc, resolution,
False, model)
401 for bead
in beads.get_children():
402 this_resolution.add_child(bead)
403 _start_model.remove_particle(tempc.get_particle_index())
404 model.remove_particle(beads.get_particle_index())
407 input_coord = coord_finder.find_nearest_coord(
408 min(r.get_index()
for r
in frag_res))
409 if input_coord
is None:
410 input_coord = rep.bead_default_coord
411 beads = build_necklace(model,
416 this_resolution.add_child(bead)
427 rep_dict[resolution] += this_resolution.get_children()
429 if resolution == primary_resolution:
430 this_representation.add_child(this_resolution)
432 this_representation.add_representation(this_resolution,
436 if rep.setup_particles_as_densities:
438 setup_bead_as_gaussian(p)
439 this_resolution.set_name(
440 this_resolution.get_name() +
' Densities %i' % resolution)
441 this_representation.add_representation(this_resolution,
446 root_representation.set_name(name_all.strip(
',') +
": Base")
447 d = root_representation.get_representations(IMP.atom.DENSITIES)
448 d[0].set_name(
'%s: ' % name_all + d[0].get_name())
449 for resolution
in rep.bead_resolutions:
452 [r.get_index()
for r
in rep.residues])
453 this_resolution.set_name(
"%s: Res %i" % (name_all, resolution))
457 if prov_dict.get(resolution):
458 pdb_element = prov_dict[resolution]
461 pdb_element.filename,
462 pdb_element.chain_id, pdb_element.offset)
464 for hier
in rep_dict[resolution]:
465 this_resolution.add_child(hier)
466 if resolution == primary_resolution:
467 root_representation.add_child(this_resolution)
469 root_representation.add_representation(this_resolution,
double get_volume_from_residue_type(ResidueType rt)
Return an estimate for the volume of a given residue.
static Gaussian setup_particle(Model *m, ParticleIndex pi)
void show_molecular_hierarchy(Hierarchy h)
Print out the molecular hierarchy.
static Fragment setup_particle(Model *m, ParticleIndex pi)
double get_mass(const Selection &s)
Get the total mass of a hierarchy, in Daltons.
static XYZR setup_particle(Model *m, ParticleIndex pi)
double get_mass(ResidueType c)
Get the mass from the residue type.
static StructureProvenance setup_particle(Model *m, ParticleIndex pi, std::string filename, std::string chain_id, int residue_offset)
Color get_rgb_color(double f)
Return the color for f from the RGB color map.
double get_mass_from_number_of_residues(unsigned int num_aa)
Estimate the mass of a protein from the number of amino acids.
double get_ball_radius_from_volume_3d(double volume)
Return the radius of a sphere with a given volume.
static Residue setup_particle(Model *m, ParticleIndex pi, ResidueType t, int index, int insertion_code)
static Representation setup_particle(Model *m, ParticleIndex pi)
GenericHierarchies get_leaves(Hierarchy mhd)
Get all the leaves of the bit of hierarchy.
Warning related to handling of structures.
A Gaussian distribution in 3D.
A decorator for a representation.
double get_volume_from_mass(double m, ProteinDensityReference ref=ALBER)
Estimate the volume of a protein from its mass.
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
A decorator for a particle representing an atom.
static Mass setup_particle(Model *m, ParticleIndex pi, Float mass)
PDBSelector * get_default_pdb_selector()
A decorator for a particle with x,y,z coordinates.
static Colored setup_particle(Model *m, ParticleIndex pi, Color color)
A decorator for a residue.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
Rotation3D get_identity_rotation_3d()
Return a rotation that does not do anything.
Class to handle individual particles of a Model object.
Hierarchy create_simplified_along_backbone(Chain input, const IntRanges &residue_segments, bool keep_detailed=false, Model *m=nullptr)
Select all CA ATOM records.
Python classes to represent, score, sample and analyze models.
Functionality for loading, creating, manipulating and scoring atomic structures.
void add_provenance(Model *m, ParticleIndex pi, Provenance p)
Add provenance to part of the model.
static Chain setup_particle(Model *m, ParticleIndex pi, std::string id)
An exception for an invalid value being passed to IMP.
Select hierarchy particles identified by the biological name.
Select all ATOM and HETATM records with the given chain ids.
A decorator for a particle with x,y,z coordinates and a radius.