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 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 
104   /**
105    * Constructor for unknown residue types.
106    *
107    * @param values a double.
108    */
109   public Rotamer(double... values) {
110     length = values.length / 2;
111     angles = new double[max(length, 7)];
112     sigmas = new double[max(length, 7)];
113     nucleicAcid3 = null;
114     aminoAcid3 = null;
115     for (int i = 0; i < values.length / 2; i++) {
116       int ii = 2 * i;
117       angles[i] = values[ii];
118       sigmas[i] = values[ii + 1];
119     }
120     chi1 = angles[0];
121     chi2 = angles[1];
122     chi3 = angles[2];
123     chi4 = angles[3];
124     chi5 = angles[4];
125     chi6 = angles[5];
126     chi7 = angles[6];
127     originalState = null;
128     isState = false;
129     isTitrating = false;
130   }
131 
132   /**
133    * Constructor for Rotamer.
134    *
135    * @param aminoAcid3 a {@link AminoAcid3} object.
136    * @param values a double.
137    */
138   public Rotamer(AminoAcid3 aminoAcid3, double... values) {
139     this(values);
140     this.aminoAcid3 = aminoAcid3;
141   }
142 
143 
144   /**
145    * Constructor for Rotamer.
146    *
147    * @param nucleicAcid3 a {@link NucleicAcid3} object.
148    * @param values a double.
149    */
150   public Rotamer(NucleicAcid3 nucleicAcid3, double... values) {
151     this(values);
152     this.nucleicAcid3 = nucleicAcid3;
153   }
154 
155   /**
156    * Constructor for Rotamer.
157    *
158    * @param aminoAcid3 a {@link AminoAcid3} object.
159    * @param titrationUtils Use to apply rotamer specific force field parameters.
160    * @param values a double.
161    */
162   public Rotamer(AminoAcid3 aminoAcid3, TitrationUtils titrationUtils, double... values) {
163     this(aminoAcid3, values);
164     if (titrationUtils != null) {
165       this.isTitrating = true;
166       this.titrationUtils = titrationUtils;
167     } else {
168       this.isTitrating = false;
169     }
170   }
171 
172   /**
173    * Constructor for unknown residue types.
174    *
175    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
176    * @param values a double.
177    */
178   public Rotamer(ResidueState residueState, double... values) {
179     this(values);
180     isState = true;
181     originalState = residueState;
182   }
183 
184   /**
185    * Constructor for unknown residue types.
186    *
187    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
188    * @param values a double.
189    */
190   public Rotamer(ResidueState residueState, TitrationUtils titrationUtils, double... values) {
191     this(residueState, values);
192     if (titrationUtils != null) {
193       this.titrationUtils = titrationUtils;
194       isTitrating = true;
195     }
196   }
197 
198   /**
199    * Constructor for Rotamer.
200    *
201    * @param aminoAcid3 a {@link AminoAcid3} object.
202    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
203    * @param values a double.
204    */
205   public Rotamer(AminoAcid3 aminoAcid3, ResidueState residueState, double... values) {
206     this(residueState, values);
207     this.aminoAcid3 = aminoAcid3;
208   }
209 
210   /**
211    * Constructor for Rotamer.
212    *
213    * @param aminoAcid3 a {@link AminoAcid3} object.
214    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
215    * @param values a double.
216    */
217   public Rotamer(AminoAcid3 aminoAcid3, ResidueState residueState, TitrationUtils titrationUtils,
218       double... values) {
219     this(aminoAcid3, residueState, values);
220     if (titrationUtils != null) {
221       this.titrationUtils = titrationUtils;
222       isTitrating = true;
223     }
224   }
225 
226   /**
227    * Constructor for Rotamer.
228    *
229    * @param nucleicAcid3 a {@link NucleicAcid3} object.
230    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
231    * @param values a double.
232    */
233   public Rotamer(NucleicAcid3 nucleicAcid3, ResidueState residueState, double... values) {
234     this(residueState, values);
235     this.nucleicAcid3 = nucleicAcid3;
236   }
237 
238   /**
239    * Constructor for Rotamer.
240    *
241    * @param nucleicAcid3 a {@link NucleicAcid3} object.
242    * @param residueState a {@link ffx.potential.bonded.ResidueState} object.
243    * @param values a double.
244    */
245   public Rotamer(NucleicAcid3 nucleicAcid3, ResidueState residueState, TitrationUtils titrationUtils,
246       double... values) {
247     this(nucleicAcid3, residueState, values);
248     if (titrationUtils != null) {
249       this.titrationUtils = titrationUtils;
250       isTitrating = true;
251     }
252   }
253 
254   /**
255    * Update force field parameters for force field dependent rotamers.
256    *
257    * @param residue Residue to update.
258    */
259   public void updateParameters(Residue residue) {
260     titrationUtils.updateResidueParameters(residue, this);
261   }
262 
263   /**
264    * Factory method to construct an original-coordinates Rotamer from a residue.
265    *
266    * @param residue Residue to construct a default rotamer for.
267    * @return Rotamer based on the coordinates of the residue.
268    */
269   public static Rotamer[] defaultRotamerFactory(Residue residue) {
270     return defaultRotamerFactory(residue, null);
271   }
272 
273   /**
274    * Factory method to construct an original-coordinates Rotamer from a residue.
275    *
276    * @param residue Residue to construct a default rotamer for.
277    * @return Rotamer based on the coordinates of the residue.
278    */
279   public static Rotamer[] defaultRotamerFactory(Residue residue, TitrationUtils titrationUtils) {
280     ResidueState resState = residue.storeState();
281     double[] chi = RotamerLibrary.measureRotamer(residue, false);
282 
283     double[] values = new double[chi.length * 2];
284     for (int i = 0; i < chi.length; i++) {
285       int index = i * 2;
286       values[index] = chi[i];
287       values[index + 1] = 0.0;
288     }
289 
290     switch (residue.getResidueType()) {
291       case AA:
292         // Only one rotamer for non-titrating cases.
293         if (titrationUtils == null) {
294           Rotamer[] rotamers = new Rotamer[1];
295           rotamers[0] = new Rotamer(residue.getAminoAcid3(), resState, titrationUtils, values);
296           return rotamers;
297         }
298         switch (residue.getAminoAcid3()) {
299           case ASH:
300             Rotamer[] rotamers = new Rotamer[2];
301             rotamers[0] = new Rotamer(AminoAcid3.ASP, resState, titrationUtils, values);
302             rotamers[1] = new Rotamer(AminoAcid3.ASH, resState, titrationUtils, values);
303             return rotamers;
304           case GLH:
305             rotamers = new Rotamer[2];
306             rotamers[0] = new Rotamer(AminoAcid3.GLU, resState, titrationUtils, values);
307             rotamers[1] = new Rotamer(AminoAcid3.GLH, resState, titrationUtils, values);
308             return rotamers;
309           case HIS:
310             rotamers = new Rotamer[3];
311             rotamers[0] = new Rotamer(AminoAcid3.HIS, resState, titrationUtils, values);
312             rotamers[1] = new Rotamer(AminoAcid3.HID, resState, titrationUtils, values);
313             rotamers[2] = new Rotamer(AminoAcid3.HIE, resState, titrationUtils, values);
314             return rotamers;
315           case LYS:
316             rotamers = new Rotamer[2];
317             rotamers[0] = new Rotamer(AminoAcid3.LYS, resState, titrationUtils, values);
318             rotamers[1] = new Rotamer(AminoAcid3.LYD, resState, titrationUtils, values);
319             return rotamers;
320           case CYS:
321             rotamers = new Rotamer[2];
322             rotamers[0] = new Rotamer(AminoAcid3.CYS, resState, titrationUtils, values);
323             rotamers[1] = new Rotamer(AminoAcid3.CYD, resState, titrationUtils, values);
324             return rotamers;
325           default:
326             // Null TitrationUtils reference indicates this residue does not support titration.
327             rotamers = new Rotamer[1];
328             rotamers[0] = new Rotamer(residue.getAminoAcid3(), resState, null, values);
329             return rotamers;
330         }
331       case NA:
332         // Null TitrationUtils reference indicates this residue does not support titration.
333         Rotamer[] rotamers = new Rotamer[1];
334         rotamers[0] = new Rotamer(residue.getNucleicAcid3(), resState, null, values);
335         return rotamers;
336       case UNK:
337       default:
338         // Null TitrationUtils reference to indicates this residue does not support titration.
339         rotamers = new Rotamer[1];
340         rotamers[0] = new Rotamer(resState, null, values);
341         return rotamers;
342     }
343   }
344 
345   /**
346    * toAngleString.
347    *
348    * @return a {@link java.lang.String} object.
349    */
350   public String toAngleString() {
351     StringBuilder sb = new StringBuilder();
352     int n = max(4, length);
353     for (int i = 0; i < n; i++) {
354       sb.append(String.format(" %6.1f %4.1f", angles[i], sigmas[i]));
355     }
356     return sb.toString();
357   }
358 
359   /** {@inheritDoc} */
360   @Override
361   public String toString() {
362     StringBuilder sb = new StringBuilder(getName());
363     int n = max(4, length);
364     for (int i = 0; i < n; i++) {
365       sb.append(String.format(" %6.1f %4.1f", angles[i], sigmas[i]));
366     }
367     return sb.toString();
368   }
369 
370   public String getName() {
371     if (aminoAcid3 != null) {
372       return aminoAcid3.toString();
373     } else if (nucleicAcid3 != null) {
374       return nucleicAcid3.toString();
375     } else {
376       return "";
377     }
378   }
379 
380   public double getRotamerPhBias() {
381     return titrationUtils.getRotamerPhBias(aminoAcid3);
382   }
383 
384   public double[] getAngles() {
385     return angles;
386   }
387 
388 }