View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.potential.bonded;
39  
40  import ffx.potential.bonded.AminoAcidUtils.AminoAcid3;
41  import ffx.potential.parameters.ForceField;
42  import ffx.potential.parameters.RelativeSolvationType;
43  
44  import java.util.HashMap;
45  import java.util.Map;
46  import java.util.logging.Logger;
47  
48  import static java.lang.String.format;
49  
50  /**
51   * A relative solvation term for chemical perturbations.
52   *
53   * @author Michael J. Schnieders
54   * @author Jacob M. Litman
55   * @since 1.0
56   */
57  public class RelativeSolvation {
58  
59    private static final Logger logger = Logger.getLogger(RelativeSolvation.class.getName());
60    /** Look-up of non-standard energies. */
61    private final Map<String, Double> nonStdEnergies;
62    /** Solvation library in use. */
63    private final SolvationLibrary solvationLibrary;
64  
65    /**
66     * Constructor for RelativeSolvation.
67     *
68     * @param solvationLibrary a {@link ffx.potential.bonded.RelativeSolvation.SolvationLibrary}
69     *     object.
70     * @param forceField a {@link ffx.potential.parameters.ForceField} object.
71     */
72    public RelativeSolvation(SolvationLibrary solvationLibrary, ForceField forceField) {
73      this.solvationLibrary = solvationLibrary;
74      nonStdEnergies = new HashMap<>();
75      for (RelativeSolvationType rsType : forceField.getRelativeSolvationTypes().values()) {
76        String resName = rsType.getResName();
77        double e = rsType.getSolvEnergy();
78        if (nonStdEnergies.put(resName, e) != null) {
79          logger.warning(format(" Repeat relative solvation for %s", resName));
80        }
81      }
82    }
83  
84    /**
85     * Gets the solvation energy (de-solvation penalty) for a given residue, allowing for sequence
86     * optimization to include an estimate of energy relative to the unfolded state.
87     *
88     * @param residue Residue to check
89     * @param checkZeroes Throws an error if not in solvation energy library
90     * @return Solvation energy
91     * @throws java.lang.IllegalArgumentException if any.
92     * @throws java.lang.IllegalArgumentException if any.
93     */
94    public double getSolvationEnergy(Residue residue, boolean checkZeroes)
95        throws IllegalArgumentException {
96      String resName = "";
97      double energy;
98      Residue theRes =
99          (residue instanceof MultiResidue) ? ((MultiResidue) residue).getActive() : residue;
100     switch (theRes.getResidueType()) {
101       case AA -> {
102         if (theRes instanceof MultiResidue) {
103           resName = ((MultiResidue) theRes).getActive().getName();
104         } else {
105           resName = theRes.getName();
106         }
107         energy = getAASolvationEnergy(theRes);
108       }
109       case NA -> {
110         if (theRes instanceof MultiResidue) {
111           resName = ((MultiResidue) theRes).getActive().getName();
112         } else {
113           resName = theRes.getName();
114         }
115         energy = getNASolvationEnergy(theRes);
116       }
117       default -> energy = 0;
118     }
119     if (checkZeroes && energy == 0) {
120       throw new IllegalArgumentException(
121           format(" Zero de-solvation energy for residue %s: likely not in solvation library.",
122               resName));
123     }
124     return energy;
125   }
126 
127   /** {@inheritDoc} */
128   @Override
129   public String toString() {
130     return "Relative solvation library: " + solvationLibrary.toString();
131   }
132 
133   /**
134    * Returns amino acid solvation energy based on solvation library.
135    *
136    * @param residue a {@link ffx.potential.bonded.Residue} object.
137    * @return Solvation energy
138    */
139   private double getAASolvationEnergy(Residue residue) {
140     return switch (solvationLibrary) {
141       case WOLFENDEN -> getWolfendenSolvationEnergy(residue);
142       case CABANI -> getCabaniSolvationEnergy(residue);
143       case EXPLICIT -> getExplicitSolvationEnergy(residue);
144       case GK -> getGKSolvationEnergy(residue);
145       case MACCALLUM_SPC -> getMacCallumSPCSolvationEnergy(residue);
146       case MACCALLUM_TIP4P -> getMacCallumTIP4PSolvationEnergy(residue);
147       default -> 0;
148     };
149   }
150 
151   /**
152    * Will return relative solvation energies for nucleic acids; currently returns 0.
153    *
154    * @param residue a {@link ffx.potential.bonded.Residue} object.
155    * @return Relative solvation energy
156    */
157   private double getNASolvationEnergy(Residue residue) {
158     return 0;
159   }
160 
161   /**
162    * Will return solvation energies relative to glycine for capped monomers in GK solvent; currently
163    * wraps getExplicitSolvationEnergy.
164    *
165    * @param residue a {@link ffx.potential.bonded.Residue} object.
166    * @return Relative solvation energy
167    */
168   private double getGKSolvationEnergy(Residue residue) {
169     return getExplicitSolvationEnergy(residue);
170   }
171 
172   /**
173    * Will return solvation energies relative to glycine for capped monomers in AMOEBA solvent;
174    * currently approximates this with charging energies in AMOEBA solvent.
175    *
176    * @param residue a {@link ffx.potential.bonded.Residue} object.
177    * @return Relative solvation energy
178    */
179   private double getExplicitSolvationEnergy(Residue residue) {
180     AminoAcid3 name = residue.getAminoAcid3();
181     return switch (name) {
182       case ALA -> 0.58;
183       case CYS -> -0.85;
184       case CYD -> -69.82;
185       case ASP -> -69.45;
186       case ASH -> -4.00;
187       case GLU -> -71.40;
188       case GLH -> -3.61;
189       case PHE -> -1.59;
190       case GLY -> 0.67;
191       case HIS -> -45.36;
192       case HID -> -8.42;
193       case HIE -> -7.53;
194       case ILE -> 0.14;
195       case LYS -> -43.98;
196       case LYD -> +0.35;
197       case MET -> -3.48;
198       case ASN -> -5.89;
199       case PRO -> 7.82;
200       case GLN -> -6.89;
201       case ARG -> -42.57;
202       case SER -> -2.14;
203       case THR -> 0.58;
204       case VAL -> 0.10;
205       case TRP -> -4.64;
206       case TYR -> 1.76;
207       case TYD -> -41.71;
208       case UNK -> nonStdEnergies.getOrDefault(residue.getName().toUpperCase(), 0.0);
209       default -> 0;
210     };
211   }
212 
213   /**
214    * Returns absolute solvation energies for side chain analogs as calculated by MacCallum for OPLS
215    * in TIP4P solvent.
216    *
217    * @param residue a {@link ffx.potential.bonded.Residue} object.
218    * @return Solvation energy
219    */
220   private double getMacCallumTIP4PSolvationEnergy(Residue residue) {
221     AminoAcid3 name = residue.getAminoAcid3();
222     return switch (name) {
223       case ALA -> 9.8;
224       case CYS -> -0.5;
225       case ASP -> -30.5;
226       case GLU -> -19.0;
227       case PHE -> -1.2;
228       case HIS -> -28.0;
229       case ILE -> 12.2;
230       case LYS -> -13.6;
231       case LEU -> 13.7;
232       case MET -> -7.1;
233       case ASN -> -34.5;
234       case GLN -> -31.4;
235       case ARG -> -43.9;
236       case SER -> -20.2;
237       case THR -> -20.3;
238       case VAL -> 12.0;
239       case TRP -> -16.2;
240       case TYR -> -18.8;
241       case UNK -> nonStdEnergies.getOrDefault(residue.getName().toUpperCase(), 0.0);
242       default -> 0;
243     };
244   }
245 
246   /**
247    * Returns absolute solvation energies for side chain analogs as calculated by MacCallum for OPLS
248    * in SPC solvent.
249    *
250    * @param residue a {@link ffx.potential.bonded.Residue} object.
251    * @return Solvation energy
252    */
253   private double getMacCallumSPCSolvationEnergy(Residue residue) {
254     AminoAcid3 name = residue.getAminoAcid3();
255     return switch (name) {
256       case ALA -> 9.3;
257       case CYS -> -1.1;
258       case ASP -> -30.1;
259       case GLU -> -18.8;
260       case PHE -> -1.4;
261       case HIS -> -27.2;
262       case ILE -> 11.9;
263       case LYS -> -8.6;
264       case LEU -> 12.6;
265       case MET -> -5.1;
266       case ASN -> -34.3;
267       case GLN -> -30.8;
268       case ARG -> -46.3;
269       case SER -> -18.5;
270       case THR -> -19.3;
271       case VAL -> 11.3;
272       case TRP -> -15.1;
273       case TYR -> -18.2;
274       case UNK -> nonStdEnergies.getOrDefault(residue.getName().toUpperCase(), 0.0);
275       default -> 0;
276     };
277   }
278 
279   /**
280    * Returns absolute solvation energies for side chain analogs as experimentally measured by Cabani
281    * et al.
282    *
283    * @param residue a {@link ffx.potential.bonded.Residue} object.
284    * @return Solvation energy
285    */
286   private double getCabaniSolvationEnergy(Residue residue) {
287     AminoAcid3 name = residue.getAminoAcid3();
288     switch (name) {
289       case ALA:
290         return 8.4;
291       case CYS:
292         return -5.2;
293       case ASP:
294         return -28.1;
295       case GLU:
296         return -27.1;
297       case PHE:
298         return -3.7;
299       case HIS:
300         return -27.4;
301       case ILE:
302         return 8.7;
303       case LYS:
304         return -15.5;
305       case LEU:
306         return 9.7;
307       case MET:
308         return 9.0;
309       case ASN:
310         return -40.6;
311       case GLN:
312         return -18.7;
313       case ARG:
314         return -30.1;
315       case SER:
316         return -21.4;
317       case THR:
318         return -21.0;
319       case VAL:
320         return 8.2;
321       case TRP:
322         return -12.3;
323       case TYR:
324         return -25.7;
325       case UNK:
326         return nonStdEnergies.getOrDefault(residue.getName().toUpperCase(), 0.0);
327       case GLY:
328       case PRO:
329       default:
330         return 0;
331     }
332   }
333 
334   /**
335    * Returns absolute solvation energies for side chain analogs as experimentally measured by
336    * Wolfenden et al.
337    *
338    * @param residue a {@link ffx.potential.bonded.Residue} object.
339    * @return Solvation energy
340    */
341   private double getWolfendenSolvationEnergy(Residue residue) {
342     AminoAcid3 name = residue.getAminoAcid3();
343     switch (name) {
344       case ALA:
345         return 8.1;
346       case CYS:
347         return -5.1;
348       case ASP:
349         return -27.5;
350       case GLU:
351         return -26.6;
352       case PHE:
353         return -3.1;
354       case HIS:
355         return -42.1;
356       case ILE:
357         return 8.8;
358       case LYS:
359         return -18.0;
360       case LEU:
361         return 9.4;
362       case MET:
363         return -6.1;
364       case ASN:
365         return -39.9;
366       case GLN:
367         return -38.7;
368       case ARG:
369         return -44.8;
370       case SER:
371         return -20.8;
372       case THR:
373         return -20.1;
374       case VAL:
375         return 8.2;
376       case TRP:
377         return -24.3;
378       case TYR:
379         return -25.2;
380       case UNK:
381         return nonStdEnergies.getOrDefault(residue.getName().toUpperCase(), 0.0);
382       case GLY:
383       case PRO:
384       default:
385         return 0; // Not listed.
386     }
387   }
388 
389   /**
390    * Citations: Wolfenden et al: Wolfenden, R., Andersson, L., Cullis, P. M. and Southgate, C. C. B.
391    * (1981) AFFINITIES OF AMINO-ACID SIDE-CHAINS FOR SOLVENT WATER. Biochemistry. 20, 849-855
392    *
393    * <p>Cabani et al: Cabani, S., Gianni, P., Mollica, V. and Lepori, L. (1981) GROUP
394    * CONTRIBUTIONS TO THE THERMODYNAMIC PROPERTIES OF NON-IONIC ORGANIC SOLUTES IN DILUTE
395    * AQUEOUS-SOLUTION. Journal of Solution Chemistry. 10, 563-595
396    *
397    * <p>MacCallum OPLS libraries: Maccallum, J. L. and Tieleman, D. P. (2003) Calculation of the
398    * water-cyclohexane transfer free energies of neutral amino acid side-chain analogs using the OPLS
399    * all-atom force field. Journal of Computational Chemistry. 24, 1930-1935
400    */
401   public enum SolvationLibrary {
402     WOLFENDEN, CABANI, EXPLICIT, GK, MACCALLUM_SPC, MACCALLUM_TIP4P, OPLS_EXPLICIT, OPLS_GK, AUTO, NONE
403   }
404 }