def from_snapshot(snapshot, scale=1.0): """Convert a Snapshot to a Compound. Snapshot can be a hoomd.data.Snapshot or a gsd.hoomd.Snapshot. Parameters ---------- snapshot : hoomd._hoomd.SnapshotSystemData_float or gsd.hoomd.Snapshot Snapshot from which to build the mbuild Compound. scale : float, optional, default 1.0 Value by which to scale the length values Returns ------- comp : Compound Note ---- GSD and HOOMD snapshots center their boxes on the origin (0,0,0), so the compound is shifted by half the box lengths """ comp = Compound() bond_array = snapshot.bonds.group n_atoms = snapshot.particles.N if "SnapshotSystemData_float" in dir(hoomd._hoomd) and isinstance( snapshot, hoomd._hoomd.SnapshotSystemData_float ): # hoomd v2 box = snapshot.box comp.box = Box.from_lengths_tilt_factors( lengths=np.array([box.Lx, box.Ly, box.Lz]) * scale, tilt_factors=np.array([box.xy, box.xz, box.yz]), ) else: # gsd / hoomd v3 box = snapshot.configuration.box comp.box = Box.from_lengths_tilt_factors( lengths=box[:3] * scale, tilt_factors=box[3:] ) # GSD and HOOMD snapshots center their boxes on the origin (0,0,0) shift = np.array(comp.box.lengths) / 2 # Add particles for i in range(n_atoms): name = snapshot.particles.types[snapshot.particles.typeid[i]] xyz = snapshot.particles.position[i] * scale + shift charge = snapshot.particles.charge[i] atom = Particle(name=name, pos=xyz, charge=charge) comp.add(atom, label=str(i)) # Add bonds particle_dict = {idx: p for idx, p in enumerate(comp.particles())} for i in range(bond_array.shape[0]): atom1 = int(bond_array[i][0]) atom2 = int(bond_array[i][1]) comp.add_bond([particle_dict[atom1], particle_dict[atom2]]) return comp
def reverse_map_molecule(molecule, target, mapping_moieties): print('unique') cg_molecule = clone(molecule) # CG molecule aa_template = target[molecule.name] # full aa Compound for molecule aa_moieties = mapping_moieties[ molecule.name] # list of lists of indices for each bead aa_molecule = Compound() # this will have the final aa molecule cg_to_aa = [] # list of tuples containing (real index, aa atom) # now cycle through beads for index, bead in enumerate(cg_molecule.particles()): aa_atoms = Compound() # placeholder for molecule atoms [ aa_atoms.add(clone(aa_template.children[i])) for i in aa_moieties[index] ] aa_atoms.translate_to(bead.pos) # shift to cg_bead position cg_to_aa += list(zip(aa_moieties[index], aa_atoms.children)) # sort atoms in cg_to_aa and add them to the aa_molecule cg_to_aa = sorted(cg_to_aa) for atom in cg_to_aa: aa_molecule.add(clone(atom[1])) # add bonds from the template aa_template = aa_template.to_trajectory() for i, j in aa_template.top.bonds: aa_molecule.add_bond([aa_molecule[i.index], aa_molecule[j.index]]) # equilibrate molecule and shift back to center # if the atom names match OpenBabel forcefield naming convention: try: aa_molecule.energy_minimization(steps=2500) # otherwise rename with just element names: except: atomnames = [i.name for i in aa_molecule] # get the atomnames for atom in aa_molecule: # make the atomnames elements atom.name = atom.name[0] aa_molecule.energy_minimization(steps=2500) for i, atom in enumerate(atomnames): aa_molecule[i].name = atomnames[i] #aa_molecule.translate(center) aa_molecule.name = molecule.name return aa_molecule