1 """@namespace IMP.mmcif.util
2 @brief Utility functions for IMP.mmcif.
13 import ihm.representation
18 class _ChainIDs(object):
19 """Map indices to multi-character chain IDs.
20 We label the first 26 chains A-Z, then we move to two-letter
21 chain IDs: AA through AZ, then BA through BZ, through to ZZ.
22 This continues with longer chain IDs."""
23 def __getitem__(self, ind):
24 chars = string.ascii_uppercase
28 ids.append(chars[ind % lc])
30 ids.append(chars[ind])
31 return "".join(reversed(ids))
35 """An individual state conformation read from a PDB file"""
36 def __init__(self, filename, frame, name):
37 self.filename, self.frame = filename, frame
40 def create(self, model):
41 rmf = RMF.open_rmf_file_read_only(self.filename)
45 return hiers, restraints
47 def link(self, hiers, restraints):
48 rmf = RMF.open_rmf_file_read_only(self.filename)
54 class _ModelFrame(object):
55 """An individual state conformation read from an IMP.Model"""
56 def __init__(self, hiers, restraints, name):
57 self.hiers, self.restraints = hiers, restraints
60 def create(self, model):
61 return self.hiers, self.restraints
63 def link(self, hiers, restraints):
64 if len(hiers) != len(self.hiers) \
65 or len(restraints) != len(self.restraints):
66 raise ValueError(
"Frames do not match")
70 restraints[:] = self.restraints
73 class _NonModeledChain(object):
74 """Represent a chain that was experimentally characterized but not modeled.
75 Such a chain resembles an IMP.atom.Chain, but has no associated
76 structure, and belongs to no state."""
77 def __init__(self, name, sequence, chain_type):
79 self.sequence = sequence
80 self.chain_type = chain_type
82 get_sequence =
lambda self: self.sequence
87 self.system = ihm.System()
92 self.entities = IMP.mmcif.data._EntityMapper(self.system)
93 self.components = IMP.mmcif.data._ComponentMapper(self.system)
94 self._software = IMP.mmcif.data._AllSoftware(self.system)
95 self._external_files = IMP.mmcif.data._ExternalFiles(self.system)
96 self.datasets = IMP.mmcif.data._Datasets(self.system)
98 self.protocols = IMP.mmcif.data._Protocols(self.system)
99 self.representation = ihm.representation.Representation()
100 self.system.orphan_representations.append(self.representation)
102 def _update_location(self, fileloc):
103 """Update FileLocation to point to a parent repository, if any"""
104 ihm.location.Repository._update_in_repos(fileloc,
105 self._external_files._repos)
107 def add_repository(self, doi, root=None, url=None, top_directory=None):
108 """Add a repository containing one or more modeling files."""
109 self._external_files.add_repo(ihm.location.Repository(
110 doi, root, url, top_directory))
112 def _add_state(self, state):
113 if not self.system.state_groups:
114 self.system.state_groups.append(ihm.model.StateGroup())
115 self.system.state_groups[-1].append(state)
116 self._states.append(state)
118 def _add_ensemble(self, ensemble):
119 self._ensembles.append(ensemble)
120 self.system.ensembles.append(ensemble)
122 def _add_frame(self, frame):
123 self._frames.append(frame)
124 frame.id = len(self._frames)
126 def _add_hierarchy(self, h, state):
128 for c
in IMP.atom.get_by_type(h, IMP.atom.CHAIN_TYPE)]
130 raise ValueError(
"No chains found in %s" % h)
133 component = self._add_chain(c)
134 state._all_modeled_components.append(component)
135 if hasattr(component,
'asym_unit'):
136 state.modeled_assembly.append(component.asym_unit)
138 state.modeled_assembly.append(component.entity)
139 state.repsegments[component] \
140 = list(self._get_repsegments(c, component,
141 self._get_all_starting_models(component)))
143 num_state_reps = len([s
for s
in self._states
144 if component
in s.repsegments])
147 if num_state_reps == 1:
148 self.representation.extend(state.repsegments[component])
149 self.protocols._add_hierarchy(h, state.modeled_assembly)
150 self._external_files.add_hierarchy(h)
151 self._software.add_hierarchy(h)
153 def _get_all_starting_models(self, comp):
154 """Get all starting models (in all states) for the given component"""
155 for state
in self._states:
156 for seg
in state.repsegments.get(comp, []):
157 if seg.starting_model:
158 yield seg.starting_model
160 def _get_repsegments(self, chain, component, existing_starting_models):
161 """Yield groups of particles under chain with same representation"""
162 smf = IMP.mmcif.data._StartingModelFinder(component,
163 existing_starting_models)
164 segfactory = IMP.mmcif.data._RepSegmentFactory(component)
166 for sp
in self._get_structure_particles(chain):
167 starting_model = smf.find(sp, self)
168 seg = segfactory.add(sp, starting_model)
171 last = segfactory.get_last()
175 def _get_structure_particles(self, chain):
176 """Yield all particles under chain with coordinates.
177 They are sorted by residue index."""
184 resind = residue.get_index()
185 if resind
in resind_dict:
187 resind_dict[resind] = residue
191 resinds = fragment.get_residue_indexes()
192 resind = resinds[len(resinds) // 2]
193 if resind
in resind_dict:
195 resind_dict[resind] = fragment
197 for item
in sorted(resind_dict.items(), key=operator.itemgetter(0)):
200 def add_non_modeled_chain(self, name, sequence,
201 chain_type=IMP.atom.UnknownChainType):
202 """Add a chain that wasn't modeled by IMP."""
203 c = _NonModeledChain(name, sequence, chain_type)
206 def _add_chain(self, c):
207 entity = self.entities.add(c)
208 component = self.components.add(c, entity)
211 def write(self, fname):
212 with open(fname,
'w')
as fh:
213 ihm.dumper.write(fh, [self.system])
217 """Represent a single IMP state."""
218 def __init__(self, system):
219 super(State, self).__init__()
220 self.system = weakref.proxy(system)
221 system._add_state(self)
224 self._wrapped_restraints = []
227 self.modeled_assembly = ihm.Assembly(name=
"Modeled assembly",
228 description=
"All components modeled by IMP")
229 system.system.orphan_assemblies.append(self.modeled_assembly)
231 self.repsegments = {}
234 self._all_modeled_components = []
236 def _add_frame(self, f, model):
237 self._frames.append(f)
238 self.system._add_frame(f)
239 if self._load_frame(f):
241 self._add_hierarchy(h)
242 self._add_restraints(self.restraints, model)
244 self._update_restraints(model)
246 def _load_frame(self, f):
247 """Load hierarchies and restraints from a frame.
248 Return True if this results in making new hierarchies."""
249 if self.hiers
is None:
250 self.hiers, self.restraints = f.create(self.model)
251 self._remove_duplicate_chain_ids(
True)
254 f.link(self.hiers, self.restraints)
255 self._remove_duplicate_chain_ids(
False)
258 def _remove_duplicate_chain_ids(self, new_hiers):
262 for c
in IMP.atom.get_by_type(h, IMP.atom.CHAIN_TYPE))
264 self._assigned_chain_ids = []
265 chain_ids = [c.get_id()
for c
in chains]
266 if len(set(chain_ids)) < len(chain_ids):
267 print(
"Duplicate chain IDs detected - reassigning "
269 for chain, cid
in zip(chains, _ChainIDs()):
270 self._assigned_chain_ids.append(cid)
273 for chain, cid
in zip(chains, self._assigned_chain_ids):
276 def _add_hierarchy(self, h):
277 self.system._add_hierarchy(h, self)
279 def _add_restraints(self, rs, model):
280 m = IMP.mmcif.restraint._RestraintMapper(self.system)
282 rw = m.handle(r, model, self.modeled_assembly)
284 self._wrapped_restraints.append(rw)
285 self.system.system.restraints.append(rw)
287 def _update_restraints(self, model):
288 for rw
in self._wrapped_restraints:
289 rw.add_model_fit(model)
293 """Represent a set of similar models in a state."""
294 def __init__(self, state, name):
295 self.state = weakref.proxy(state)
296 state.system._add_ensemble(self)
298 mg = ihm.model.ModelGroup(name=name)
300 super(Ensemble, self).__init__(model_group=mg, num_models=0, name=name)
303 """Add a frame from a custom source"""
304 self._frames.append(frame)
306 model = IMP.mmcif.data._Model(frame, self.state)
307 self.model_group.append(model)
308 self.state._add_frame(frame, model)
311 """Add a frame from an RMF file"""
315 """Add hierarchies and restraints from an IMP.Model"""
316 self.
add_frame(_ModelFrame(hiers, restraints, name))
Represent a set of similar models in a state.
static bool get_is_setup(const IMP::ParticleAdaptor &p)
A decorator to associate a particle with a part of a protein/DNA/RNA.
atom::Hierarchies create_hierarchies(RMF::FileConstHandle fh, Model *m)
Represent a single IMP state.
def add_rmf
Add a frame from an RMF file.
void link_restraints(RMF::FileConstHandle fh, const Restraints &hs)
Classes to represent data structures used in mmCIF.
Class for storing model, its restraints, constraints, and particles.
static bool get_is_setup(Model *m, ParticleIndex pi)
An individual state conformation read from a PDB file.
def add_frame
Add a frame from a custom source.
void load_frame(RMF::FileConstHandle file, RMF::FrameID frame)
Load the given RMF frame into the state of the linked objects.
Map IMP restraints to mmCIF categories.
A decorator for a residue.
Restraints create_restraints(RMF::FileConstHandle fh, Model *m)
void link_hierarchies(RMF::FileConstHandle fh, const atom::Hierarchies &hs)
def add_model
Add hierarchies and restraints from an IMP.Model.
Store info for a chain of a protein.
Functionality for loading, creating, manipulating and scoring atomic structures.
Hierarchies get_leaves(const Selection &h)
Support for the RMF file format for storing hierarchical molecular data and markup.