def _process_mass_line(self, line): words = line.split() try: mass = float(words[1]) except ValueError: raise ParameterError('Could not convert mass to float [%s]' % words[1]) except IndexError: raise ParameterError('Error parsing MASS line. Not enough tokens') if words[0] in self.atom_types: self.atom_types[words[0]].mass = mass elif words[0] in ('EP', 'LP'): atype = AtomType(words[0], len(self.atom_types)+1, mass, 0) self.atom_types[words[0]] = atype else: atype = AtomType(words[0], len(self.atom_types)+1, mass, AtomicNum[element_by_mass(mass)]) self.atom_types[words[0]] = atype
def create_random_structure(parametrized, novalence=False): """ Create a random Structure with random attributes Parameters ---------- parametrized : bool If True, add at least two of all kinds of parameters to the generated random structure. If False, just fill in the atoms and residues and some random valence terms, but no "types" novalence : bool, optional If True, no valence terms will be added. Default is False. This is set to False if parametrized is True """ from parmed.topologyobjects import ( Atom, Bond, AtomType, BondType, AngleType, DihedralType, ImproperType, CmapType, OutOfPlaneBendType, StretchBendType, TorsionTorsionType, AmoebaNonbondedExceptionType, Angle, UreyBradley, Dihedral, Improper, Cmap, TrigonalAngle, OutOfPlaneBend, StretchBend, PiTorsion, TorsionTorsion, AcceptorDonor, Group, ChiralFrame, MultipoleFrame, NonbondedException, RBTorsionType) from parmed import structure from copy import copy if parametrized: novalence = False # Generate random atom and parameter types atom_types = [ AtomType(''.join(random.sample(uppercase, 3)), i, random.random() * 16 + 1, random.randint(1, 8)) for i in range(random.randint(8, 20)) ] bond_types = [ BondType(random.random() * 2, random.random() * 100) for i in range(random.randint(10, 20)) ] angle_types = [ AngleType(random.random() * 50, random.random() * 120) for i in range(random.randint(10, 20)) ] dihed_types = [ DihedralType(random.random() * 10, random.randint(1, 6), random.choice([0, 180])) for i in range(random.randint(10, 20)) ] rb_types = [RBTorsionType(*[random.random() * 10 for i in range(6)])] imp_types = [ ImproperType(random.random() * 100, random.choice([0, 180])) for i in range(random.randint(10, 20)) ] cmap_types = [ CmapType(24, [random.random() * 5 for i in range(24 * 24)]) for i in range(random.randint(5, 10)) ] oop_types = [ OutOfPlaneBendType(random.random() * 100) for i in range(random.randint(10, 20)) ] strbnd_types = [ StretchBendType(random.random() * 10, random.random() * 10, random.random() * 2, random.random() * 2, random.random() * 120) for i in range(random.randint(10, 20)) ] ang1, ang2 = list(range(-180, 180, 36)), list(range(-180, 180, 18)) tortor_types = [ TorsionTorsionType((10, 20), ang1[:], ang2[:], [random.random() * 10 for j in range(200)]) for i in range(random.randint(5, 10)) ] for typ in atom_types: typ.set_lj_params(random.random() * 2, random.random() * 2) struct = structure.Structure() # Add atoms in residues for res in range(random.randint(20, 30)): resname = ''.join(random.sample(uppercase, 3)) resid = res + 1 for i in range(random.randint(10, 25)): name = ''.join(random.sample(uppercase, 4)) if parametrized: typ = random.choice(atom_types) type = str(typ) mass = typ.mass atomic_number = typ.atomic_number else: type = ''.join(random.sample(uppercase, 3)) mass = random.random() * 16 + 1 atomic_number = random.randint(1, 8) charge = random.random() * 2 - 1 solvent_radius = random.random() * 2 screen = random.random() * 2 atom = Atom(atomic_number=atomic_number, type=type, charge=charge, mass=mass, solvent_radius=solvent_radius, screen=screen, name=name) if parametrized: atom.atom_type = typ struct.add_atom(atom, resname, resid) if novalence: return struct # Possibly add parameter type lists if parametrized: struct.bond_types.extend([copy(x) for x in bond_types]) struct.bond_types.claim() struct.angle_types.extend([copy(x) for x in angle_types]) struct.angle_types.claim() struct.dihedral_types.extend([copy(x) for x in dihed_types]) struct.dihedral_types.claim() struct.rb_torsion_types.extend([copy(x) for x in rb_types]) struct.rb_torsion_types.claim() struct.urey_bradley_types.extend([copy(x) for x in bond_types]) struct.urey_bradley_types.claim() struct.improper_types.extend([copy(x) for x in imp_types]) struct.improper_types.claim() struct.cmap_types.extend([copy(x) for x in cmap_types]) struct.cmap_types.claim() struct.trigonal_angle_types.extend([copy(x) for x in angle_types]) struct.trigonal_angle_types.claim() struct.out_of_plane_bend_types.extend([copy(x) for x in oop_types]) struct.out_of_plane_bend_types.claim() struct.pi_torsion_types.extend([copy(x) for x in dihed_types]) struct.pi_torsion_types.claim() struct.stretch_bend_types.extend([copy(x) for x in strbnd_types]) struct.stretch_bend_types.claim() struct.torsion_torsion_types.extend([copy(x) for x in tortor_types]) struct.torsion_torsion_types.claim() struct.adjust_types.extend([ AmoebaNonbondedExceptionType(0.5, 0.5, 0.6, 0.6, 0.7) for i in range(random.randint(10, 20)) ]) struct.adjust_types.claim() # Add valence terms with optional for i in range(random.randint(40, 50)): struct.bonds.append(Bond(*random.sample(struct.atoms, 2))) if parametrized: struct.bonds[-1].type = random.choice(struct.bond_types) for i in range(random.randint(35, 45)): struct.angles.append(Angle(*random.sample(struct.atoms, 3))) if parametrized: struct.angles[-1].type = random.choice(struct.angle_types) for i in range(random.randint(35, 45)): struct.urey_bradleys.append( UreyBradley(*random.sample(struct.atoms, 2))) if parametrized: struct.urey_bradleys[-1].type = random.choice( struct.urey_bradley_types) for i in range(random.randint(30, 40)): struct.dihedrals.append( Dihedral(*random.sample(struct.atoms, 4), improper=random.choice([True, False]))) if parametrized: struct.dihedrals[-1].type = random.choice(struct.dihedral_types) for i in range(random.randint(30, 40)): struct.rb_torsions.append(Dihedral(*random.sample(struct.atoms, 4))) if parametrized: struct.rb_torsions[-1].type = random.choice( struct.rb_torsion_types) for i in range(random.randint(10, 20)): struct.impropers.append(Improper(*random.sample(struct.atoms, 4))) if parametrized: struct.impropers[-1].type = random.choice(struct.improper_types) for i in range(random.randint(25, 35)): struct.cmaps.append(Cmap(*random.sample(struct.atoms, 5))) if parametrized: struct.cmaps[-1].type = random.choice(struct.cmap_types) for i in range(random.randint(30, 40)): struct.trigonal_angles.append( TrigonalAngle(*random.sample(struct.atoms, 4))) if parametrized: struct.trigonal_angles[-1].type = random.choice( struct.trigonal_angle_types) for i in range(random.randint(30, 40)): struct.out_of_plane_bends.append( OutOfPlaneBend(*random.sample(struct.atoms, 4))) if parametrized: struct.out_of_plane_bends[-1].type = random.choice( struct.out_of_plane_bend_types) for i in range(random.randint(30, 40)): struct.stretch_bends.append( StretchBend(*random.sample(struct.atoms, 3))) if parametrized: struct.stretch_bends[-1].type = random.choice( struct.stretch_bend_types) for i in range(random.randint(20, 30)): struct.pi_torsions.append(PiTorsion(*random.sample(struct.atoms, 6))) if parametrized: struct.pi_torsions[-1].type = random.choice( struct.pi_torsion_types) for i in range(random.randint(10, 20)): struct.torsion_torsions.append( TorsionTorsion(*random.sample(struct.atoms, 5))) if parametrized: struct.torsion_torsions[-1].type = random.choice( struct.torsion_torsion_types) # Now use some lesser-used features for i in range(random.randint(5, 10)): struct.acceptors.append(AcceptorDonor(*random.sample(struct.atoms, 2))) struct.donors.append(AcceptorDonor(*random.sample(struct.atoms, 2))) struct.groups.append(Group(random.choice(struct.atoms), 2, 0)) struct.chiral_frames.append( ChiralFrame(*random.sample(struct.atoms, 2), chirality=random.choice([-1, 1]))) struct.multipole_frames.append( MultipoleFrame(random.choice(struct.atoms), 0, 1, 2, 3)) for i in range(random.randint(20, 30)): struct.adjusts.append( NonbondedException(*random.sample(struct.atoms, 2))) if parametrized: struct.adjusts[-1].type = random.choice(struct.adjust_types) struct.prune_empty_terms() struct.unchange() struct.update_dihedral_exclusions() return struct
def from_structure(cls, struct, allow_unequal_duplicates=True): """ Extracts known parameters from a Structure instance Parameters ---------- struct : :class:`parmed.structure.Structure` The parametrized ``Structure`` instance from which to extract parameters into a ParameterSet allow_unequal_duplicates : bool, optional If True, if two or more unequal parameter types are defined by the same atom types, the last one encountered will be assigned. If False, an exception will be raised. Default is True Returns ------- params : :class:`ParameterSet` The parameter set with all parameters defined in the Structure Notes ----- The parameters here are copies of the ones in the Structure, so modifying the generated ParameterSet will have no effect on ``struct``. Furthermore, the *first* occurrence of each parameter will be used. If future ones differ, they will be silently ignored, since this is expected behavior in some instances (like with Gromacs topologies in the ff99sb-ildn force field) unless ``allow_unequal_duplicates`` is set to ``False`` Dihedrals are a little trickier. They can be multi-term, which can be represented either as a *single* entry in dihedrals with a type of DihedralTypeList or multiple entries in dihedrals with a DihedralType parameter type. In this case, the parameter is constructed from either the first DihedralTypeList found or the first DihedralType of each periodicity found if no matching DihedralTypeList is found. Raises ------ :class:`parmed.exceptions.ParameterError` if allow_unequal_duplicates is False and 2+ unequal parameters are defined between the same atom types. `NotImplementedError` if any AMOEBA potential terms are defined in the input structure """ params = cls() found_dihed_type_list = dict() for atom in struct.atoms: if atom.atom_type in (UnassignedAtomType, None): atom_type = AtomType(atom.type, None, atom.mass, atom.atomic_number) atom_type.set_lj_params(atom.epsilon, atom.rmin, atom.epsilon_14, atom.rmin_14) params.atom_types[atom.type] = atom_type else: atom_type = copy(atom.atom_type) params.atom_types[str(atom_type)] = atom_type if atom_type.number is not None: params.atom_types_int[int(atom_type)] = atom_type params.atom_types_tuple[(int(atom_type), str(atom_type))] =\ atom_type for bond in struct.bonds: if bond.type is None: continue key = (bond.atom1.type, bond.atom2.type) if key in params.bond_types: if (not allow_unequal_duplicates and params.bond_types[key] != bond.type): raise ParameterError('Unequal bond types defined between ' '%s and %s' % key) continue # pragma: no cover typ = copy(bond.type) key = (bond.atom1.type, bond.atom2.type) params.bond_types[key] = typ params.bond_types[tuple(reversed(key))] = typ for angle in struct.angles: if angle.type is None: continue key = (angle.atom1.type, angle.atom2.type, angle.atom3.type) if key in params.angle_types: if (not allow_unequal_duplicates and params.angle_types[key] != angle.type): raise ParameterError('Unequal angle types defined between ' '%s, %s, and %s' % key) continue # pragma: no cover typ = copy(angle.type) key = (angle.atom1.type, angle.atom2.type, angle.atom3.type) params.angle_types[key] = typ params.angle_types[tuple(reversed(key))] = typ if angle.funct == 5: key = (angle.atom1.type, angle.atom3.type) params.urey_bradley_types[key] = NoUreyBradley params.urey_bradley_types[tuple(reversed(key))] = NoUreyBradley for dihedral in struct.dihedrals: if dihedral.type is None: continue key = (dihedral.atom1.type, dihedral.atom2.type, dihedral.atom3.type, dihedral.atom4.type) if dihedral.improper: key = cls._periodic_improper_key( dihedral.atom1, dihedral.atom2, dihedral.atom3, dihedral.atom4, ) if key in params.improper_periodic_types: if (not allow_unequal_duplicates and params.improper_periodic_types[key] != dihedral.type): raise ParameterError('Unequal dihedral types defined ' 'between %s, %s, %s, and %s' % key) continue # pragma: no cover typ = copy(dihedral.type) params.improper_periodic_types[key] = typ else: # Proper dihedral. Look out for multi-term forms if (key in params.dihedral_types and found_dihed_type_list[key]): # Already found a multi-term dihedral type list if not allow_unequal_duplicates: if isinstance(dihedral.type, DihedralTypeList): if params.dihedral_types[key] != dihedral.type: raise ParameterError('Unequal dihedral types ' 'defined between %s, %s, %s, and %s' % key) elif isinstance(dihedral.type, DihedralType): for dt in params.dihedral_types[key]: if dt == dihedral.type: break else: raise ParameterError('Unequal dihedral types ' 'defined between %s, %s, %s, and %s' % key) continue # pragma: no cover elif key in params.dihedral_types: # We have one term of a potentially multi-term dihedral. if isinstance(dihedral.type, DihedralTypeList): # This is a full Fourier series list found_dihed_type_list[key] = True found_dihed_type_list[tuple(reversed(key))] = True typ = copy(dihedral.type) params.dihedral_types[key] = typ params.dihedral_types[tuple(reversed(key))] = typ else: # This *might* be another term. Make sure another term # with its periodicity does not already exist for t in params.dihedral_types[key]: if t.per == dihedral.type.per: if (not allow_unequal_duplicates and t != dihedral.type): raise ParameterError('Unequal dihedral ' 'types defined bewteen %s, %s, %s, ' 'and %s' % key) break else: # If we got here, we did NOT find this periodicity. # And since this is mutating a list in-place, it # automatically propagates to the reversed key typ = copy(dihedral.type) params.dihedral_types[key].append(typ) else: # New parameter. If it's a DihedralTypeList, assign it and # be done with it. If it's a DihedralType, start a # DihedralTypeList to be added to later. if isinstance(dihedral.type, DihedralTypeList): found_dihed_type_list[key] = True found_dihed_type_list[tuple(reversed(key))] = True typ = copy(dihedral.type) params.dihedral_types[key] = typ params.dihedral_types[tuple(reversed(key))] = typ else: found_dihed_type_list[key] = False found_dihed_type_list[tuple(reversed(key))] = False typ = DihedralTypeList() typ.append(copy(dihedral.type)) params.dihedral_types[key] = typ params.dihedral_types[tuple(reversed(key))] = typ for improper in struct.impropers: if improper.type is None: continue key = (improper.atom1.type, improper.atom2.type, improper.atom3.type, improper.atom4.type) if key in params.improper_types: if (not allow_unequal_duplicates and params.improper_types[key] != improper.type): raise ParameterError('Unequal improper types defined ' 'between %s, %s, %s, and %s' % key) continue # pragma: no cover params.improper_types[key] = copy(improper.type) for cmap in struct.cmaps: if cmap.type is None: continue key = (cmap.atom1.type, cmap.atom2.type, cmap.atom3.type, cmap.atom4.type, cmap.atom2.type, cmap.atom3.type, cmap.atom4.type, cmap.atom5.type) if key in params.cmap_types: if (not allow_unequal_duplicates and cmap.type != params.cmap_types[key]): raise ParameterError('Unequal CMAP types defined between ' '%s, %s, %s, %s, and %s' % (key[0], key[1], key[2], key[3], key[7])) continue # pragma: no cover typ = copy(cmap.type) params.cmap_types[key] = typ params.cmap_types[tuple(reversed(key))] = typ for urey in struct.urey_bradleys: if urey.type is None or urey.type is NoUreyBradley: continue key = (urey.atom1.type, urey.atom2.type) if key not in params.urey_bradley_types: warnings.warn('Angle corresponding to Urey-Bradley type not ' 'found') typ = copy(urey.type) params.urey_bradley_types[key] = typ params.urey_bradley_types[tuple(reversed(key))] = typ for adjust in struct.adjusts: if adjust.type is None: continue key = (adjust.atom1.type, adjust.atom2.type) if key in params.pair_types: if (not allow_unequal_duplicates and params.pair_types[key] != adjust.type): raise ParameterError('Unequal pair types defined between ' '%s and %s' % key) continue # pragma: no cover typ = copy(adjust.type) params.pair_types[key] = typ params.pair_types[tuple(reversed(key))] = typ # Trap for Amoeba potentials if (struct.trigonal_angles or struct.out_of_plane_bends or struct.torsion_torsions or struct.stretch_bends or struct.trigonal_angles or struct.pi_torsions): raise NotImplementedError('Cannot extract parameters from an ' 'Amoeba-parametrized system yet') return params
def _process_nonbonded(struct, force): """ Adds nonbonded parameters to the structure """ typemap = dict() element_typemap = defaultdict(int) assert force.getNumParticles() == len(struct.atoms), "Atom # mismatch" for i in range(force.getNumParticles()): atom = struct.atoms[i] chg, sig, eps = force.getParticleParameters(i) atype_name = Element[atom.atomic_number] key = (atype_name, sig._value, eps._value) if key in typemap: atom_type = typemap[key] else: element_typemap[atype_name] += 1 atype_name = '%s%d' % (atype_name, element_typemap[atype_name]) atom_type = AtomType(atype_name, None, atom.mass, atom.atomic_number) atom.charge = chg.value_in_unit(u.elementary_charge) rmin = sig.value_in_unit(u.angstroms) * 2**(1/6) / 2 # to rmin/2 eps = eps.value_in_unit(u.kilocalories_per_mole) atom_type.set_lj_params(eps, rmin) atom.atom_type = atom_type atom.type = atom_type.name explicit_exceptions = defaultdict(set) bond_graph_exceptions = defaultdict(set) for atom in struct.atoms: for a2 in atom.bond_partners: bond_graph_exceptions[atom].add(a2) for a3 in a2.bond_partners: bond_graph_exceptions[atom].add(a3) # TODO should we compress exception types? for ii in range(force.getNumExceptions()): i, j, q, sig, eps = force.getExceptionParameters(ii) q = q.value_in_unit(u.elementary_charge**2) sig = sig.value_in_unit(u.angstrom) eps = eps.value_in_unit(u.kilocalorie_per_mole) ai, aj = struct.atoms[i], struct.atoms[j] if q == 0 and (sig == 0 or eps == 0): explicit_exceptions[ai].add(aj) explicit_exceptions[aj].add(ai) continue try: chgscale = q / (ai.charge * aj.charge) except ZeroDivisionError: if q != 0: raise TypeError('Cannot scale charge product of 0 to match ' '%s' % q) chgscale = 1 nbtype = NonbondedExceptionType(sig*2**(1/6), eps, chgscale) struct.adjusts.append(NonbondedException(ai, aj, type=nbtype)) struct.adjust_types.append(nbtype) struct.adjust_types.claim() # Check that all of our exceptions are accounted for for ai, exceptions in iteritems(bond_graph_exceptions): if exceptions - explicit_exceptions[ai]: warnings.warn('Detected incomplete exceptions. Not supported.', OpenMMWarning) struct.unknown_functional = True
def from_structure(cls, struct, allow_unequal_duplicates=True): """ Extracts known parameters from a Structure instance Parameters ---------- struct : :class:`parmed.structure.Structure` The parametrized ``Structure`` instance from which to extract parameters into a ParameterSet allow_unequal_duplicates : bool, optional If True, if two or more unequal parameter types are defined by the same atom types, the last one encountered will be assigned. If False, an exception will be raised. Default is True Returns ------- params : :class:`ParameterSet` The parameter set with all parameters defined in the Structure Notes ----- The parameters here are copies of the ones in the Structure, so modifying the generated ParameterSet will have no effect on ``struct``. Furthermore, the *first* occurrence of each parameter will be used. If future ones differ, they will be silently ignored, since this is expected behavior in some instances (like with Gromacs topologies in the ff99sb-ildn force field) unless ``allow_unequal_duplicates`` is set to ``False`` Dihedrals are a little trickier. They can be multi-term, which can be represented either as a *single* entry in dihedrals with a type of DihedralTypeList or multiple entries in dihedrals with a DihedralType parameter type. In this case, the parameter is constructed from either the first DihedralTypeList found or the first DihedralType of each periodicity found if no matching DihedralTypeList is found. Raises ------ :class:`parmed.exceptions.ParameterError` if allow_unequal_duplicates is False and 2+ unequal parameters are defined between the same atom types. `NotImplementedError` if any AMOEBA potential terms are defined in the input structure """ params = cls() found_dihed_type_list = dict() for atom in struct.atoms: if atom.atom_type in (UnassignedAtomType, None): atom_type = AtomType(atom.type, None, atom.mass, atom.atomic_number) atom_type.set_lj_params(atom.epsilon, atom.rmin, atom.epsilon_14, atom.rmin_14) params.atom_types[atom.type] = atom_type else: atom_type = copy(atom.atom_type) params.atom_types[str(atom_type)] = atom_type if atom_type.number is not None: params.atom_types_int[int(atom_type)] = atom_type params.atom_types_tuple[(int(atom_type), str(atom_type))] =\ atom_type for bond in struct.bonds: if bond.type is None: continue key = (bond.atom1.type, bond.atom2.type) if key in params.bond_types: if (not allow_unequal_duplicates and params.bond_types[key] != bond.type): raise ParameterError('Unequal bond types defined between ' '%s and %s' % key) continue # pragma: no cover typ = copy(bond.type) key = (bond.atom1.type, bond.atom2.type) params.bond_types[key] = typ params.bond_types[tuple(reversed(key))] = typ for angle in struct.angles: if angle.type is None: continue key = (angle.atom1.type, angle.atom2.type, angle.atom3.type) if key in params.angle_types: if (not allow_unequal_duplicates and params.angle_types[key] != angle.type): raise ParameterError('Unequal angle types defined between ' '%s, %s, and %s' % key) continue # pragma: no cover typ = copy(angle.type) key = (angle.atom1.type, angle.atom2.type, angle.atom3.type) params.angle_types[key] = typ params.angle_types[tuple(reversed(key))] = typ if angle.funct == 5: key = (angle.atom1.type, angle.atom3.type) params.urey_bradley_types[key] = NoUreyBradley params.urey_bradley_types[tuple(reversed(key))] = NoUreyBradley for dihedral in struct.dihedrals: if dihedral.type is None: continue key = (dihedral.atom1.type, dihedral.atom2.type, dihedral.atom3.type, dihedral.atom4.type) if dihedral.improper: key = cls._periodic_improper_key( dihedral.atom1, dihedral.atom2, dihedral.atom3, dihedral.atom4, ) if key in params.improper_periodic_types: if (not allow_unequal_duplicates and params.improper_periodic_types[key] != dihedral.type): raise ParameterError('Unequal dihedral types defined ' 'between %s, %s, %s, and %s' % key) continue # pragma: no cover typ = copy(dihedral.type) params.improper_periodic_types[key] = typ else: # Proper dihedral. Look out for multi-term forms if (key in params.dihedral_types and found_dihed_type_list[key]): # Already found a multi-term dihedral type list if not allow_unequal_duplicates: if isinstance(dihedral.type, DihedralTypeList): if params.dihedral_types[key] != dihedral.type: raise ParameterError( 'Unequal dihedral types ' 'defined between %s, %s, %s, and %s' % key) elif isinstance(dihedral.type, DihedralType): for dt in params.dihedral_types[key]: if dt == dihedral.type: break else: raise ParameterError( 'Unequal dihedral types ' 'defined between %s, %s, %s, and %s' % key) continue # pragma: no cover elif key in params.dihedral_types: # We have one term of a potentially multi-term dihedral. if isinstance(dihedral.type, DihedralTypeList): # This is a full Fourier series list found_dihed_type_list[key] = True found_dihed_type_list[tuple(reversed(key))] = True typ = copy(dihedral.type) params.dihedral_types[key] = typ params.dihedral_types[tuple(reversed(key))] = typ else: # This *might* be another term. Make sure another term # with its periodicity does not already exist for t in params.dihedral_types[key]: if t.per == dihedral.type.per: if (not allow_unequal_duplicates and t != dihedral.type): raise ParameterError( 'Unequal dihedral ' 'types defined bewteen %s, %s, %s, ' 'and %s' % key) break else: # If we got here, we did NOT find this periodicity. # And since this is mutating a list in-place, it # automatically propagates to the reversed key typ = copy(dihedral.type) params.dihedral_types[key].append(typ) else: # New parameter. If it's a DihedralTypeList, assign it and # be done with it. If it's a DihedralType, start a # DihedralTypeList to be added to later. if isinstance(dihedral.type, DihedralTypeList): found_dihed_type_list[key] = True found_dihed_type_list[tuple(reversed(key))] = True typ = copy(dihedral.type) params.dihedral_types[key] = typ params.dihedral_types[tuple(reversed(key))] = typ else: found_dihed_type_list[key] = False found_dihed_type_list[tuple(reversed(key))] = False typ = DihedralTypeList() typ.append(copy(dihedral.type)) params.dihedral_types[key] = typ params.dihedral_types[tuple(reversed(key))] = typ for improper in struct.impropers: if improper.type is None: continue key = (improper.atom1.type, improper.atom2.type, improper.atom3.type, improper.atom4.type) if key in params.improper_types: if (not allow_unequal_duplicates and params.improper_types[key] != improper.type): raise ParameterError('Unequal improper types defined ' 'between %s, %s, %s, and %s' % key) continue # pragma: no cover params.improper_types[key] = copy(improper.type) for cmap in struct.cmaps: if cmap.type is None: continue key = (cmap.atom1.type, cmap.atom2.type, cmap.atom3.type, cmap.atom4.type, cmap.atom2.type, cmap.atom3.type, cmap.atom4.type, cmap.atom5.type) if key in params.cmap_types: if (not allow_unequal_duplicates and cmap.type != params.cmap_types[key]): raise ParameterError( 'Unequal CMAP types defined between ' '%s, %s, %s, %s, and %s' % (key[0], key[1], key[2], key[3], key[7])) continue # pragma: no cover typ = copy(cmap.type) params.cmap_types[key] = typ params.cmap_types[tuple(reversed(key))] = typ for urey in struct.urey_bradleys: if urey.type is None or urey.type is NoUreyBradley: continue key = (urey.atom1.type, urey.atom2.type) if key not in params.urey_bradley_types: warnings.warn('Angle corresponding to Urey-Bradley type not ' 'found') typ = copy(urey.type) params.urey_bradley_types[key] = typ params.urey_bradley_types[tuple(reversed(key))] = typ for adjust in struct.adjusts: if adjust.type is None: continue key = (adjust.atom1.type, adjust.atom2.type) if key in params.pair_types: if (not allow_unequal_duplicates and params.pair_types[key] != adjust.type): raise ParameterError('Unequal pair types defined between ' '%s and %s' % key) continue # pragma: no cover typ = copy(adjust.type) params.pair_types[key] = typ params.pair_types[tuple(reversed(key))] = typ # Trap for Amoeba potentials if (struct.trigonal_angles or struct.out_of_plane_bends or struct.torsion_torsions or struct.stretch_bends or struct.trigonal_angles or struct.pi_torsions): raise NotImplementedError('Cannot extract parameters from an ' 'Amoeba-parametrized system yet') return params
def _process_nonbonded(struct, force): """ Adds nonbonded parameters to the structure """ typemap = dict() element_typemap = defaultdict(int) assert force.getNumParticles() == len(struct.atoms), "Atom # mismatch" for i in range(force.getNumParticles()): atom = struct.atoms[i] chg, sig, eps = force.getParticleParameters(i) atype_name = Element[atom.atomic_number] key = (atype_name, sig._value, eps._value) if key in typemap: atom_type = typemap[key] else: element_typemap[atype_name] += 1 atype_name = '%s%d' % (atype_name, element_typemap[atype_name]) typemap[key] = atom_type = AtomType(atype_name, None, atom.mass, atom.atomic_number) atom.charge = chg.value_in_unit(u.elementary_charge) rmin = sig.value_in_unit(u.angstroms) * 2**(1.0 / 6) / 2 # to rmin/2 eps = eps.value_in_unit(u.kilocalories_per_mole) atom_type.set_lj_params(eps, rmin) atom.atom_type = atom_type atom.type = atom_type.name explicit_exceptions = defaultdict(set) bond_graph_exceptions = defaultdict(set) for atom in struct.atoms: for a2 in atom.bond_partners: if atom is not a2: bond_graph_exceptions[atom].add(a2) for a3 in a2.bond_partners: if a3 is atom: continue if atom is not a3: bond_graph_exceptions[atom].add(a3) # TODO should we compress exception types? for ii in range(force.getNumExceptions()): i, j, q, sig, eps = force.getExceptionParameters(ii) q = q.value_in_unit(u.elementary_charge**2) sig = sig.value_in_unit(u.angstrom) eps = eps.value_in_unit(u.kilocalorie_per_mole) ai, aj = struct.atoms[i], struct.atoms[j] if q == 0 and (sig == 0 or eps == 0): explicit_exceptions[ai].add(aj) explicit_exceptions[aj].add(ai) continue try: chgscale = q / (ai.charge * aj.charge) except ZeroDivisionError: if q != 0: raise TypeError('Cannot scale charge product of 0 to match ' '%s' % q) chgscale = 1 nbtype = NonbondedExceptionType(sig * 2**(1.0 / 6), eps, chgscale) struct.adjusts.append(NonbondedException(ai, aj, type=nbtype)) struct.adjust_types.append(nbtype) struct.adjust_types.claim() # Check that all of our exceptions are accounted for for ai, exceptions in iteritems(bond_graph_exceptions): if exceptions - explicit_exceptions[ai]: struct.unknown_functional = True warnings.warn('Detected incomplete exceptions. Not supported.', OpenMMWarning) break