def cg(self, force=False, com=False): # Generate the coarse grained structure # Set the b-factor field to something that reflects the secondary structure # If the coarse grained structure is set already, just return, # unless regeneration is forced. if self._cg and not force: return self._cg self._cg = [] atid = 1 bb = [1] fail = False previous = '' for residue, rss, resname in zip(self.residues, self.sstypes, self.sequence): # For DNA we need to get the O3' to the following residue when calculating COM # The force and com options ensure that this part does not affect itp generation or anything else if com: # Just an initialization, this should complain if it isn't updated in the loop store = 0 for ind, i in enumerate(residue): if i[0] == "O3'": if previous != '': residue[ind] = previous previous = i else: store = ind previous = i # We couldn't remove the O3' from the 5' end residue during the loop so we do it now if store > 0: del residue[store] # Check if residues names has changed, for example because user has set residues interactively. residue = [(atom[0], resname)+atom[2:] for atom in residue] if residue[0][1] in ("SOL", "HOH", "TIP"): continue if not residue[0][1] in MAP.CoarseGrained.mapping.keys(): logging.warning("Skipped unknown residue %s\n" % residue[0][1]) continue # Get the mapping for this residue # CG.map returns bead coordinates and mapped atoms # This will fail if there are (too many) atoms missing, which is # only problematic if a mapped structure is written; the topology # is inferred from the sequence. So this is the best place to raise # an error try: beads, ids = MAP.map(residue, ca2bb=self.options['ForceField'].ca2bb) beads = zip(MAP.CoarseGrained.names[residue[0][1]], beads, ids) if residue[0][1] in self.options['ForceField'].polar: beads = add_dummy(beads, dist=0.14, n=2) elif residue[0][1] in self.options['ForceField'].charged: beads = add_dummy(beads, dist=0.11, n=1) except ValueError: logging.error("Too many atoms missing from residue %s %d(ch:%s):", residue[0][1], residue[0][2]-(32 << 20), residue[0][3]) logging.error(repr([i[0] for i in residue])) fail = True for name, (x, y, z), ids in beads: # Add the bead with coordinates and secondary structure id to the list self._cg.append((name, residue[0][1][:3], residue[0][2], residue[0][3], x, y, z, SS.ss2num[rss])) # Add the ids to the list, after converting them to indices to the list of atoms self.mapping.append([atid+i for i in ids]) # Increment the atom id; This pertains to the atoms that are included in the output. atid += len(residue) # Keep track of the numbers for CONECTing bb.append(bb[-1]+len(beads)) if fail: logging.error("Unable to generate coarse grained structure due to missing atoms.") sys.exit(1) return self._cg