Example #1
0
def obtain_scale_factors(parameter_dict):
    print("Obtaining correct scaling for epsilon and sigma...")
    # The scaling factors are 1/largestSigma in the LJ coeffs, and 1
    # / largestEpsilon
    LJFFs = []
    for CG_site, directory in parameter_dict["CG_to_template_dirs"].items():
        FF_loc = os.path.join(
            directory, parameter_dict["CG_to_template_force_fields"][CG_site])
        FF = hf.load_FF_xml(FF_loc)
        LJFFs += FF["lj"]
    largest_sigma = max(list(map(float, np.array(LJFFs)[:, 2])))
    largest_epsilon = max(list(map(float, np.array(LJFFs)[:, 1])))
    return 1 / float(largest_sigma), 1 / float(largest_epsilon)
Example #2
0
 def get_new_type_mappings(
     self, CG_to_template_dirs, CG_to_template_force_fields
 ):
     force_field_locations = []
     force_field_mappings = []
     morphology_atom_types = []
     CG_to_template_mappings = {}
     for CG_site, directory in CG_to_template_dirs.items():
         FF_loc = os.path.join(
             directory, CG_to_template_force_fields[CG_site]
         )
         if FF_loc not in force_field_locations:
             force_field_locations.append(FF_loc)
     for FF_loc in force_field_locations:
         mapping_for_this_FF = {}
         force_field = hf.load_FF_xml(FF_loc)
         for lj_interaction in force_field["lj"]:
             atom_type = lj_interaction[0]
             while atom_type in morphology_atom_types:
                 # Atom type already exists in morphology, so increment the
                 # atom_type number by one
                 for i in range(1, len(atom_type)):
                     # Work out where the integer start so we can increment
                     # it (should be i = 1 for one-character element names)
                     try:
                         integer = int(atom_type[i:])
                         break
                     except:
                         continue
                 atom_type = "".join([atom_type[:i], str(integer + 1)])
             morphology_atom_types.append(atom_type)
             mapping_for_this_FF[lj_interaction[0]] = atom_type
         force_field_mappings.append(mapping_for_this_FF)
     for CG_site, directory in CG_to_template_dirs.items():
         FF_loc = os.path.join(
             directory, CG_to_template_force_fields[CG_site]
         )
         CG_to_template_mappings[CG_site] = force_field_mappings[
             force_field_locations.index(FF_loc)
         ]
     return CG_to_template_mappings
Example #3
0
 def get_FF_coeffs(self):
     # First find all of the forcefields specified in the par file
     all_FF_names = {}
     for CG_site, directory in self.CG_to_template_dirs.items():
         FF_loc = os.path.join(directory, self.CG_to_template_force_fields[CG_site])
         if FF_loc not in list(all_FF_names.values()):
             all_FF_names[CG_site] = FF_loc
     FF_list = []
     # Then load in all of the FFs with the appropriate mappings
     for CG_site in list(all_FF_names.keys()):
         FF_list.append(
             hf.load_FF_xml(
                 all_FF_names[CG_site], mapping=self.new_type_mappings[CG_site]
             )
         )
     # Combine all of the individual, mapped FFs into one master field
     master_FF = {}
     for FF in FF_list:
         for FF_type in list(FF.keys()):
             if FF_type not in list(master_FF.keys()):
                 master_FF[FF_type] = FF[FF_type]
             else:
                 master_FF[FF_type] += FF[FF_type]
     # Finally, assign the expected variables to each value in the masterFF
     self.lj_coeffs = master_FF["lj"]
     self.dpd_coeffs = master_FF["dpd"]
     self.bond_coeffs = master_FF["bond"]
     self.angle_coeffs = master_FF["angle"]
     self.dihedral_coeffs = master_FF["dihedral"]
     self.improper_coeffs = master_FF["improper"]
     # Set Pair Coeffs
     self.pair_class = None
     if self.pair_type.lower() != "none":
         # Log the correct pairType energy
         self.log_quantities.append("".join(["pair_", self.pair_type, "_energy"]))
         # HOOMD crashes if you don't specify all pair combinations, so need
         # to make sure we do this.
         atom_types = sorted(
             list(set(self.AA_morphology_dict["type"])),
             key=lambda x: hf.convert_string_to_int(x),
         )
         all_pair_types = []
         # Create a list of all of the pairTypes to ensure that the required
         # coefficients are set
         for atom_type1 in atom_types:
             for atom_type2 in atom_types:
                 pair_type = "{0}-{1}".format(atom_type1, atom_type2)
                 reverse_pair_type = "{1}-{0}".format(atom_type1, atom_type2)
                 if (pair_type not in all_pair_types) and (
                     reverse_pair_type not in all_pair_types
                 ):
                     all_pair_types.append(pair_type)
         # Read in the pairTypes, parameters and coefficients and set them
         # for HOOMD
         if self.pair_type.lower() == "dpd":
             self.pair_class = pair.dpd(
                 r_cut=self.pair_r_cut * self.s_scale, T=self.temperature
             )
             # Use the geometric mixing rule for all possible combinations of
             # the specified forcefield coefficients
             for atom_index1, atom_type1 in enumerate(
                 [coeff[0] for coeff in self.dpd_coeffs]
             ):
                 for atom_index2, atom_type2 in enumerate(
                     [coeff[0] for coeff in self.dpd_coeffs]
                 ):
                     self.pair_class.pair_coeff.set(
                         atom_type1,
                         atom_type2,
                         A=np.sqrt(
                             (self.dpd_coeffs[atom_index1][1] * self.e_scale)
                             * (self.dpd_coeffs[atom_index2][1] * self.e_scale)
                         ),
                         r_cut=np.sqrt(
                             (self.dpd_coeffs[atom_index1][2] * self.s_scale)
                             * (self.dpd_coeffs[atom_index2][1] * self.s_scale)
                         ),
                         gamma=self.pair_dpd_gamma_val,
                     )
                     try:
                         all_pair_types.remove(
                             "{0}-{1}".format(atom_type1, atom_type2)
                         )
                     except:
                         pass
             # Because we've been removing each pair from allPairTypes, all
             # that are left are the pair potentials that are unspecified in
             # the parXX.py (e.g. ghost particle interactions), so set these
             # interactions to zero
             for pair_type in all_pair_types:
                 self.pair_class.pair_coeff.set(
                     pair_type.split("-")[0],
                     pair_type.split("-")[1],
                     A=0.0,
                     r_cut=0.0,
                     gamma=0.0,
                 )
         elif self.pair_type.lower() == "lj":
             self.pair_class = pair.lj(r_cut=self.pair_r_cut * self.s_scale)
             self.pair_class.set_params(mode="xplor")
             for atom_index1, atom_type1 in enumerate(
                 [coeff[0] for coeff in self.lj_coeffs]
             ):
                 for atom_index2, atom_type2 in enumerate(
                     [coeff[0] for coeff in self.lj_coeffs]
                 ):
                     self.pair_class.pair_coeff.set(
                         atom_type1,
                         atom_type2,
                         epsilon=np.sqrt(
                             (self.lj_coeffs[atom_index1][1] * self.e_scale)
                             * (self.lj_coeffs[atom_index2][1] * self.e_scale)
                         ),
                         sigma=np.sqrt(
                             (self.lj_coeffs[atom_index1][2] * self.s_scale)
                             * (self.lj_coeffs[atom_index2][2] * self.s_scale)
                         ),
                     )
                     try:
                         all_pair_types.remove(
                             "{0}-{1}".format(atom_type1, atom_type2)
                         )
                     except:
                         pass
             # Because we've been removing each pair from allPairTypes, all
             # that are left are the pair potentials that are unspecified in
             # the parXX.py (e.g. ghost particle interactions), so set these
             # interactions to zero
             for pair_type in all_pair_types:
                 self.pair_class.pair_coeff.set(
                     pair_type.split("-")[0],
                     pair_type.split("-")[1],
                     epsilon=0.0,
                     sigma=0.0,
                 )
         else:
             raise SystemError(
                 "Non-dpd/lj pair potentials not yet hard-coded!"
                 " Please describe how to interpret them on this line."
             )
     # Set Bond Coeffs
     # Real bonds
     if self.bond_type.lower() == "harmonic":
         if len(self.bond_coeffs) > 0:
             self.log_quantities.append(
                 "".join(["bond_", self.bond_type, "_energy"])
             )
         self.bond_class = bond.harmonic()
         for bond_coeff in self.bond_coeffs:
             # [k] = kcal mol^{-1} \AA^{-2} * episilon/sigma^{2}, [r0] =
             # \AA * sigma^{2}
             self.bond_class.bond_coeff.set(
                 bond_coeff[0],
                 k=bond_coeff[1] * (self.e_scale / (self.s_scale ** 2)),
                 r0=bond_coeff[2] * self.s_scale,
             )
         # Ghost bonds
         # If there is no anchoring, rather than change the xml, just set the
         # bond k values to 0.
         if self.group_anchoring.lower() == "all":
             group_anchoring_types = [
                 "".join(["X", CG_type])
                 for CG_type in list(self.CG_to_template_AAIDs.keys())
             ]
         elif self.group_anchoring.lower() == "none":
             group_anchoring_types = []
         else:
             group_anchoring_types = [
                 "".join(["X", CG_type])
                 for CG_type in self.group_anchoring.split(",")
             ]
         anchor_bond_types = []
         no_anchor_bond_types = []
         for bond_type in self.AA_morphology_dict["bond"]:
             if "X" in bond_type[0]:
                 atom_type1 = bond_type[0].split("-")[0]
                 atom_type2 = bond_type[0].split("-")[1]
                 if (atom_type1 in group_anchoring_types) or (
                     atom_type2 in group_anchoring_types
                 ):
                     if bond_type[0] not in anchor_bond_types:
                         anchor_bond_types.append(bond_type[0])
                 else:
                     if bond_type[0] not in no_anchor_bond_types:
                         no_anchor_bond_types.append(bond_type[0])
         for bond_type in anchor_bond_types:
             self.bond_class.bond_coeff.set(bond_type, k=1E6, r0=0)
         for bond_type in no_anchor_bond_types:
             self.bond_class.bond_coeff.set(bond_type, k=0, r0=0)
     else:
         raise SystemError(
             "Non-harmonic bond potentials not yet hard-coded!"
             " Please describe how to interpret them on this line."
         )
     # Set Angle Coeffs
     self.angle_class = None
     if len(self.angle_coeffs) > 0:
         self.log_quantities.append("".join(["angle_", self.angle_type, "_energy"]))
         if self.angle_type.lower() == "harmonic":
             self.angle_class = angle.harmonic()
             for angle_coeff in self.angle_coeffs:
                 # [k] = kcal mol^{-1} rad^{-2} * epsilon, [t] = rad
                 self.angle_class.set_coeff(
                     angle_coeff[0],
                     k=angle_coeff[1] * self.e_scale,
                     t0=angle_coeff[2],
                 )
         else:
             raise SystemError(
                 "Non-harmonic angle potentials not yet hard-coded!"
                 " please describe how to interpret them on this line."
             )
     else:
         print("No angles detected!")
     # Set Dihedral Coeffs
     self.dihedral_class = None
     if len(self.dihedral_coeffs) > 0:
         self.log_quantities.append(
             "".join(["dihedral_", self.dihedral_type, "_energy"])
         )
         if self.dihedral_type.lower() == "table":
             self.dihedral_class = dihedral.table(width=1000)
             for dihedral_coeff in self.dihedral_coeffs:
                 self.dihedral_class.dihedral_coeff.set(
                     dihedral_coeff[0],
                     func=multi_harmonic_torsion,
                     coeff=dict(
                         v0=dihedral_coeff[1] * self.e_scale,
                         v1=dihedral_coeff[2] * self.e_scale,
                         v2=dihedral_coeff[3] * self.e_scale,
                         v3=dihedral_coeff[4] * self.e_scale,
                         v4=dihedral_coeff[5] * self.e_scale,
                     ),
                 )
         elif self.dihedral_type.lower() == "opls":
             self.dihedral_class = dihedral.opls()
             for dihedral_coeff in self.dihedral_coeffs:
                 self.dihedral_class.set_coeff(
                     dihedral_coeff[0],
                     k1=dihedral_coeff[1] * self.e_scale,
                     k2=dihedral_coeff[2] * self.e_scale,
                     k3=dihedral_coeff[3] * self.e_scale,
                     k4=dihedral_coeff[4] * self.e_scale,
                 )
         else:
             raise SystemError(
                 "Non-tabulated dihedral potentials not yet hard-coded!"
                 " Please describe how to interpret them on this line."
             )
     else:
         print("No dihedrals detected")
     # Set Improper Coeffs
     self.improper_class = None
     if len(self.improper_coeffs) > 0:
         self.improper_class = improper.harmonic()
         for improper_coeff in self.improper_coeffs:
             self.improper_class.improper_coeff.set(
                 improper_coeff[0],
                 k=improper_coeff[1] * self.e_scale,
                 chi=improper_coeff[2],
             )