1 """@namespace IMP.pmi1.mmcif
2 @brief Support for the mmCIF file format.
4 IMP has basic support for writing out files in mmCIF format, for
5 deposition in [PDB-Dev](https://pdb-dev.wwpdb.org/).
6 mmCIF files are currently generated by creating an
7 IMP.pmi1.mmcif.ProtocolOutput class, and attaching it to an
8 IMP.pmi1.representation.Representation object, after which any
9 generated models and metadata are collected and output as mmCIF.
12 from __future__
import print_function
41 import ihm.representation
44 def _assign_id(obj, seen_objs, obj_by_id):
45 """Assign a unique ID to obj, and track all ids in obj_by_id."""
46 if obj
not in seen_objs:
47 if not hasattr(obj,
'id'):
49 obj.id = len(obj_by_id)
50 seen_objs[obj] = obj.id
52 obj.id = seen_objs[obj]
55 def _get_by_residue(p):
56 """Determine whether the given particle represents a specific residue
57 or a more coarse-grained object."""
61 class _ComponentMapper(object):
62 """Map a Particle to a component name"""
63 def __init__(self, prot):
66 self.name =
'cif-output'
67 self.o.dictionary_pdbs[self.name] = self.prot
68 self.o._init_dictchain(self.name, self.prot, multichar_chain=
True)
70 def __getitem__(self, p):
71 protname, is_a_bead = self.o.get_prot_name_from_particle(self.name, p)
75 class _AsymMapper(object):
76 """Map a Particle to an asym_unit"""
77 def __init__(self, simo, prot):
79 self._cm = _ComponentMapper(prot)
81 def __getitem__(self, p):
82 protname = self._cm[p]
83 return self.simo.asym_units[protname]
85 def get_feature(self, ps):
86 """Get an ihm.restraint.Feature that covers the given particles"""
94 rngs.append(asym(rind, rind))
98 rngs.append(asym(rinds[0], rinds[-1]))
100 raise ValueError(
"Unsupported particle type %s" % str(p))
101 return ihm.restraint.ResidueFeature(rngs)
104 class _AllSoftware(object):
105 def __init__(self, system):
107 self.modeller_used = self.phyre2_used =
False
108 self.system.software.extend([
110 name=
"Integrative Modeling Platform (IMP)",
111 version=IMP.__version__,
112 classification=
"integrative model building",
113 description=
"integrative model building",
114 location=
'https://integrativemodeling.org'),
116 name=
"IMP PMI module",
117 version=IMP.pmi1.__version__,
118 classification=
"integrative model building",
119 description=
"integrative model building",
120 location=
'https://integrativemodeling.org')])
122 def set_modeller_used(self, version, date):
123 if self.modeller_used:
125 self.modeller_used =
True
126 self.system.software.append(ihm.Software(
127 name=
'MODELLER', classification=
'comparative modeling',
128 description=
'Comparative modeling by satisfaction '
129 'of spatial restraints, build ' + date,
130 location=
'https://salilab.org/modeller/',
133 def set_phyre2_used(self):
136 self.phyre2_used =
True
137 self.system.software.append(ihm.Software(
138 name=
'Phyre2', classification=
'protein homology modeling',
139 description=
'Protein Homology/analogY Recognition '
142 location=
'http://www.sbg.bio.ic.ac.uk/~phyre2/'))
144 def _get_fragment_is_rigid(fragment):
145 """Determine whether a fragment is modeled rigidly"""
150 class _PDBFragment(ihm.representation.ResidueSegment):
151 """Record details about part of a PDB file used as input
153 def __init__(self, state, component, start, end, pdb_offset,
154 pdbname, chain, hier, asym_unit):
156 super(_PDBFragment, self).__init__(
157 asym_unit=asym_unit.pmi_range(start, end),
158 rigid=
None, primitive=
'sphere')
159 self.component, self.start, self.end, self.offset, self.pdbname \
160 = component, start, end, pdb_offset, pdbname
161 self.state, self.chain, self.hier = state, chain, hier
166 rigid = property(
lambda self: _get_fragment_is_rigid(self),
167 lambda self, val:
None)
169 def combine(self, other):
173 class _BeadsFragment(ihm.representation.FeatureSegment):
174 """Record details about beads used to represent part of a component."""
176 def __init__(self, state, component, start, end, count, hier, asym_unit):
177 super(_BeadsFragment, self).__init__(asym_unit=asym_unit(start, end),
178 rigid=
None, primitive=
'sphere', count=count)
179 self.state, self.component, self.hier \
180 = state, component, hier
182 rigid = property(
lambda self: _get_fragment_is_rigid(self),
183 lambda self, val:
None)
185 def combine(self, other):
187 if type(other) == type(self)
and \
188 other.asym_unit.seq_id_range[0] == self.asym_unit.seq_id_range[1] + 1:
189 self.asym_unit.seq_id_range = (self.asym_unit.seq_id_range[0],
190 other.asym_unit.seq_id_range[1])
191 self.count += other.count
195 class _AllModelRepresentations(object):
196 def __init__(self, simo):
200 self.fragments = OrderedDict()
201 self._all_representations = {}
203 def copy_component(self, state, name, original, asym_unit):
204 """Copy all representation for `original` in `state` to `name`"""
207 newf.asym_unit = asym_unit(*f.asym_unit.seq_id_range)
209 for rep
in self.fragments:
210 if original
in self.fragments[rep]:
211 if name
not in self.fragments[rep]:
212 self.fragments[rep][name] = OrderedDict()
213 self.fragments[rep][name][state] = [copy_frag(f)
214 for f
in self.fragments[rep][original][state]]
217 first_state = list(self.fragments[rep][name].keys())[0]
218 if state
is first_state:
219 representation = self._all_representations[rep]
220 representation.extend(self.fragments[rep][name][state])
222 def add_fragment(self, state, representation, fragment):
223 """Add a model fragment."""
224 comp = fragment.component
225 id_rep = id(representation)
226 self._all_representations[id_rep] = representation
227 if id_rep
not in self.fragments:
228 self.fragments[id_rep] = OrderedDict()
229 if comp
not in self.fragments[id_rep]:
230 self.fragments[id_rep][comp] = OrderedDict()
231 if state
not in self.fragments[id_rep][comp]:
232 self.fragments[id_rep][comp][state] = []
233 fragments = self.fragments[id_rep][comp][state]
234 if len(fragments) == 0
or not fragments[-1].combine(fragment):
235 fragments.append(fragment)
238 first_state = list(self.fragments[id_rep][comp].keys())[0]
239 if state
is first_state:
240 representation.append(fragment)
243 class _AllDatasets(object):
244 """Track all datasets generated by PMI and add them to the ihm.System"""
245 def __init__(self, system):
248 self._datasets_by_state = {}
249 self._restraints_by_state = {}
251 def get_all_group(self, state):
252 """Get a DatasetGroup encompassing all datasets so far in this state"""
256 g = ihm.dataset.DatasetGroup(self._datasets_by_state.get(state, [])
257 + [r.dataset
for r
in self._restraints_by_state.get(state, [])
261 def add(self, state, dataset):
262 """Add a new dataset."""
263 self._datasets.append(dataset)
264 if state
not in self._datasets_by_state:
265 self._datasets_by_state[state] = []
266 self._datasets_by_state[state].append(dataset)
269 self.system.orphan_datasets.append(dataset)
273 """Add the dataset for a restraint"""
274 if state
not in self._restraints_by_state:
275 self._restraints_by_state[state] = []
276 self._restraints_by_state[state].append(restraint)
279 class _CrossLinkRestraint(ihm.restraint.CrossLinkRestraint):
280 """Restrain to a set of cross links"""
283 _label_map = {
'wtDSS':
'DSS',
'scDSS':
'DSS',
'scEDC':
'EDC'}
285 def __init__(self, pmi_restraint):
286 self.pmi_restraint = pmi_restraint
287 label = self.pmi_restraint.label
289 label = self._label_map.get(label, label)
291 super(_CrossLinkRestraint, self).__init__(
292 dataset=self.pmi_restraint.dataset,
295 def _set_psi_sigma(self, model):
298 if model.m != self.pmi_restraint.m:
300 for resolution
in self.pmi_restraint.sigma_dictionary:
301 statname =
'ISDCrossLinkMS_Sigma_%s_%s' % (resolution, self.label)
302 if model.stats
and statname
in model.stats:
303 sigma = float(model.stats[statname])
304 p = self.pmi_restraint.sigma_dictionary[resolution][0]
305 old_values.append((p, p.get_scale()))
307 for psiindex
in self.pmi_restraint.psi_dictionary:
308 statname =
'ISDCrossLinkMS_Psi_%s_%s' % (psiindex, self.label)
309 if model.stats
and statname
in model.stats:
310 psi = float(model.stats[statname])
311 p = self.pmi_restraint.psi_dictionary[psiindex][0]
312 old_values.append((p, p.get_scale()))
316 return list(reversed(old_values))
318 def add_fits_from_model_statfile(self, model):
320 old_values = self._set_psi_sigma(model)
324 for xl
in self.cross_links:
326 xl.fits[model] = ihm.restraint.CrossLinkFit(
327 psi=xl.psi, sigma1=xl.sigma1, sigma2=xl.sigma2)
329 for p, scale
in old_values:
333 def __set_dataset(self, val):
334 self.pmi_restraint.dataset = val
335 dataset = property(
lambda self: self.pmi_restraint.dataset,
339 def get_asym_mapper_for_state(simo, state, asym_map):
340 asym = asym_map.get(state,
None)
342 asym = _AsymMapper(simo, state.prot)
343 asym_map[state] = asym
346 class _PMICrossLink(object):
349 psi = property(
lambda self: self.psi_p.get_scale(),
350 lambda self, val:
None)
351 sigma1 = property(
lambda self: self.sigma1_p.get_scale(),
352 lambda self, val:
None)
353 sigma2 = property(
lambda self: self.sigma2_p.get_scale(),
354 lambda self, val:
None)
357 class _ResidueCrossLink(ihm.restraint.ResidueCrossLink, _PMICrossLink):
361 class _FeatureCrossLink(ihm.restraint.FeatureCrossLink, _PMICrossLink):
365 class _EM2DRestraint(ihm.restraint.EM2DRestraint):
366 def __init__(self, state, pmi_restraint, image_number, resolution,
367 pixel_size, image_resolution, projection_number,
369 self.pmi_restraint, self.image_number = pmi_restraint, image_number
370 super(_EM2DRestraint, self).__init__(
371 dataset=pmi_restraint.datasets[image_number],
372 assembly=state.modeled_assembly,
373 segment=
False, number_raw_micrographs=micrographs_number,
374 pixel_size_width=pixel_size, pixel_size_height=pixel_size,
375 image_resolution=image_resolution,
376 number_of_projections=projection_number)
379 def __get_dataset(self):
380 return self.pmi_restraint.datasets[self.image_number]
381 def __set_dataset(self, val):
382 self.pmi_restraint.datasets[self.image_number] = val
383 dataset = property(__get_dataset, __set_dataset)
385 def add_fits_from_model_statfile(self, model):
386 ccc = self._get_cross_correlation(model)
387 transform = self._get_transformation(model)
388 rot = transform.get_rotation()
389 rm = [[e
for e
in rot.get_rotation_matrix_row(i)]
for i
in range(3)]
390 self.fits[model] = ihm.restraint.EM2DRestraintFit(
391 cross_correlation_coefficient=ccc,
393 tr_vector=transform.get_translation())
395 def _get_transformation(self, model):
396 """Get the transformation that places the model on the image"""
397 stats = model.em2d_stats
or model.stats
398 prefix =
'ElectronMicroscopy2D_%s_Image%d' % (self.pmi_restraint.label,
399 self.image_number + 1)
400 r = [float(stats[prefix +
'_Rotation%d' % i])
for i
in range(4)]
401 t = [float(stats[prefix +
'_Translation%d' % i])
405 inv = model.transform.get_inverse()
409 def _get_cross_correlation(self, model):
410 """Get the cross correlation coefficient between the model projection
412 stats = model.em2d_stats
or model.stats
413 return float(stats[
'ElectronMicroscopy2D_%s_Image%d_CCC'
414 % (self.pmi_restraint.label,
415 self.image_number + 1)])
418 class _EM3DRestraint(ihm.restraint.EM3DRestraint):
420 def __init__(self, simo, state, pmi_restraint, target_ps, densities):
421 self.pmi_restraint = pmi_restraint
422 super(_EM3DRestraint, self).__init__(
423 dataset=pmi_restraint.dataset,
424 assembly=self._get_assembly(densities, simo, state),
425 fitting_method=
'Gaussian mixture models',
426 number_of_gaussians=len(target_ps))
429 def __set_dataset(self, val):
430 self.pmi_restraint.dataset = val
431 dataset = property(
lambda self: self.pmi_restraint.dataset,
434 def _get_assembly(self, densities, simo, state):
435 """Get the Assembly that this restraint acts on"""
436 cm = _ComponentMapper(state.prot)
439 components[cm[d]] =
None
440 a = simo._get_subassembly(components,
441 name=
"EM subassembly",
442 description=
"All components that fit the EM map")
445 def add_fits_from_model_statfile(self, model):
446 ccc = self._get_cross_correlation(model)
447 self.fits[model] = ihm.restraint.EM3DRestraintFit(
448 cross_correlation_coefficient=ccc)
450 def _get_cross_correlation(self, model):
451 """Get the cross correlation coefficient between the model
453 if model.stats
is not None:
454 return float(model.stats[
'GaussianEMRestraint_%s_CCC'
455 % self.pmi_restraint.label])
458 class _GeometricRestraint(ihm.restraint.GeometricRestraint):
460 def __init__(self, simo, state, pmi_restraint, geometric_object,
461 feature, distance, sigma):
462 self.pmi_restraint = pmi_restraint
463 super(_GeometricRestraint, self).__init__(
464 dataset=pmi_restraint.dataset,
465 geometric_object=geometric_object, feature=feature,
466 distance=distance, harmonic_force_constant = 1. / sigma,
470 def __set_dataset(self, val):
471 self.pmi_restraint.dataset = val
472 dataset = property(
lambda self: self.pmi_restraint.dataset,
476 class _ReplicaExchangeProtocolStep(ihm.protocol.Step):
477 def __init__(self, state, rex):
478 if rex.monte_carlo_sample_objects
is not None:
479 method =
'Replica exchange monte carlo'
481 method =
'Replica exchange molecular dynamics'
482 super(_ReplicaExchangeProtocolStep, self).__init__(
483 assembly=state.modeled_assembly,
485 method=method, name=
'Sampling',
486 num_models_begin=
None,
487 num_models_end=rex.vars[
"number_of_frames"],
488 multi_scale=
True, multi_state=
False, ordered=
False)
491 class _SimpleProtocolStep(ihm.protocol.Step):
492 def __init__(self, state, num_models_end, method):
493 super(_SimpleProtocolStep, self).__init__(
494 assembly=state.modeled_assembly,
496 method=method, name=
'Sampling',
497 num_models_begin=
None,
498 num_models_end=num_models_end,
499 multi_scale=
True, multi_state=
False, ordered=
False)
502 class _Chain(object):
503 """Represent a single chain in a Model"""
504 def __init__(self, pmi_chain_id, asym_unit):
505 self.pmi_chain_id, self.asym_unit = pmi_chain_id, asym_unit
509 def add(self, xyz, atom_type, residue_type, residue_index,
510 all_indexes, radius):
511 if atom_type
is None:
512 self.spheres.append((xyz, residue_type, residue_index,
513 all_indexes, radius))
515 self.atoms.append((xyz, atom_type, residue_type, residue_index,
516 all_indexes, radius))
517 orig_comp = property(
lambda self: self.comp)
519 class _TransformedChain(object):
520 """Represent a chain that is a transformed version of another"""
521 def __init__(self, orig_chain, asym_unit, transform):
522 self.orig_chain, self.asym_unit = orig_chain, asym_unit
523 self.transform = transform
525 def __get_spheres(self):
526 for (xyz, residue_type, residue_index, all_indexes,
527 radius)
in self.orig_chain.spheres:
528 yield (self.transform * xyz, residue_type, residue_index,
530 spheres = property(__get_spheres)
532 def __get_atoms(self):
533 for (xyz, atom_type, residue_type, residue_index, all_indexes,
534 radius)
in self.orig_chain.atoms:
535 yield (self.transform * xyz, atom_type, residue_type, residue_index,
537 atoms = property(__get_atoms)
539 entity = property(
lambda self: self.orig_chain.entity)
540 orig_comp = property(
lambda self: self.orig_chain.comp)
542 class _Excluder(object):
543 def __init__(self, component, simo):
544 self._seqranges = simo._exclude_coords.get(component, [])
546 def is_excluded(self, indexes):
547 """Return True iff the given sequence range is excluded."""
548 for seqrange
in self._seqranges:
549 if indexes[0] >= seqrange[0]
and indexes[-1] <= seqrange[1]:
553 class _Model(ihm.model.Model):
554 def __init__(self, prot, simo, protocol, assembly, representation):
555 super(_Model, self).__init__(assembly=assembly, protocol=protocol,
556 representation=representation)
557 self.simo = weakref.proxy(simo)
563 self.em2d_stats =
None
566 self._is_restrained =
True
569 self.m = prot.get_model()
570 o.dictionary_pdbs[name] = prot
571 o._init_dictchain(name, prot, multichar_chain=
True)
572 (particle_infos_for_pdb,
573 self.geometric_center) = o.get_particle_infos_for_pdb_writing(name)
575 self._make_spheres_atoms(particle_infos_for_pdb, o, name, simo)
578 def all_chains(self, simo):
579 """Yield all chains, including transformed ones"""
581 for c
in self.chains:
583 chain_for_comp[c.comp] = c
584 for tc
in simo._transformed_components:
585 orig_chain = chain_for_comp.get(tc.original,
None)
587 asym = simo.asym_units[tc.name]
588 c = _TransformedChain(orig_chain, asym, tc.transform)
592 def _make_spheres_atoms(self, particle_infos_for_pdb, o, name, simo):
593 entity_for_chain = {}
596 for protname, chain_id
in o.dictchain[name].items():
597 entity_for_chain[chain_id] = simo.entities[protname]
598 comp_for_chain[chain_id] = protname
602 correct_asym[chain_id] = simo.asym_units[protname]
609 for (xyz, atom_type, residue_type, chain_id, residue_index,
610 all_indexes, radius)
in particle_infos_for_pdb:
611 if chain
is None or chain.pmi_chain_id != chain_id:
612 chain = _Chain(chain_id, correct_asym[chain_id])
613 chain.entity = entity_for_chain[chain_id]
614 chain.comp = comp_for_chain[chain_id]
615 self.chains.append(chain)
616 excluder = _Excluder(chain.comp, simo)
617 if not excluder.is_excluded(all_indexes
if all_indexes
618 else [residue_index]):
619 chain.add(xyz, atom_type, residue_type, residue_index,
622 def parse_rmsf_file(self, fname, component):
623 self.rmsf[component] = rmsf = {}
624 with open(fname)
as fh:
626 resnum, blocknum, val = line.split()
627 rmsf[int(resnum)] = (int(blocknum), float(val))
629 def get_rmsf(self, component, indexes):
630 """Get the RMSF value for the given residue indexes."""
633 rmsf = self.rmsf[component]
634 blocknums = dict.fromkeys(rmsf[ind][0]
for ind
in indexes)
635 if len(blocknums) != 1:
636 raise ValueError(
"Residue indexes %s aren't all in the same block"
638 return rmsf[indexes[0]][1]
641 for chain
in self.all_chains(self.simo):
642 pmi_offset = chain.asym_unit.entity.pmi_offset
643 for atom
in chain.atoms:
644 (xyz, atom_type, residue_type, residue_index,
645 all_indexes, radius) = atom
646 pt = self.transform * xyz
647 yield ihm.model.Atom(asym_unit=chain.asym_unit,
648 seq_id=residue_index - pmi_offset,
649 atom_id=atom_type.get_string(),
651 x=pt[0], y=pt[1], z=pt[2])
653 def get_spheres(self):
654 for chain
in self.all_chains(self.simo):
655 pmi_offset = chain.asym_unit.entity.pmi_offset
656 for sphere
in chain.spheres:
657 (xyz, residue_type, residue_index,
658 all_indexes, radius) = sphere
659 if all_indexes
is None:
660 all_indexes = (residue_index,)
661 pt = self.transform * xyz
662 yield ihm.model.Sphere(asym_unit=chain.asym_unit,
663 seq_id_range=(all_indexes[0] - pmi_offset,
664 all_indexes[-1] - pmi_offset),
665 x=pt[0], y=pt[1], z=pt[2], radius=radius,
666 rmsf=self.get_rmsf(chain.orig_comp, all_indexes))
669 class _AllProtocols(object):
670 def __init__(self, simo):
671 self.simo = weakref.proxy(simo)
673 self.protocols = OrderedDict()
675 def add_protocol(self, state):
676 """Add a new Protocol"""
677 if state
not in self.protocols:
678 self.protocols[state] = []
679 p = ihm.protocol.Protocol()
680 self.simo.system.orphan_protocols.append(p)
681 self.protocols[state].append(p)
683 def add_step(self, step, state):
684 """Add a ProtocolStep to the last Protocol of the given State"""
685 if state
not in self.protocols:
686 self.add_protocol(state)
687 protocol = self.get_last_protocol(state)
688 if len(protocol.steps) == 0:
689 step.num_models_begin = 0
691 step.num_models_begin = protocol.steps[-1].num_models_end
692 protocol.steps.append(step)
693 step.id = len(protocol.steps)
695 step.dataset_group = self.simo.all_datasets.get_all_group(state)
697 def add_postproc(self, step, state):
698 """Add a postprocessing step to the last protocol"""
699 protocol = self.get_last_protocol(state)
700 if len(protocol.analyses) == 0:
701 protocol.analyses.append(ihm.analysis.Analysis())
702 protocol.analyses[-1].steps.append(step)
704 def get_last_protocol(self, state):
705 """Return the most recently-added _Protocol"""
706 return self.protocols[state][-1]
709 class _AllStartingModels(object):
710 def __init__(self, simo):
714 self.models = OrderedDict()
717 def add_pdb_fragment(self, fragment):
718 """Add a starting model PDB fragment."""
719 comp = fragment.component
720 state = fragment.state
721 if comp
not in self.models:
722 self.models[comp] = OrderedDict()
723 if state
not in self.models[comp]:
724 self.models[comp][state] = []
725 models = self.models[comp][state]
726 if len(models) == 0 \
727 or models[-1].fragments[0].pdbname != fragment.pdbname:
728 model = self._add_model(fragment)
732 models[-1].fragments.append(weakref.proxy(fragment))
734 pmi_offset = models[-1].asym_unit.entity.pmi_offset
735 sid_begin = min(fragment.start + fragment.offset - pmi_offset,
736 models[-1].asym_unit.seq_id_range[0])
737 sid_end = max(fragment.end + fragment.offset - pmi_offset,
738 models[-1].asym_unit.seq_id_range[1])
739 models[-1].asym_unit = fragment.asym_unit.asym(sid_begin, sid_end)
740 fragment.starting_model = models[-1]
742 def _add_model(self, f):
743 parser = ihm.metadata.PDBParser()
744 r = parser.parse_file(f.pdbname)
746 self.simo._add_dataset(r[
'dataset'])
748 templates = r[
'templates'].get(f.chain, [])
751 self.simo.system.locations.append(t.alignment_file)
753 self.simo._add_dataset(t.dataset)
754 pmi_offset = f.asym_unit.entity.pmi_offset
756 asym_unit=f.asym_unit.asym.pmi_range(f.start + f.offset,
758 dataset=r[
'dataset'], asym_id=f.chain,
759 templates=templates, offset=f.offset + pmi_offset,
760 metadata=r[
'metadata'],
761 software=r[
'software'][0]
if r[
'software']
else None,
762 script_file=r[
'script'])
763 m.fragments = [weakref.proxy(f)]
767 class _StartingModel(ihm.startmodel.StartingModel):
768 def get_seq_dif(self):
772 pmi_offset = self.asym_unit.entity.pmi_offset
773 mh = IMP.mmcif.data._StartingModelAtomHandler(self.templates,
775 for f
in self.fragments:
777 residue_indexes=list(range(f.start - f.offset,
778 f.end - f.offset + 1)))
779 for a
in mh.get_ihm_atoms(sel.get_selected_particles(),
780 f.offset - pmi_offset):
782 self._seq_dif = mh._seq_dif
785 class _ReplicaExchangeAnalysisPostProcess(ihm.analysis.ClusterStep):
786 """Post processing using AnalysisReplicaExchange0 macro"""
788 def __init__(self, rex, num_models_begin):
791 for fname
in self.get_all_stat_files():
792 with open(fname)
as fh:
793 num_models_end += len(fh.readlines())
794 super(_ReplicaExchangeAnalysisPostProcess, self).__init__(
795 feature=
'RMSD', num_models_begin=num_models_begin,
796 num_models_end=num_models_end)
798 def get_stat_file(self, cluster_num):
799 return os.path.join(self.rex._outputdir,
"cluster.%d" % cluster_num,
802 def get_all_stat_files(self):
803 for i
in range(self.rex._number_of_clusters):
804 yield self.get_stat_file(i)
807 class _ReplicaExchangeAnalysisEnsemble(ihm.model.Ensemble):
808 """Ensemble generated using AnalysisReplicaExchange0 macro"""
810 num_models_deposited =
None
812 def __init__(self, pp, cluster_num, model_group, num_deposit):
813 with open(pp.get_stat_file(cluster_num))
as fh:
814 num_models = len(fh.readlines())
815 super(_ReplicaExchangeAnalysisEnsemble, self).__init__(
816 num_models=num_models,
817 model_group=model_group, post_process=pp,
818 clustering_feature=pp.feature,
819 name=model_group.name)
820 self.cluster_num = cluster_num
821 self.num_models_deposited = num_deposit
823 def get_rmsf_file(self, component):
824 return os.path.join(self.post_process.rex._outputdir,
825 'cluster.%d' % self.cluster_num,
826 'rmsf.%s.dat' % component)
828 def load_rmsf(self, model, component):
829 fname = self.get_rmsf_file(component)
830 if os.path.exists(fname):
831 model.parse_rmsf_file(fname, component)
833 def get_localization_density_file(self, fname):
834 return os.path.join(self.post_process.rex._outputdir,
835 'cluster.%d' % self.cluster_num,
838 def load_localization_density(self, state, fname, select_tuple, asym_units):
839 fullpath = self.get_localization_density_file(fname)
840 if os.path.exists(fullpath):
841 details =
"Localization density for %s %s" \
842 % (fname, self.model_group.name)
843 local_file = ihm.location.OutputFileLocation(fullpath,
845 for s
in select_tuple:
846 if isinstance(s, tuple)
and len(s) == 3:
847 asym = asym_units[s[2]].pmi_range(s[0], s[1])
850 den = ihm.model.LocalizationDensity(file=local_file,
852 self.densities.append(den)
854 def load_all_models(self, simo, state):
855 stat_fname = self.post_process.get_stat_file(self.cluster_num)
857 with open(stat_fname)
as fh:
858 stats = ast.literal_eval(fh.readline())
860 rmf_file = os.path.join(os.path.dirname(stat_fname),
861 "%d.rmf3" % model_num)
862 for c
in state.all_modeled_components:
864 state._pmi_object.set_coordinates_from_rmf(c, rmf_file, 0,
865 force_rigid_update=
True)
869 if model_num >= self.num_models_deposited:
873 def _get_precision(self):
874 precfile = os.path.join(self.post_process.rex._outputdir,
875 "precision.%d.%d.out" % (self.cluster_num,
877 if not os.path.exists(precfile):
880 r = re.compile(
'All .*/cluster.%d/ average centroid distance ([\d\.]+)'
882 with open(precfile)
as fh:
886 return float(m.group(1))
888 precision = property(
lambda self: self._get_precision(),
889 lambda self, val:
None)
891 class _SimpleEnsemble(ihm.model.Ensemble):
892 """Simple manually-created ensemble"""
894 num_models_deposited =
None
896 def __init__(self, pp, model_group, num_models, drmsd,
897 num_models_deposited, ensemble_file):
898 super(_SimpleEnsemble, self).__init__(
899 model_group=model_group, post_process=pp, num_models=num_models,
900 file=ensemble_file, precision=drmsd, name=model_group.name,
901 clustering_feature=
'dRMSD')
902 self.num_models_deposited = num_models_deposited
904 def load_localization_density(self, state, component, asym, local_file):
905 den = ihm.model.LocalizationDensity(file=local_file, asym_unit=asym)
906 self.densities.append(den)
909 class _EntityMapper(dict):
910 """Handle mapping from IMP components to CIF entities.
911 Multiple components may map to the same entity if they share sequence."""
912 def __init__(self, system):
913 super(_EntityMapper, self).__init__()
914 self._sequence_dict = {}
918 def add(self, component_name, sequence, offset):
919 def entity_seq(sequence):
922 return [
'UNK' if s ==
'X' else s
for s
in sequence]
925 if sequence
not in self._sequence_dict:
928 d = component_name.split(
"@")[0].split(
".")[0]
929 entity = Entity(entity_seq(sequence), description=d,
931 self.system.entities.append(entity)
932 self._sequence_dict[sequence] = entity
933 self[component_name] = self._sequence_dict[sequence]
936 class _TransformedComponent(object):
937 def __init__(self, name, original, transform):
938 self.name, self.original, self.transform = name, original, transform
941 class _SimpleRef(object):
942 """Class with similar interface to weakref.ref, but keeps a strong ref"""
943 def __init__(self, ref):
949 class _State(ihm.model.State):
950 """Representation of a single state in the system."""
952 def __init__(self, pmi_object, po):
957 self._pmi_object = weakref.proxy(pmi_object)
958 if hasattr(pmi_object,
'state'):
961 self._pmi_state = _SimpleRef(pmi_object.state)
963 self._pmi_state = weakref.ref(pmi_object)
966 super(_State, self).__init__(experiment_type=
'Fraction of bulk')
971 self.modeled_assembly = ihm.Assembly(
972 name=
"Modeled assembly",
973 description=self.get_postfixed_name(
974 "All components modeled by IMP"))
975 po.system.orphan_assemblies.append(self.modeled_assembly)
977 self.all_modeled_components = []
980 return hash(self._pmi_state())
981 def __eq__(self, other):
982 return self._pmi_state() == other._pmi_state()
984 def add_model_group(self, group):
988 def get_prefixed_name(self, name):
989 """Prefix the given name with the state name, if available."""
991 return self.short_name +
' ' + name
995 return name[0].upper() + name[1:]
if name
else ''
997 def get_postfixed_name(self, name):
998 """Postfix the given name with the state name, if available."""
1000 return "%s in state %s" % (name, self.short_name)
1004 short_name = property(
lambda self: self._pmi_state().short_name)
1005 long_name = property(
lambda self: self._pmi_state().long_name)
1006 def __get_name(self):
1007 return self._pmi_state().long_name
1008 def __set_name(self, val):
1009 self._pmi_state().long_name = val
1010 name = property(__get_name, __set_name)
1014 """A single entity in the system.
1015 This functions identically to the base ihm.Entity class, but it
1016 allows identifying residues by either the IHM numbering scheme
1017 (seq_id, which is always contiguous starting at 1) or by the PMI
1018 scheme (which is similar, but may not start at 1 if the sequence in
1019 the FASTA file has one or more N-terminal gaps"""
1020 def __init__(self, sequence, pmi_offset, *args, **keys):
1023 self.pmi_offset = pmi_offset
1024 super(Entity, self).__init__(sequence, *args, **keys)
1027 """Return a single IHM residue indexed using PMI numbering"""
1028 return self.residue(res_id - self.pmi_offset)
1031 """Return a range of IHM residues indexed using PMI numbering"""
1032 off = self.pmi_offset
1033 return self(res_id_begin - off, res_id_end - off)
1037 """A single asymmetric unit in the system.
1038 This functions identically to the base ihm.AsymUnit class, but it
1039 allows identifying residues by either the IHM numbering scheme
1040 (seq_id, which is always contiguous starting at 1) or by the PMI
1041 scheme (which is similar, but may not start at 1 if the sequence in
1042 the FASTA file has one or more N-terminal gaps"""
1044 def __init__(self, entity, *args, **keys):
1045 super(AsymUnit, self).__init__(
1046 entity, auth_seq_id_map=entity.pmi_offset, *args, **keys)
1049 """Return a single IHM residue indexed using PMI numbering"""
1050 return self.residue(res_id - self.entity.pmi_offset)
1053 """Return a range of IHM residues indexed using PMI numbering"""
1054 off = self.entity.pmi_offset
1055 return self(res_id_begin - off, res_id_end - off)
1059 """Class to encode a modeling protocol as mmCIF.
1061 IMP has basic support for writing out files in mmCIF format, for
1062 deposition in [PDB-Dev](https://pdb-dev.wwpdb.org/).
1063 After creating an instance of this class, attach it to an
1064 IMP.pmi1.representation.Representation object. After this, any
1065 generated models and metadata are automatically collected and
1068 def __init__(self, fh):
1070 self.system = ihm.System()
1071 self._state_group = ihm.model.StateGroup()
1072 self.system.state_groups.append(self._state_group)
1075 self._state_ensemble_offset = 0
1076 self._each_metadata = []
1077 self._file_datasets = []
1078 self._main_script = os.path.abspath(sys.argv[0])
1081 loc = ihm.location.WorkflowFileLocation(path=self._main_script,
1082 details=
"The main integrative modeling script")
1083 self.system.locations.append(loc)
1086 self.__asym_states = {}
1087 self._working_directory = os.getcwd()
1089 "Default representation")
1090 self.entities = _EntityMapper(self.system)
1092 self.asym_units = {}
1093 self._all_components = {}
1094 self.all_modeled_components = []
1095 self._transformed_components = []
1096 self.sequence_dict = {}
1099 self._xy_plane = ihm.geometry.XYPlane()
1100 self._xz_plane = ihm.geometry.XZPlane()
1101 self._z_axis = ihm.geometry.ZAxis()
1102 self._center_origin = ihm.geometry.Center(0,0,0)
1103 self._identity_transform = ihm.geometry.Transformation.identity()
1106 self._exclude_coords = {}
1108 self.all_representations = _AllModelRepresentations(self)
1109 self.all_protocols = _AllProtocols(self)
1110 self.all_datasets = _AllDatasets(self.system)
1111 self.all_starting_models = _AllStartingModels(self)
1113 self.all_software = _AllSoftware(self.system)
1116 """Create a new Representation and return it. This can be
1117 passed to add_model(), add_bead_element() or add_pdb_element()."""
1118 r = ihm.representation.Representation()
1119 self.system.orphan_representations.append(r)
1123 """Don't record coordinates for the given domain.
1124 Coordinates for the given domain (specified by a component name
1125 and a 2-element tuple giving the start and end residue numbers)
1126 will be excluded from the mmCIF file. This can be used to exclude
1127 parts of the structure that weren't well resolved in modeling.
1128 Any bead or residue that lies wholly within this range will be
1129 excluded. Multiple ranges for a given component can be excluded
1130 by calling this method multiple times."""
1131 if component
not in self._exclude_coords:
1132 self._exclude_coords[component] = []
1133 self._exclude_coords[component].append(seqrange)
1135 def _is_excluded(self, component, start, end):
1136 """Return True iff this chunk of sequence should be excluded"""
1137 for seqrange
in self._exclude_coords.get(component, ()):
1138 if start >= seqrange[0]
and end <= seqrange[1]:
1141 def _add_state(self, state):
1142 """Create a new state and return a pointer to it."""
1143 self._state_ensemble_offset = len(self.system.ensembles)
1144 s = _State(state, self)
1145 self._state_group.append(s)
1146 self._last_state = s
1149 def get_file_dataset(self, fname):
1150 for d
in self._file_datasets:
1151 fd = d.get(os.path.abspath(fname),
None)
1155 def _get_chain_for_component(self, name, output):
1156 """Get the chain ID for a component, if any."""
1158 if name
in self.asym_units:
1159 return self.asym_units[name]._id
1164 def _get_assembly_comps(self, assembly):
1165 """Get the names of the components in the given assembly"""
1169 comps[ca.details] =
None
1173 """Make a new component that's a transformed copy of another.
1174 All representation for the existing component is copied to the
1176 assembly_comps = self._get_assembly_comps(state.modeled_assembly)
1177 if name
in assembly_comps:
1178 raise ValueError(
"Component %s already exists" % name)
1179 elif original
not in assembly_comps:
1180 raise ValueError(
"Original component %s does not exist" % original)
1181 self.create_component(state, name,
True)
1182 self.add_component_sequence(state, name, self.sequence_dict[original])
1183 self._transformed_components.append(_TransformedComponent(
1184 name, original, transform))
1185 self.all_representations.copy_component(state, name, original,
1186 self.asym_units[name])
1188 def create_component(self, state, name, modeled):
1189 new_comp = name
not in self._all_components
1190 self._all_components[name] =
None
1192 state.all_modeled_components.append(name)
1194 self.asym_units[name] =
None
1195 self.all_modeled_components.append(name)
1197 def add_component_sequence(self, state, name, seq):
1198 def get_offset(seq):
1200 for i
in range(len(seq)):
1203 seq, offset = get_offset(seq)
1204 if name
in self.sequence_dict:
1205 if self.sequence_dict[name] != seq:
1206 raise ValueError(
"Sequence mismatch for component %s" % name)
1208 self.sequence_dict[name] = seq
1209 self.entities.add(name, seq, offset)
1210 if name
in self.asym_units:
1211 if self.asym_units[name]
is None:
1213 entity = self.entities[name]
1214 asym =
AsymUnit(entity, details=name)
1215 self.system.asym_units.append(asym)
1216 self.asym_units[name] = asym
1217 state.modeled_assembly.append(self.asym_units[name])
1219 def _add_restraint_model_fits(self):
1220 """Add fits to restraints for all known models"""
1221 for group, m
in self.system._all_models():
1222 if m._is_restrained:
1223 for r
in self.system.restraints:
1224 if hasattr(r,
'add_fits_from_model_statfile'):
1225 r.add_fits_from_model_statfile(m)
1227 def _add_em2d_raw_micrographs(self):
1228 """If the deprecated metadata.EMMicrographsDataset class was used,
1229 transfer its data to the EM2D restraint."""
1230 for r
in self.system.restraints:
1231 if isinstance(r, _EM2DRestraint):
1232 for d
in r.dataset.parents:
1233 if isinstance(d, IMP.pmi1.metadata.EMMicrographsDataset):
1234 r.number_raw_micrographs = d.number
1235 if isinstance(d.location,
1236 IMP.pmi1.metadata.FileLocation):
1237 d.location.content_type = \
1238 ihm.location.InputFileLocation.content_type
1242 ihm.dumper.write(self.fh, [self.system])
1245 """Do any final processing on the class hierarchy.
1246 After calling this method, the `system` member (an instance
1247 of `ihm.System`) completely reproduces the PMI modeling, and
1248 can be written out to an mmCIF file with `ihm.dumper.write`,
1249 and/or modified using the ihm API."""
1250 self._add_restraint_model_fits()
1252 self._add_em2d_raw_micrographs()
1255 self.system.software.extend(m
for m
in self._metadata
1256 if isinstance(m, ihm.Software))
1257 self.system.citations.extend(m
for m
in self._metadata
1258 if isinstance(m, ihm.Citation))
1259 self.system.locations.extend(m
for m
in self._metadata
1260 if isinstance(m, ihm.location.FileLocation))
1263 all_repos = [m
for m
in self._metadata
1264 if isinstance(m, ihm.location.Repository)]
1265 self.system.update_locations_in_repositories(all_repos)
1267 def add_pdb_element(self, state, name, start, end, offset, pdbname,
1268 chain, hier, representation=
None):
1269 if self._is_excluded(name, start, end):
1271 if representation
is None:
1272 representation = self.default_representation
1273 asym = self.asym_units[name]
1274 p = _PDBFragment(state, name, start, end, offset, pdbname, chain,
1276 self.all_representations.add_fragment(state, representation, p)
1277 self.all_starting_models.add_pdb_fragment(p)
1279 def add_bead_element(self, state, name, start, end, num, hier,
1280 representation=
None):
1281 if self._is_excluded(name, start, end):
1283 if representation
is None:
1284 representation = self.default_representation
1285 asym = self.asym_units[name]
1286 pmi_offset = asym.entity.pmi_offset
1287 b = _BeadsFragment(state, name, start - pmi_offset, end - pmi_offset,
1289 self.all_representations.add_fragment(state, representation, b)
1291 def get_cross_link_group(self, pmi_restraint):
1292 r = _CrossLinkRestraint(pmi_restraint)
1293 self.system.restraints.append(r)
1294 self._add_restraint_dataset(r)
1297 def add_experimental_cross_link(self, r1, c1, r2, c2, rsr):
1298 if c1
not in self._all_components
or c2
not in self._all_components:
1304 e1 = self.entities[c1]
1305 e2 = self.entities[c2]
1306 xl = ihm.restraint.ExperimentalCrossLink(residue1=e1.pmi_residue(r1),
1307 residue2=e2.pmi_residue(r2))
1308 rsr.experimental_cross_links.append([xl])
1311 def add_cross_link(self, state, ex_xl, p1, p2, length, sigma1_p, sigma2_p,
1314 asym = get_asym_mapper_for_state(self, state, self.__asym_states)
1315 d = ihm.restraint.UpperBoundDistanceRestraint(length)
1317 if _get_by_residue(p1)
and _get_by_residue(p2):
1318 cls = _ResidueCrossLink
1320 cls = _FeatureCrossLink
1321 xl = cls(ex_xl, asym1=asym[p1], asym2=asym[p2], distance=d,
1324 xl.psi_p, xl.sigma1_p, xl.sigma2_p = psi_p, sigma1_p, sigma2_p
1325 rsr.cross_links.append(xl)
1327 def add_replica_exchange(self, state, rex):
1332 self.all_protocols.add_step(_ReplicaExchangeProtocolStep(state, rex),
1335 def _add_simple_dynamics(self, num_models_end, method):
1337 state = self._last_state
1338 self.all_protocols.add_step(_SimpleProtocolStep(state, num_models_end,
1341 def _add_protocol(self):
1343 state = self._last_state
1344 self.all_protocols.add_protocol(state)
1346 def _add_dataset(self, dataset):
1347 return self.all_datasets.add(self._last_state, dataset)
1349 def _add_restraint_dataset(self, restraint):
1350 return self.all_datasets.add_restraint(self._last_state, restraint)
1352 def _add_simple_postprocessing(self, num_models_begin, num_models_end):
1354 state = self._last_state
1355 pp = ihm.analysis.ClusterStep(
'RMSD', num_models_begin, num_models_end)
1356 self.all_protocols.add_postproc(pp, state)
1359 def _add_no_postprocessing(self, num_models):
1361 state = self._last_state
1362 pp = ihm.analysis.EmptyStep()
1363 pp.num_models_begin = pp.num_models_end = num_models
1364 self.all_protocols.add_postproc(pp, state)
1367 def _add_simple_ensemble(self, pp, name, num_models, drmsd,
1368 num_models_deposited, localization_densities,
1370 """Add an ensemble generated by ad hoc methods (not using PMI).
1371 This is currently only used by the Nup84 system."""
1373 state = self._last_state
1374 group = ihm.model.ModelGroup(name=state.get_postfixed_name(name))
1375 state.add_model_group(group)
1378 if isinstance(ensemble_file, IMP.pmi1.metadata.FileLocation):
1379 ensemble_file.content_type = \
1380 ihm.location.OutputFileLocation.content_type
1381 self.system.locations.append(ensemble_file)
1382 e = _SimpleEnsemble(pp, group, num_models, drmsd, num_models_deposited,
1384 self.system.ensembles.append(e)
1385 for c
in state.all_modeled_components:
1386 den = localization_densities.get(c,
None)
1389 if isinstance(den, IMP.pmi1.metadata.FileLocation):
1390 den.content_type = \
1391 ihm.location.OutputFileLocation.content_type
1392 e.load_localization_density(state, c, self.asym_units[c], den)
1396 """Point a previously-created ensemble to an 'all-models' file.
1397 This could be a trajectory such as DCD, an RMF, or a multimodel
1400 if isinstance(location, IMP.pmi1.metadata.FileLocation):
1401 location.content_type = ihm.location.OutputFileLocation.content_type
1402 self.system.locations.append(location)
1404 ind = i + self._state_ensemble_offset
1405 self.system.ensembles[ind].file = location
1407 def add_replica_exchange_analysis(self, state, rex, density_custom_ranges):
1413 protocol = self.all_protocols.get_last_protocol(state)
1414 num_models = protocol.steps[-1].num_models_end
1415 pp = _ReplicaExchangeAnalysisPostProcess(rex, num_models)
1416 self.all_protocols.add_postproc(pp, state)
1417 for i
in range(rex._number_of_clusters):
1418 group = ihm.model.ModelGroup(name=state.get_prefixed_name(
1419 'cluster %d' % (i + 1)))
1420 state.add_model_group(group)
1422 e = _ReplicaExchangeAnalysisEnsemble(pp, i, group, 1)
1423 self.system.ensembles.append(e)
1425 for fname, stuple
in sorted(density_custom_ranges.items()):
1426 e.load_localization_density(state, fname, stuple,
1428 for stats
in e.load_all_models(self, state):
1429 m = self.add_model(group)
1432 m.name =
'Best scoring model'
1435 for c
in state.all_modeled_components:
1438 def _get_subassembly(self, comps, name, description):
1439 """Get an Assembly consisting of the given components.
1440 `compdict` is a dictionary of the components to add, where keys
1441 are the component names and values are the sequence ranges (or
1442 None to use all residues in the component)."""
1444 for comp, seqrng
in comps.items():
1445 a = self.asym_units[comp]
1446 asyms.append(a
if seqrng
is None else a(*seqrng))
1448 a = ihm.Assembly(asyms, name=name, description=description)
1451 def _add_foxs_restraint(self, model, comp, seqrange, dataset, rg, chi,
1453 """Add a basic FoXS fit. This is largely intended for use from the
1455 assembly = self._get_subassembly({comp:seqrange},
1456 name=
"SAXS subassembly",
1457 description=
"All components that fit SAXS data")
1458 r = ihm.restraint.SASRestraint(dataset, assembly, segment=
False,
1459 fitting_method=
'FoXS', fitting_atom_type=
'Heavy atoms',
1460 multi_state=
False, radius_of_gyration=rg, details=details)
1461 r.fits[model] = ihm.restraint.SASRestraintFit(chi_value=chi)
1462 self.system.restraints.append(r)
1463 self._add_restraint_dataset(r)
1465 def add_em2d_restraint(self, state, r, i, resolution, pixel_size,
1466 image_resolution, projection_number,
1467 micrographs_number):
1468 r = _EM2DRestraint(state, r, i, resolution, pixel_size,
1469 image_resolution, projection_number,
1471 self.system.restraints.append(r)
1472 self._add_restraint_dataset(r)
1474 def add_em3d_restraint(self, state, target_ps, densities, pmi_restraint):
1476 r = _EM3DRestraint(self, state, pmi_restraint, target_ps, densities)
1477 self.system.restraints.append(r)
1478 self._add_restraint_dataset(r)
1480 def add_zaxial_restraint(self, state, ps, lower_bound, upper_bound,
1481 sigma, pmi_restraint):
1482 self._add_geometric_restraint(state, ps, lower_bound, upper_bound,
1483 sigma, pmi_restraint, self._xy_plane)
1485 def add_yaxial_restraint(self, state, ps, lower_bound, upper_bound,
1486 sigma, pmi_restraint):
1487 self._add_geometric_restraint(state, ps, lower_bound, upper_bound,
1488 sigma, pmi_restraint, self._xz_plane)
1490 def add_xyradial_restraint(self, state, ps, lower_bound, upper_bound,
1491 sigma, pmi_restraint):
1492 self._add_geometric_restraint(state, ps, lower_bound, upper_bound,
1493 sigma, pmi_restraint, self._z_axis)
1495 def _add_geometric_restraint(self, state, ps, lower_bound, upper_bound,
1496 sigma, pmi_restraint, geom):
1497 asym = get_asym_mapper_for_state(self, state, self.__asym_states)
1498 r = _GeometricRestraint(self, state, pmi_restraint, geom,
1499 asym.get_feature(ps),
1500 ihm.restraint.LowerUpperBoundDistanceRestraint(
1501 lower_bound, upper_bound),
1503 self.system.restraints.append(r)
1504 self._add_restraint_dataset(r)
1506 def _get_membrane(self, tor_R, tor_r, tor_th):
1507 """Get an object representing a half-torus membrane"""
1508 if not hasattr(self,
'_seen_membranes'):
1509 self._seen_membranes = {}
1512 membrane_id = tuple(int(x * 100.)
for x
in (tor_R, tor_r, tor_th))
1513 if membrane_id
not in self._seen_membranes:
1514 m = ihm.geometry.HalfTorus(center=self._center_origin,
1515 transformation=self._identity_transform,
1516 major_radius=tor_R, minor_radius=tor_r, thickness=tor_th,
1517 inner=
True, name=
'Membrane')
1518 self._seen_membranes[membrane_id] = m
1519 return self._seen_membranes[membrane_id]
1521 def add_membrane_surface_location_restraint(
1522 self, state, ps, tor_R, tor_r, tor_th, sigma, pmi_restraint):
1523 self._add_membrane_restraint(state, ps, tor_R, tor_r, tor_th, sigma,
1524 pmi_restraint, ihm.restraint.UpperBoundDistanceRestraint(0.))
1526 def add_membrane_exclusion_restraint(
1527 self, state, ps, tor_R, tor_r, tor_th, sigma, pmi_restraint):
1528 self._add_membrane_restraint(state, ps, tor_R, tor_r, tor_th, sigma,
1529 pmi_restraint, ihm.restraint.LowerBoundDistanceRestraint(0.))
1531 def _add_membrane_restraint(self, state, ps, tor_R, tor_r, tor_th,
1532 sigma, pmi_restraint, rsr):
1533 asym = get_asym_mapper_for_state(self, state, self.__asym_states)
1534 r = _GeometricRestraint(self, state, pmi_restraint,
1535 self._get_membrane(tor_R, tor_r, tor_th),
1536 asym.get_feature(ps), rsr, sigma)
1537 self.system.restraints.append(r)
1538 self._add_restraint_dataset(r)
1540 def add_model(self, group, assembly=None, representation=None):
1541 state = self._last_state
1542 if representation
is None:
1543 representation = self.default_representation
1544 protocol = self.all_protocols.get_last_protocol(state)
1545 m = _Model(state.prot, self, protocol,
1546 assembly
if assembly
else state.modeled_assembly,
1551 def _update_locations(self, filelocs):
1552 """Update FileLocation to point to a parent repository, if any"""
1553 all_repos = [m
for m
in self._metadata
1554 if isinstance(m, ihm.location.Repository)]
1555 for fileloc
in filelocs:
1556 ihm.location.Repository._update_in_repos(fileloc, all_repos)
1558 _metadata = property(
lambda self:
1559 itertools.chain.from_iterable(self._each_metadata))
Select non water and non hydrogen atoms.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
A decorator to associate a particle with a part of a protein/DNA/RNA.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
def create_representation
Create a new Representation and return it.
def finalize
Do any final processing on the class hierarchy.
Class for easy writing of PDBs, RMFs, and stat files.
Class to encode a modeling protocol as mmCIF.
A single asymmetric unit in the system.
def exclude_coordinates
Don't record coordinates for the given domain.
Base class for capturing a modeling protocol.
def pmi_residue
Return a single IHM residue indexed using PMI numbering.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
void read_pdb(TextInput input, int model, Hierarchy h)
Classes to represent data structures used in mmCIF.
void add_restraint(RMF::FileHandle fh, Restraint *hs)
static bool get_is_setup(Model *m, ParticleIndex pi)
Ints get_index(const ParticlesTemp &particles, const Subset &subset, const Subsets &excluded)
def set_ensemble_file
Point a previously-created ensemble to an 'all-models' file.
def pmi_range
Return a range of IHM residues indexed using PMI numbering.
Basic utilities for handling cryo-electron microscopy 3D density maps.
def pmi_residue
Return a single IHM residue indexed using PMI numbering.
def create_transformed_component
Make a new component that's a transformed copy of another.
Transformation3D get_identity_transformation_3d()
Return a transformation that does not do anything.
Representation of the system.
A decorator for a residue.
Basic functionality that is expected to be used by a wide variety of IMP users.
General purpose algebraic and geometric methods that are expected to be used by a wide variety of IMP...
A single entity in the system.
def pmi_range
Return a range of IHM residues indexed using PMI numbering.
Classes for writing output files and processing them.
Functionality for loading, creating, manipulating and scoring atomic structures.
Hierarchies get_leaves(const Selection &h)
Select hierarchy particles identified by the biological name.
Select all ATOM and HETATM records with the given chain ids.
Inferential scoring building on methods developed as part of the Inferential Structure Determination ...