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-2024.
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 static org.apache.commons.math3.util.FastMath.max;
41  
42  import ffx.potential.bonded.AminoAcidUtils.AminoAcid3;
43  import ffx.potential.bonded.NucleicAcidUtils.NucleicAcid3;
44  import ffx.potential.parameters.TitrationUtils;
45  
46  /**
47   * The Rotamer Class usually represents one immutable amino acid Rotamer.
48   * <p>
49   * It is additionally being extended to represent one nucleic acid Rotamer.
50   *
51   * @author Ava M. Lynn
52   * @author Jacob M. Litman
53   * @since 1.0
54   */
55  public class Rotamer {
56  
57    /** Torsions chi 1-4 are used for amino acids and nucleic acids. */
58    public final double chi1;
59    public final double chi2;
60    public final double chi3;
61    public final double chi4;
62    /** Torsions chi 5-7 are only currently used for nucleic acids. */
63    public final double chi5;
64    final double chi6;
65    final double chi7;
66  
67    /**
68     * An array of chi angles for this rotamer.
69     */
70    public final double[] angles;
71    /**
72     * An array of sigmas for each chi angle.
73     */
74    public final double[] sigmas;
75    /**
76     * Number of chi/sigma values.
77     */
78    public final int length;
79    /**
80     * Residue state used to initialize the rotamer.
81     */
82    public ResidueState originalState;
83    /**
84     * Flag to indicate the rotamer was initialized from a Residue state.
85     */
86    public boolean isState;
87    /**
88     * The A.A. name of this residue (or null for a N.A.).
89     */
90    public AminoAcid3 aminoAcid3;
91    /**
92     * The N.A. name of this residue (or null for a A.A.).
93     */
94    public NucleicAcid3 nucleicAcid3;
95    /**
96     * If this flag is set, application of a rotamer requires updating force field parameters.
97     */
98    public boolean isTitrating;
99    /**
100    * The TitrationUtils handles application of rotamer specific force field parameters.
101    */
102   private TitrationUtils titrationUtils = null;
103   private int rotIndex;
104 
105   /**
106    * Constructor for unknown residue types.
107    *
108    * @param values a double.
109    */
110   public Rotamer(double... values) {
111     length = values.length / 2;
112     angles = new double[max(length, 7)];
113     sigmas = new double[max(length, 7)];
114     nucleicAcid3 = null;
115     aminoAcid3 = null;
116     for (int i = 0; i < values.length / 2; i++) {
117       int ii = 2 * i;
118       angles[i] = values[ii];
119       sigmas[i] = values[ii + 1];
120     }
121     chi1 = angles[0];
122     chi2 = angles[1];
123     chi3 = angles[2];
124     chi4 = angles[3];
125     chi5 = angles[4];
126     chi6 = angles[5];
127     chi7 = angles[6];
128     originalState = null;
129     isState = false;
130     isTitrating = false;
131   }
132 
133   /**
134    * Constructor for Rotamer.
135    *
136    * @param aminoAcid3 a {@link AminoAcid3} object.
137    * @param values a double.
138    */
139   public Rotamer(AminoAcid3 aminoAcid3, double... values) {
140     this(values);
141     this.aminoAcid3 = aminoAcid3;
142   }
143 
144   /**
145    * Constructor for Rotamer.
146    *
147    * @param aminoAcid3 a {@link AminoAcid3} object.
148    * @param values a double.
149    */
150   public Rotamer(AminoAcid3 aminoAcid3, int rotIndex, double... values) {
151     this(values);
152     this.aminoAcid3 = aminoAcid3;
153     this.rotIndex = rotIndex;
154   }
155 
156 
157   /**
158    * Constructor for Rotamer.
159    *
160    * @param nucleicAcid3 a {@link NucleicAcid3} object.
161    * @param values a double.
162    */
163   public Rotamer(NucleicAcid3 nucleicAcid3, double... values) {
164     this(values);
165     this.nucleicAcid3 = nucleicAcid3;
166   }
167 
168   /**
169    * Constructor for Rotamer.
170    *
171    * @param aminoAcid3 a {@link AminoAcid3} object.
172    * @param titrationUtils Use to apply rotamer specific force field parameters.
173    * @param values a double.
174    */
175   public Rotamer(AminoAcid3 aminoAcid3, TitrationUtils titrationUtils, double... values) {
176     this(aminoAcid3, values);
177     if (titrationUtils != null) {
178       this.isTitrating = true;
179       this.titrationUtils = titrationUtils;
180     } else {
181       this.isTitrating = false;
182     }
183   }
184 
185   public Rotamer(AminoAcid3 aminoAcid3, TitrationUtils titrationUtils, int rotIndex, double... values) {
186     this(aminoAcid3, values);
187     if (titrationUtils != null) {
188       this.isTitrating = true;
189       this.titrationUtils = titrationUtils;
190       this.rotIndex = rotIndex;
191     } else {
192       this.isTitrating = false;
193     }
194   }
195 
196   /**
197    * Constructor for unknown residue types.
198    *
199    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
200    * @param values a double.
201    */
202   public Rotamer(ResidueState residueState, double... values) {
203     this(values);
204     isState = true;
205     originalState = residueState;
206   }
207 
208   /**
209    * Constructor for unknown residue types.
210    *
211    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
212    * @param values a double.
213    */
214   public Rotamer(ResidueState residueState, TitrationUtils titrationUtils, double... values) {
215     this(residueState, values);
216     if (titrationUtils != null) {
217       this.titrationUtils = titrationUtils;
218       isTitrating = true;
219     }
220   }
221 
222   /**
223    * Constructor for Rotamer.
224    *
225    * @param aminoAcid3 a {@link AminoAcid3} object.
226    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
227    * @param values a double.
228    */
229   public Rotamer(AminoAcid3 aminoAcid3, ResidueState residueState, double... values) {
230     this(residueState, values);
231     this.aminoAcid3 = aminoAcid3;
232   }
233 
234   /**
235    * Constructor for Rotamer.
236    *
237    * @param aminoAcid3 a {@link AminoAcid3} object.
238    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
239    * @param values a double.
240    */
241   public Rotamer(AminoAcid3 aminoAcid3, ResidueState residueState, TitrationUtils titrationUtils,
242       double... values) {
243     this(aminoAcid3, residueState, values);
244     if (titrationUtils != null) {
245       this.titrationUtils = titrationUtils;
246       isTitrating = true;
247     }
248   }
249 
250   /**
251    * Constructor for Rotamer.
252    *
253    * @param nucleicAcid3 a {@link NucleicAcid3} object.
254    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
255    * @param values a double.
256    */
257   public Rotamer(NucleicAcid3 nucleicAcid3, ResidueState residueState, double... values) {
258     this(residueState, values);
259     this.nucleicAcid3 = nucleicAcid3;
260   }
261 
262   /**
263    * Constructor for Rotamer.
264    *
265    * @param nucleicAcid3 a {@link NucleicAcid3} object.
266    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
267    * @param values a double.
268    */
269   public Rotamer(NucleicAcid3 nucleicAcid3, ResidueState residueState, TitrationUtils titrationUtils,
270       double... values) {
271     this(nucleicAcid3, residueState, values);
272     if (titrationUtils != null) {
273       this.titrationUtils = titrationUtils;
274       isTitrating = true;
275     }
276   }
277 
278   /**
279    * Update force field parameters for force field dependent rotamers.
280    *
281    * @param residue Residue to update.
282    */
283   public void updateParameters(Residue residue) {
284     titrationUtils.updateResidueParameters(residue, this);
285   }
286 
287   /**
288    * Factory method to construct an original-coordinates Rotamer from a residue.
289    *
290    * @param residue Residue to construct a default rotamer for.
291    * @return Rotamer based on the coordinates of the residue.
292    */
293   public static Rotamer[] defaultRotamerFactory(Residue residue) {
294     return defaultRotamerFactory(residue, null);
295   }
296 
297   /**
298    * Factory method to construct an original-coordinates Rotamer from a residue.
299    *
300    * @param residue Residue to construct a default rotamer for.
301    * @return Rotamer based on the coordinates of the residue.
302    */
303   public static Rotamer[] defaultRotamerFactory(Residue residue, TitrationUtils titrationUtils) {
304     ResidueState resState = residue.storeState();
305     double[] chi = RotamerLibrary.measureRotamer(residue, false);
306 
307     double[] values = new double[chi.length * 2];
308     for (int i = 0; i < chi.length; i++) {
309       int index = i * 2;
310       values[index] = chi[i];
311       values[index + 1] = 0.0;
312     }
313 
314     switch (residue.getResidueType()) {
315       case AA:
316         // Only one rotamer for non-titrating cases.
317         if (titrationUtils == null) {
318           Rotamer[] rotamers = new Rotamer[1];
319           rotamers[0] = new Rotamer(residue.getAminoAcid3(), resState, titrationUtils, values);
320           return rotamers;
321         }
322         switch (residue.getAminoAcid3()) {
323           case ASH:
324             Rotamer[] rotamers = new Rotamer[2];
325             rotamers[0] = new Rotamer(AminoAcid3.ASP, resState, titrationUtils, values);
326             rotamers[1] = new Rotamer(AminoAcid3.ASH, resState, titrationUtils, values);
327             return rotamers;
328           case GLH:
329             rotamers = new Rotamer[2];
330             rotamers[0] = new Rotamer(AminoAcid3.GLU, resState, titrationUtils, values);
331             rotamers[1] = new Rotamer(AminoAcid3.GLH, resState, titrationUtils, values);
332             return rotamers;
333           case HIS:
334             rotamers = new Rotamer[3];
335             rotamers[0] = new Rotamer(AminoAcid3.HIS, resState, titrationUtils, values);
336             rotamers[1] = new Rotamer(AminoAcid3.HID, resState, titrationUtils, values);
337             rotamers[2] = new Rotamer(AminoAcid3.HIE, resState, titrationUtils, values);
338             return rotamers;
339           case LYS:
340             rotamers = new Rotamer[2];
341             rotamers[0] = new Rotamer(AminoAcid3.LYS, resState, titrationUtils, values);
342             rotamers[1] = new Rotamer(AminoAcid3.LYD, resState, titrationUtils, values);
343             return rotamers;
344           case CYS:
345             rotamers = new Rotamer[2];
346             rotamers[0] = new Rotamer(AminoAcid3.CYS, resState, titrationUtils, values);
347             rotamers[1] = new Rotamer(AminoAcid3.CYD, resState, titrationUtils, values);
348             return rotamers;
349           default:
350             // Null TitrationUtils reference indicates this residue does not support titration.
351             rotamers = new Rotamer[1];
352             rotamers[0] = new Rotamer(residue.getAminoAcid3(), resState, null, values);
353             return rotamers;
354         }
355       case NA:
356         // Null TitrationUtils reference indicates this residue does not support titration.
357         Rotamer[] rotamers = new Rotamer[1];
358         rotamers[0] = new Rotamer(residue.getNucleicAcid3(), resState, null, values);
359         return rotamers;
360       case UNK:
361       default:
362         // Null TitrationUtils reference to indicates this residue does not support titration.
363         rotamers = new Rotamer[1];
364         rotamers[0] = new Rotamer(resState, null, values);
365         return rotamers;
366     }
367   }
368 
369   /**
370    * toAngleString.
371    *
372    * @return a {@link java.lang.String} object.
373    */
374   public String toAngleString() {
375     StringBuilder sb = new StringBuilder();
376     int n = max(4, length);
377     for (int i = 0; i < n; i++) {
378       sb.append(String.format(" %6.1f %4.1f", angles[i], sigmas[i]));
379     }
380     return sb.toString();
381   }
382 
383   /** {@inheritDoc} */
384   @Override
385   public String toString() {
386     StringBuilder sb = new StringBuilder(getName());
387     int n = max(4, length);
388     for (int i = 0; i < n; i++) {
389       sb.append(String.format(" %6.1f %4.1f", angles[i], sigmas[i]));
390     }
391     return sb.toString();
392   }
393 
394   public String getName() {
395     if (aminoAcid3 != null) {
396       return aminoAcid3.toString();
397     } else if (nucleicAcid3 != null) {
398       return nucleicAcid3.toString();
399     } else {
400       return "";
401     }
402   }
403 
404   public int getRotIndex() {return rotIndex;}
405 
406   public double getRotamerPhBias() {
407     return titrationUtils.getRotamerPhBias(aminoAcid3);
408   }
409 
410   public double[] getAngles() {
411     return angles;
412   }
413 
414 }