def cg_by_index(trj, atom_indices_list, bead_label_list, chain_list=None, segment_id_list=None, resSeq_list=None, inplace=False, bonds=None, split_shared_atoms=False, mod_weights_list=None, mapping_function="com", charge_tol=1e-5, center_postwrap=False): """Create a coarse grained (CG) trajectory from subsets of atoms by computing centers of mass of selected sets of atoms. Parameters ---------- atom_indices_list : list of array-like, dtype=int, shape=(n_beads,n_atoms) List of indices of atoms to combine into CG sites bead_label_list : list of maximum 4-letter strings to label CG sites chain_list : optional list of chain id's to split resulting beads into separate chains resSeq_list : optional list of residue sequence id's to assign cg residues segment_id_list : optional list of segment id's to assign cg residues inplace : bool, default=False If ``True``, the operation is done inplace, modifying ``trj``. Otherwise, a copy is returned with the sliced atoms, and ``trj`` is not modified. bonds : array-like,dtype=int, shape=(n_bonds,2), default=None If specified, sets these bonds in new topology split_shared_atoms: boolean If specified, check to see if atoms are shared per molecule in beads. If so, equally divide their weight accordingly for each bead. mapping_function: string, default='com': how to map xyz coordinates options: %s center_postwrap: Boolean Whether to wrap the CG system after it is mapped. Assumes that box is centered at 0, and only has effect if periodic information is present. Note - If repeated resSeq values are used, as for a repeated motiff in a CG polymer, those sections most be broken into separate chains or an incorrect topology will result Returns ------- traj : md.Trajectory The return value is either ``trj``, or the new trajectory, depending on the value of ``inplace``. """ % mapping_options.keys() if not len(atom_indices_list) == len(bead_label_list): raise ValueError("Must supply a list of bead labels of the " "same length as a list of selected atom indices") for bead_label in bead_label_list: if not (type(bead_label) is str) or len(bead_label) > 4 or len(bead_label) < 1: raise ValueError("Specified bead label '%s' is not valid, \ must be a string between 1 and 4 characters" % bead_label) bead_label_list = [bead_label.upper() for bead_label in bead_label_list] if mapping_function not in mapping_options: raise ValueError("Must select a mapping function from: %s"\ %mapping_options.keys()) if chain_list is None: chain_list = np.ones(len(atom_indices_list), dtype=int) elif len(chain_list) != len(atom_indices_list): raise ValueError("Supplied chain_list must be of the same length " "as a list of selected atom indices") if segment_id_list is not None and len(segment_id_list) != len( atom_indices_list): raise ValueError("Supplied segment_id_list must be of the same " "length as a list of selected atom indices") if resSeq_list is not None and len(resSeq_list) != len(atom_indices_list): raise ValueError("Supplied resSeq_list must be of the same " "length as a list of selected atom indices") n_beads = len(atom_indices_list) xyz = np.zeros((trj.xyz.shape[0], n_beads, trj.xyz.shape[2]), dtype=trj.xyz.dtype, order='C') forces = np.zeros((trj.xyz.shape[0], n_beads, trj.xyz.shape[2]), dtype=np.double, order='C') columns = ["serial", "name", "element", "resSeq", "resName", "chainID"] #total masse for each cg bead. masses = np.zeros((n_beads), dtype=np.float64) #list of masses for elements in cg bead. masses_i = [] #masses for ii in range(n_beads): #atoms in curent cg bead. atom_indices = atom_indices_list[ii] #first, construct lists of masses in current cg bead. temp_masses = np.array([]) for jj in atom_indices: temp_masses = np.append(temp_masses, trj.top.atom(jj).element.mass) masses_i.append(temp_masses) masses[ii] = masses_i[ii].sum() if hasattr(trj.top.atom(1), 'charge'): #total charge for each cg bead. charges = np.zeros((n_beads), dtype=np.float64) #lists of charges for in current cg bead charges_i = [] #charges for ii in range(n_beads): #atoms in curent cg bead. atom_indices = atom_indices_list[ii] #first, construct lists of masses in current cg bead. temp_charges = np.array([]) for jj in atom_indices: temp_charges = np.append(temp_charges, trj.top.atom(jj).charge) charges_i.append(temp_charges) charges[ii] = charges_i[ii].sum() forcenorm_i = [] if mapping_function == 'cof' or mapping_function == 'center_of_force': for ii in range(n_beads): atom_indices = atom_indices_list[ii] forcenorm_i.append(get_forcenorms(trj, atom_indices)) if mapping_function == 'coc' or mapping_function == 'center_of_charge': for charge in charges: if np.absolute(charge) < charge_tol: raise ValueError("Total charge on site %i is near zero" % ii) topology_labels = [] element_label_dict = {} if (split_shared_atoms): mod_weights_list = gen_unique_overlap_mod_weights(atom_indices_list) has_forces = False try: trj.__dict__['forces'] test_forces = map_forces(trj, (0, )) has_forces = True except TypeError: print("WARNING: Invalid Forces\nNo Map applied to forces") except KeyError: pass except: print("Unknown error, check your forces\nexiting...") raise for i in range(n_beads): atom_indices = atom_indices_list[i] bead_label = bead_label_list[i] xyz_i = xyz[:, i, :] if mapping_function == 'coc' or mapping_function == 'center_of_charge': weights = charges_i[i] elif mapping_function == 'com' or mapping_function == 'center_of_mass': weights = masses_i[i] elif mapping_function == 'cof' or mapping_function == 'center_of_force': weights = forcenorm_i[i] elif mapping_function == 'center': weights = np.ones(len(atom_indices)) if (mod_weights_list is not None): weights[:] = np.multiply(weights, mod_weights_list[i]) compute_center_weighted(xyz_i, trj.xyz, atom_indices, weights, unitcell_lengths=trj.unitcell_lengths, center_postwrap=center_postwrap) if has_forces: forces_i = map_forces(trj, atom_indices) forces[:, i, :] = forces_i if resSeq_list is not None: resSeq = resSeq_list[i] else: resSeq = i + 1 #element_label='%4s'%('B%i'%(resSeq)) if not bead_label in element_label_dict: element_label = '%2s' % ('B%i' % (len(element_label_dict) % 10)) element_label_dict[bead_label] = element_label else: element_label = element_label_dict[bead_label] if element_label.strip().upper( ) not in element.Element._elements_by_symbol: element.Element(1000 + resSeq, element_label, element_label, masses[i], 1.0) topology_labels.append([ i, bead_label, element_label, resSeq, '%3s' % bead_label, chain_list[i] ]) df = pd.DataFrame(topology_labels, columns=columns) topology = Topology.from_dataframe(df, bonds=bonds) if segment_id_list is not None: for beadidx, bead in enumerate(topology.atoms): bead.residue.segment_id = segment_id_list[beadidx] if inplace: if trj._topology is not None: trj._topology = topology trj._xyz = xyz return trj unitcell_lengths = unitcell_angles = None if trj._have_unitcell: unitcell_lengths = trj._unitcell_lengths.copy() unitcell_angles = trj._unitcell_angles.copy() time = trj._time.copy() new_trj = Trajectory(xyz=xyz, topology=topology, time=time, unitcell_lengths=unitcell_lengths, unitcell_angles=unitcell_angles) new_trj.forces = forces return new_trj
def cg_by_index(trj, atom_indices_list, bead_label_list, chain_list=None, segment_id_list=None, resSeq_list=None, inplace=False, bonds=None, mapping_function="com"): """Create a coarse grained (CG) trajectory from subsets of atoms by computing centers of mass of selected sets of atoms. Parameters ---------- atom_indices_list : list of array-like, dtype=int, shape=(n_beads,n_atoms) List of indices of atoms to combine into CG sites bead_label_list : list of maximum 4-letter strings to label CG sites chain_list : optional list of chain id's to split resulting beads into separate chains resSeq_list : optional list of residue sequence id's to assign cg residues segment_id_list : optional list of segment id's to assign cg residues inplace : bool, default=False If ``True``, the operation is done inplace, modifying ``trj``. Otherwise, a copy is returned with the sliced atoms, and ``trj`` is not modified. bonds : array-like,dtype=int, shape=(n_bonds,2), default=None If specified, sets these bonds in new topology mapping_function: string, default='com': how to map xyz coordinates options: %s Note - If repeated resSeq values are used, as for a repeated motiff in a CG polymer, those sections most be broken into separate chains or an incorrect topology will result Returns ------- traj : md.Trajectory The return value is either ``trj``, or the new trajectory, depending on the value of ``inplace``. """ % mapping_options.keys() if not len(atom_indices_list) == len(bead_label_list): raise ValueError( "Must supply a list of bead labels of the same length as a list of selected atom indices" ) for bead_label in bead_label_list: if not (type(bead_label) is str) or len(bead_label) > 4 or len(bead_label) < 1: raise ValueError( "Specified bead label '%s' is not valid, must be a string between 1 and 4 characters" % bead_label) bead_label_list = [bead_label.upper() for bead_label in bead_label_list] if mapping_function not in mapping_options: raise ValueError("Must select a mapping function from: %s" % mapping_options.keys()) map_coords = mapping_options[mapping_function] if chain_list is None: chain_list = np.ones(len(atom_indices_list), dtype=int) elif len(chain_list) != len(atom_indices_list): raise ValueError( "Supplied chain_list must be of the same length as a list of selected atom indices" ) if segment_id_list is not None and len(segment_id_list) != len( atom_indices_list): raise ValueError( "Supplied segment_id_list must be of the same length as a list of selected atom indices" ) if resSeq_list is not None and len(resSeq_list) != len(atom_indices_list): raise ValueError( "Supplied resSeq_list must be of the same length as a list of selected atom indices" ) n_beads = len(atom_indices_list) xyz = np.zeros((trj.xyz.shape[0], n_beads, trj.xyz.shape[2]), dtype=trj.xyz.dtype, order='C') forces = np.zeros((trj.xyz.shape[0], n_beads, trj.xyz.shape[2]), dtype=np.double, order='C') columns = ["serial", "name", "element", "resSeq", "resName", "chainID"] masses = np.array([ np.sum([a.mass for a in trj.top.atoms if a.index in atom_indices]) for atom_indices in atom_indices_list ], dtype=np.float64) charges = np.array([ np.sum([a.charge for a in trj.top.atoms if a.index in atom_indices]) for atom_indices in atom_indices_list ], dtype=np.float64) topology_labels = [] element_label_dict = {} xyz_i = np.zeros((trj.xyz.shape[0], trj.xyz.shape[2]), dtype=trj.xyz.dtype, order='C') for i in range(n_beads): atom_indices = atom_indices_list[i] bead_label = bead_label_list[i] #xyz_i = map_coords(trj,atom_indices) masses_i = np.array( [a.mass for a in trj.top.atoms if a.index in atom_indices_list[i]], dtype=np.float64) map_coords(xyz_i, trj.xyz, atom_indices, masses_i, unitcell_lengths=trj.unitcell_lengths) xyz[:, i, :] = xyz_i if "forces" in trj.__dict__ and len(trj.forces) > 0: forces_i = map_forces(trj, atom_indices) forces[:, i, :] = forces_i if resSeq_list is not None: resSeq = resSeq_list[i] else: resSeq = i + 1 #element_label='%4s'%('B%i'%(resSeq)) if not bead_label in element_label_dict: element_label = '%2s' % ('B%i' % (len(element_label_dict) % 10)) element_label_dict[bead_label] = element_label else: element_label = element_label_dict[bead_label] if element_label.strip().upper( ) not in element.Element._elements_by_symbol: element.Element(1000 + resSeq, element_label, element_label, masses[i], 1.0) topology_labels.append([ i, bead_label, element_label, resSeq, '%3s' % bead_label, chain_list[i] ]) df = pd.DataFrame(topology_labels, columns=columns) topology = Topology.from_dataframe(df, bonds=bonds) if segment_id_list is not None: for beadidx, bead in enumerate(topology.atoms): bead.residue.segment_id = segment_id_list[beadidx] if inplace: if trj._topology is not None: trj._topology = topology trj._xyz = xyz return trj unitcell_lengths = unitcell_angles = None if trj._have_unitcell: unitcell_lengths = trj._unitcell_lengths.copy() unitcell_angles = trj._unitcell_angles.copy() time = trj._time.copy() new_trj = Trajectory(xyz=xyz, topology=topology, time=time, unitcell_lengths=unitcell_lengths, unitcell_angles=unitcell_angles) new_trj.forces = forces return new_trj
def cg_by_index(trj, atom_indices_list, bead_label_list, chain_list=None, segment_id_list=None, resSeq_list=None, inplace=False, bonds=None, mapping_function="com"): """Create a coarse grained (CG) trajectory from subsets of atoms by computing centers of mass of selected sets of atoms. Parameters ---------- atom_indices_list : list of array-like, dtype=int, shape=(n_beads,n_atoms) List of indices of atoms to combine into CG sites bead_label_list : list of maximum 4-letter strings to label CG sites chain_list : optional list of chain id's to split resulting beads into separate chains resSeq_list : optional list of residue sequence id's to assign cg residues segment_id_list : optional list of segment id's to assign cg residues inplace : bool, default=False If ``True``, the operation is done inplace, modifying ``trj``. Otherwise, a copy is returned with the sliced atoms, and ``trj`` is not modified. bonds : array-like,dtype=int, shape=(n_bonds,2), default=None If specified, sets these bonds in new topology mapping_function: string, default='com': how to map xyz coordinates options: %s Note - If repeated resSeq values are used, as for a repeated motiff in a CG polymer, those sections most be broken into separate chains or an incorrect topology will result Returns ------- traj : md.Trajectory The return value is either ``trj``, or the new trajectory, depending on the value of ``inplace``. """%mapping_options.keys() if not len(atom_indices_list)==len(bead_label_list): raise ValueError("Must supply a list of bead labels of the same length as a list of selected atom indices") for bead_label in bead_label_list: if not (type(bead_label) is str) or len(bead_label)>4 or len(bead_label)<1: raise ValueError("Specified bead label '%s' is not valid, must be a string between 1 and 4 characters"%bead_label) bead_label_list = [ bead_label.upper() for bead_label in bead_label_list ] if mapping_function not in mapping_options: raise ValueError("Must select a mapping function from: %s"%mapping_options.keys()) map_coords = mapping_options[mapping_function] if chain_list is None: chain_list = np.ones(len(atom_indices_list),dtype=int) elif len(chain_list)!=len(atom_indices_list): raise ValueError("Supplied chain_list must be of the same length as a list of selected atom indices") if segment_id_list is not None and len(segment_id_list)!=len(atom_indices_list): raise ValueError("Supplied segment_id_list must be of the same length as a list of selected atom indices") if resSeq_list is not None and len(resSeq_list)!=len(atom_indices_list): raise ValueError("Supplied resSeq_list must be of the same length as a list of selected atom indices") n_beads = len(atom_indices_list) xyz = np.zeros((trj.xyz.shape[0],n_beads,trj.xyz.shape[2]),dtype=trj.xyz.dtype,order='C') forces = np.zeros((trj.xyz.shape[0],n_beads,trj.xyz.shape[2]),dtype=np.double,order='C') columns = ["serial","name","element","resSeq","resName","chainID"] masses = np.array([ np.sum([a.mass for a in trj.top.atoms if a.index in atom_indices]) for atom_indices in atom_indices_list],dtype=np.float64) charges = np.array([ np.sum([a.charge for a in trj.top.atoms if a.index in atom_indices]) for atom_indices in atom_indices_list],dtype=np.float64) topology_labels = [] element_label_dict = {} xyz_i = np.zeros((trj.xyz.shape[0],trj.xyz.shape[2]),dtype=trj.xyz.dtype,order='C') for i in range(n_beads): atom_indices = atom_indices_list[i] bead_label = bead_label_list[i] #xyz_i = map_coords(trj,atom_indices) masses_i = np.array([a.mass for a in trj.top.atoms if a.index in atom_indices_list[i]],dtype=np.float64) map_coords(xyz_i,trj.xyz,atom_indices,masses_i,unitcell_lengths=trj.unitcell_lengths) xyz[:,i,:] = xyz_i if "forces" in trj.__dict__ and len(trj.forces)>0: forces_i = map_forces(trj,atom_indices) forces[:,i,:] = forces_i if resSeq_list is not None: resSeq = resSeq_list[i] else: resSeq = i + 1 #element_label='%4s'%('B%i'%(resSeq)) if not bead_label in element_label_dict: element_label='%2s'%('B%i'%(len(element_label_dict)%10)) element_label_dict[bead_label] = element_label else: element_label = element_label_dict[bead_label] if element_label.strip().upper() not in element.Element._elements_by_symbol: element.Element(1000+resSeq, element_label, element_label, masses[i], 1.0) topology_labels.append( [i,bead_label,element_label,resSeq,'%3s'%bead_label,chain_list[i]] ) df = pd.DataFrame(topology_labels,columns=columns) topology = Topology.from_dataframe(df,bonds=bonds) if segment_id_list is not None: for beadidx,bead in enumerate(topology.atoms): bead.residue.segment_id = segment_id_list[beadidx] if inplace: if trj._topology is not None: trj._topology = topology trj._xyz = xyz return trj unitcell_lengths = unitcell_angles = None if trj._have_unitcell: unitcell_lengths = trj._unitcell_lengths.copy() unitcell_angles = trj._unitcell_angles.copy() time = trj._time.copy() new_trj = Trajectory(xyz=xyz, topology=topology, time=time, unitcell_lengths=unitcell_lengths, unitcell_angles=unitcell_angles) new_trj.forces = forces return new_trj