Skip to content

Commit

Permalink
Corrected serious mistakes in the improper interactions defined in th…
Browse files Browse the repository at this point in the history
…e oplsaa.lt file (2023 version). (I verified the new version of oplsaa.lt is correct by confirming that the number and magnitude of the impropers generated by moltemplate (for ethylene and benzioc-acid) agree with impropers generated by the ligpargen server for these molecules.) I am now confident that the improper interactions in the latest oplsaa.lt file are correct! (There is one exception: allenes. The original BOSS filse have non-sensical improper interactions for allenes. So the oplsaa2lt.py conversion script comments those out.) The conversion script (oplsaa2lt.py) is also working, so there is no longer a need to hand-edit the generated oplsaa.lt file afterwards. Please update your oplsaa.lt files to this version. Previous versions will not work.
  • Loading branch information
jewettaij committed Dec 4, 2024
1 parent e10f1f2 commit e56e240
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 46 deletions.
30 changes: 25 additions & 5 deletions moltemplate/force_fields/convert_OPLSAA_to_LT/oplsaa2lt.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,12 @@ def rename_type(ty: str) -> str:
ty = ty.strip()
for orig, changed in TYPE_CONVERSION_TUPLES:
ty = ty.replace(orig, changed)
if ty in ["X", "Y", "Z"]:
# In BOSS files, "X", "Y", "Z" indicate wildcards
ty = "??" # But here we use "??" to indicate wildcards
if len(ty) == 1:
# It is a good idea to make sure these strings are the same length (2).
ty += '~' # (eg "C"->"C~") It doesn't matter which character we add
ty += "~" # (eg "C"->"C~") It doesn't matter which character we add
assert len(ty) == 2 # The "ty" strings should all be 2-characters long.
return ty

Expand Down Expand Up @@ -131,11 +134,28 @@ def get_dihedrals_and_impropers(input_lines) -> tuple[list[Dihedral], list[Impro
if dihed_definition.endswith("P in"):
dihed_definition = dihed_definition.replace("P in", "P")
types = list(map(rename_type, dihed_definition.split('-')))
assert len(types) == 4
comment = l[DEFINITION_END+1:].strip()
#if dihed_definition == "HC-CT-CT-C(O)"
if "improper" in comment:
loaded_impropers.append(
Improper(types=types, v1=v1, v2=v2, v3=v3, v4=v4, comment=comment))
# I've had good results using the "cenIsortJKL.py" symmetry
# rules with OPLSAA. (When I use those settings, the resulting
# LAMMPS data files agrees with the data files from LigParGen.)
# But in order for this to work, we need to swap the first two atom
# types, since now the first atom is the center. -Andrew 2024-12-04
types = [types[1], types[0], types[2], types[3]] # see above comment
improper = Improper(types=types, v1=v1, v2=v2, v3=v3, v4=v4, comment=comment)
# There is a weird problem with "allenes improper" interactions
# that appear in the 2023 version of the BOSS files.
# Those files specify improper interactions between atoms
# that are typically collinear. That would be numerically
# unstable so we must comment these out. This seems like
# a bug in the BOSS files. Perhaps later I'll report this.
# But for now, I just comment them out.
if comment.strip() == "allenes improper":
improper.to_comment = True

loaded_impropers.append(improper)

else:
loaded_dihedrals.append(
Dihedral(types=types, v1=v1, v2=v2, v3=v3, v4=v4, comment=comment))
Expand Down Expand Up @@ -404,7 +424,7 @@ def main(argv):
if not improper.to_skip:
outfile.write(f" {improper.coeff_line}")
outfile.write(" } # (end of improper_coeffs)\n")
outfile.write('\n write_once("Data Impropers By Type (opls_imp.py)") {\n')
outfile.write('\n write_once("Data Impropers By Type (cenIsortJKL.py)") {\n')
for improper in impropers:
if not improper.to_skip:
outfile.write(f" {improper.bytype_line}")
Expand Down
38 changes: 23 additions & 15 deletions moltemplate/force_fields/convert_OPLSAA_to_LT/oplsaa2lt_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def __init__(self, types: list[str], comment: str):
self.comment = comment
self.duplicate_count = 0
self.to_skip = False
self.to_comment = False

@property
def ty1(self) -> str:
Expand Down Expand Up @@ -190,6 +191,12 @@ def _duplicate_count_str(self) -> str:
return f"__{self.duplicate_count}"
return ""

@property
def _prepend_comment_if_needed(self) -> str:
if self.to_comment:
return "# UNTRUSTED: "
return ""


class Bond(BondedInteraction):
kind = "bond"
Expand All @@ -203,15 +210,17 @@ def __init__(self, types: list[str], k: str, eq: str, comment: str):

@property
def bytype_line(self) -> str:
l = f"@{type(self).kind}:{self.typename}"
l = self._prepend_comment_if_needed
l += f"@{type(self).kind}:{self.typename}"
l += f"{self._duplicate_count_str}"
l += f" @atom:*_b{self.ty1}*_a*_d*_i*"
l += f" @atom:*_b{self.ty2}*_a*_d*_i*\n"
return l

@property
def coeff_line(self) -> str:
l = f"{self._coeff_line_base}{self._duplicate_count_str} {self.k} {self.eq} # {self.comment}\n"
l = self._prepend_comment_if_needed
l += f"{self._coeff_line_base}{self._duplicate_count_str} {self.k} {self.eq} # {self.comment}\n"
return l


Expand All @@ -227,7 +236,8 @@ def __init__(self, types: list[str], k: str, eq: str, comment: str):

@property
def bytype_line(self) -> str:
l = f"@{type(self).kind}:{self.typename}"
l = self._prepend_comment_if_needed
l += f"@{type(self).kind}:{self.typename}"
l += f"{self._duplicate_count_str}"
l += f" @atom:*_b*_a{self.ty1}*_d*_i*"
l += f" @atom:*_b*_a{self.ty2}*_d*_i*"
Expand All @@ -236,7 +246,8 @@ def bytype_line(self) -> str:

@property
def coeff_line(self) -> str:
l = f"{self._coeff_line_base}{self._duplicate_count_str} {self.k} {self.eq} # {self.comment}\n"
l = self._prepend_comment_if_needed
l += f"{self._coeff_line_base}{self._duplicate_count_str} {self.k} {self.eq} # {self.comment}\n"
return l


Expand All @@ -251,7 +262,8 @@ def __init__(self, types: list[str], v1, v2, v3, v4, comment: str):

@property
def bytype_line(self) -> str:
l = f"@{type(self).kind}:{self.typename}"
l = self._prepend_comment_if_needed
l += f"@{type(self).kind}:{self.typename}"
l += f"{self._duplicate_count_str}"
l += f" @atom:*_b*_a*_d{self.ty1}*_i*"
l += f" @atom:*_b*_a*_d{self.ty2}*_i*"
Expand All @@ -261,7 +273,8 @@ def bytype_line(self) -> str:

@property
def coeff_line(self) -> str:
l = f"{self._coeff_line_base}{self._duplicate_count_str} {self.v1} {self.v2} {self.v3} {self.v4}"
l = self._prepend_comment_if_needed
l += f"{self._coeff_line_base}{self._duplicate_count_str} {self.v1} {self.v2} {self.v3} {self.v4}"
l += f" # {self.comment} \n"
return l

Expand All @@ -275,16 +288,10 @@ def __init__(self, types: list[str], v1, v2, v3, v4, comment: str):
self.v1, self.v2, self.v3, self.v4 = v1, v2, v3, v4
self.comment = comment

# replacing every X/Y/Z with "*", I don't know if that's the correct approach,
# as if this was the intended behaviour I think in the FF file they would have used
# "*", as they did in the dihedrals sections...
for i, ty in enumerate(self.types):
if ty in ("X", "Y", "Z"):
self.types[i] = "*"

@property
def bytype_line(self) -> str:
l = f"@{type(self).kind}:{self.typename}"
l = self._prepend_comment_if_needed
l += f"@{type(self).kind}:{self.typename}"
l += f" @atom:*_b*_a*_d*_i{self.ty1}*"
l += f" @atom:*_b*_a*_d*_i{self.ty2}*"
l += f" @atom:*_b*_a*_d*_i{self.ty3}*"
Expand All @@ -293,8 +300,9 @@ def bytype_line(self) -> str:

@property
def coeff_line(self) -> str:
l = self._prepend_comment_if_needed
# If using "improper_style cvff", then use:
l = f"{self._coeff_line_base}{self._duplicate_count_str} {float(self.v2)/2:.4f} -1 2 # {self.comment}\n"
l += f"{self._coeff_line_base}{self._duplicate_count_str} {float(self.v2)/2:.4f} -1 2 # {self.comment}\n"
# If using "improper_style harmonic", then use this instead:
# l += f"{self._coeff_line_base}{self._duplicate_count_str} {float(self.v2)} 180.0 # {self.comment}\n"
return l
42 changes: 17 additions & 25 deletions moltemplate/force_fields/oplsaa.lt
Original file line number Diff line number Diff line change
Expand Up @@ -10333,33 +10333,25 @@ OPLSAA {


write_once("In Settings") {
improper_coeff @improper:O~_C~_€€_€€ 10.5000 -1 2 # improper torsion
improper_coeff @improper:€€_CA_€€_€€ 2.5000 -1 2 # improper torsion 9/08 was 2.2
improper_coeff @improper:€€_CM_€€_€€ 15.0000 -1 2 # improper torsion
improper_coeff @improper:€€_N~_€€_€€ 2.5000 -1 2 # improper torsion 9/08 was 2.0
# The next 4 impropers weren't in the 2008 version. They are in the 2023 version
# Unfortunately, they are causing problems, overwriting legitimate impropers.
# For now, I will comment them out.
# Later, I will revisit these -Andrew 2024-12-02
# improper_coeff @improper:CM_CT_CM_CT -4.0000 -1 2 # allenes improper
# improper_coeff @improper:CM_CT_CM_HC -4.0000 -1 2 # allenes improper
# improper_coeff @improper:CM_HC_CM_CT -4.0000 -1 2 # allenes improper
# improper_coeff @improper:CM_HC_CM_HC -4.0000 -1 2 # allenes improper
improper_coeff @improper:CA_€€_€€_€€ 2.5000 -1 2 # improper torsion 9/08 was 2.2
improper_coeff @improper:CM_€€_€€_€€ 15.0000 -1 2 # improper torsion
improper_coeff @improper:N~_€€_€€_€€ 2.5000 -1 2 # improper torsion 9/08 was 2.0
improper_coeff @improper:C~_O~_€€_€€ 10.5000 -1 2 # improper torsion
# UNTRUSTED: improper_coeff @improper:CT_CM_CM_CT -4.0000 -1 2 # allenes improper
# UNTRUSTED: improper_coeff @improper:CT_CM_CM_HC -4.0000 -1 2 # allenes improper
# UNTRUSTED: improper_coeff @improper:HC_CM_CM_CT -4.0000 -1 2 # allenes improper
# UNTRUSTED: improper_coeff @improper:HC_CM_CM_HC -4.0000 -1 2 # allenes improper
} # (end of improper_coeffs)

write_once("Data Impropers By Type (opls_imp.py)") {
@improper:O~_C~_€€_€€ @atom:*_b*_a*_d*_iO~* @atom:*_b*_a*_d*_iC~* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??*
@improper:€€_CA_€€_€€ @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_iCA* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??*
@improper:€€_CM_€€_€€ @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??*
@improper:€€_N~_€€_€€ @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_iN~* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??*
# The next 4 impropers weren't in the 2008 version. They are in the 2023 version
# Unfortunately, they are causing problems, overwriting legitimate impropers.
# For now, I will comment them out.
# Later, I will revisit these -Andrew 2024-12-02
# @improper:CM_CT_CM_CT @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCT* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCT*
# @improper:CM_CT_CM_HC @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCT* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iHC*
# @improper:CM_HC_CM_CT @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iHC* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCT*
# @improper:CM_HC_CM_HC @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iHC* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iHC*
write_once("Data Impropers By Type (cenIsortJKL.py)") {
@improper:CA_€€_€€_€€ @atom:*_b*_a*_d*_iCA* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??*
@improper:CM_€€_€€_€€ @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??*
@improper:N~_€€_€€_€€ @atom:*_b*_a*_d*_iN~* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??*
@improper:C~_O~_€€_€€ @atom:*_b*_a*_d*_iC~* @atom:*_b*_a*_d*_iO~* @atom:*_b*_a*_d*_i??* @atom:*_b*_a*_d*_i??*
# UNTRUSTED: @improper:CT_CM_CM_CT @atom:*_b*_a*_d*_iCT* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCT*
# UNTRUSTED: @improper:CT_CM_CM_HC @atom:*_b*_a*_d*_iCT* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iHC*
# UNTRUSTED: @improper:HC_CM_CM_CT @atom:*_b*_a*_d*_iHC* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCT*
# UNTRUSTED: @improper:HC_CM_CM_HC @atom:*_b*_a*_d*_iHC* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iCM* @atom:*_b*_a*_d*_iHC*
} # (end of impropers by type)


Expand Down
2 changes: 1 addition & 1 deletion moltemplate/force_fields/oplsaa2008.lt
Original file line number Diff line number Diff line change
Expand Up @@ -8207,7 +8207,7 @@ OPLSAA {
# Rules for creating improper interactions according to atom type:
# ImproperTypeName AtomType1 AtomType2 AtomType3 AtomType4
# (* = wildcard)
write_once("Data Impropers By Type (opls_imp.py)") {
write_once("Data Impropers By Type (cenKswapIL.py)") {
@improper:X_X_003_004 @atom:* @atom:* @atom:*_b*_a*_d*_i003* @atom:*_b*_a*_d*_i004*
@improper:X_X_003_052 @atom:* @atom:* @atom:*_b*_a*_d*_i003* @atom:*_b*_a*_d*_i052*
@improper:X_X_024_X @atom:* @atom:* @atom:*_b*_a*_d*_i024* @atom:*
Expand Down
File renamed without changes.

0 comments on commit e56e240

Please sign in to comment.