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-2021.
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 ffx.numerics.math.ScalarMath.mod;
41  import static ffx.potential.bonded.BondedUtils.determineIntxyz;
42  import static ffx.potential.bonded.BondedUtils.intxyz;
43  import static java.lang.String.format;
44  
45  import ffx.potential.MolecularAssembly;
46  import ffx.potential.bonded.AminoAcidUtils.AminoAcid3;
47  import ffx.potential.bonded.NucleicAcidUtils.NucleicAcid3;
48  import ffx.potential.bonded.Residue.ResidueType;
49  import ffx.potential.parameters.AngleType;
50  import ffx.potential.parameters.TitrationUtils;
51  import java.io.BufferedReader;
52  import java.io.File;
53  import java.io.FileReader;
54  import java.io.IOException;
55  import java.util.ArrayList;
56  import java.util.Arrays;
57  import java.util.Collections;
58  import java.util.HashMap;
59  import java.util.List;
60  import java.util.Map;
61  import java.util.Optional;
62  import java.util.logging.Level;
63  import java.util.logging.Logger;
64  import org.apache.commons.math3.util.FastMath;
65  
66  /**
67   * The Rotamer Library Class manages a library of side-chain Rotamers for amino acids, and a library
68   * of backbone Rotamers for nucleic acids.
69   *
70   * @author Ava M. Lynn
71   * @author Shibo Gao
72   * @author Jacob M. Litman
73   * @since 1.0
74   */
75  public class RotamerLibrary {
76  
77    private static final Logger logger = Logger.getLogger(RotamerLibrary.class.getName());
78    /**
79     * Number of amino acid residues types currently recognized, although there are not rotamer
80     * libraries for each yet.
81     */
82    private static final int numberOfAminoAcids = AminoAcidUtils.AminoAcid3.values().length;
83    /**
84     * Number of nucleic acid residues types currently recognized, although there are not rotamer
85     * libraries for each yet.
86     */
87    private static final int numberOfNucleicAcids = NucleicAcidUtils.NucleicAcid3.values().length;
88  
89    private static final ProteinLibrary DEFAULT_PROTEIN_LIB = ProteinLibrary.Richardson;
90    private static final NucleicAcidLibrary DEFAULT_NA_LIB = NucleicAcidLibrary.RICHARDSON;
91    private static final Map<String, NonstandardRotLibrary> nonstdRotCache = new HashMap<>();
92    private static final RotamerLibrary defaultRotamerLibrary =
93        new RotamerLibrary(ProteinLibrary.PonderAndRichards, false);
94    private static final boolean useIdealRingGeometries =
95        Boolean.parseBoolean(System.getProperty("useIdealRingGeo", "true"));
96    private static final Map<AminoAcid3, Map<String, Double>> idealAngleGeometries;
97  
98    static {
99      idealAngleGeometries = Map.of(
100         AminoAcid3.PHE,
101         Map.of("CD1-CG-CB", 120.3, "CD2-CG-CB", 120.3, "CE1-CD1-CG", 120.3, "CE2-CD2-CG", 120.3,
102             "CZ-CE1-CD1", 120.0, "CZ-CE2-CD2", 120.0),
103         AminoAcid3.TYR,
104         Map.of("CD1-CG-CB", 120.3, "CD2-CG-CB", 120.3, "CE1-CD1-CG", 120.3, "CE2-CD2-CG", 120.3,
105             "CZ-CE1-CD1", 120.0, "CZ-CE2-CD2", 120.0),
106         AminoAcid3.TYD,
107         Map.of("CD1-CG-CB", 120.5, "CD2-CG-CB", 120.5, "CE1-CD1-CG", 120.4, "CE2-CD2-CG", 120.4,
108             "CZ-CE1-CD1", 120.8, "CZ-CE2-CD2", 120.8),
109         AminoAcid3.HIS,
110         Map.of("ND1-CG-CB", 122.1, "CD2-CG-CB", 131.0, "CD2-CG-ND1", 106.8, "CE1-ND1-CG", 109.5,
111             "NE2-CD2-CG", 107.1),
112         AminoAcid3.HID,
113         Map.of("ND1-CG-CB", 123.5, "CD2-CG-CB", 132.3, "CD2-CG-ND1", 104.2, "CE1-ND1-CG", 108.8,
114             "NE2-CD2-CG", 111.2),
115         AminoAcid3.HIE,
116         Map.of("ND1-CG-CB", 120.2, "CD2-CG-CB", 129.1, "CD2-CG-ND1", 110.7, "CE1-ND1-CG", 105.1,
117             "NE2-CD2-CG", 104.6),
118         AminoAcid3.TRP,
119         Map.of("CD1-CG-CB", 126.4, "CD2-CG-CB", 126.5, "CD2-CG-CD1", 107.1, "NE1-CD1-CG", 106.9,
120             "CE2-NE1-CD1", 109.4, "CE3-CD2-CE2", 121.6, "CZ2-CE2-CD2", 123.5, "CZ3-CE3-CD2", 116.7,
121             "CH2-CZ2-CE2", 116.2));
122   }
123 
124   /**
125    * The first time rotamers are requested for an amino acid type, they are instantiated into an
126    * array, which is stored in the cache. Subsequently the reference is simply returned.
127    */
128   private final Rotamer[][] aminoAcidRotamerCache = new Rotamer[numberOfAminoAcids][];
129   /**
130    * The first time rotamers are requested for a nucleic acid type, they are instantiated into an
131    * array, which is stored in the cache. Subsequently the reference is simply returned.
132    */
133   private final Rotamer[][] nucleicAcidRotamerCache = new Rotamer[numberOfNucleicAcids][];
134   /** The idealized amino acid rotamer library in use. Defaults to the Richardson library. */
135   private final ProteinLibrary proteinLibrary;
136   /**
137    * The idealized nucleic acid rotamer library in use. Defaults to the Richardson library as there's
138    * no other library.
139    */
140   private final NucleicAcidLibrary nucleicAcidLibrary;
141   /**
142    * Use the original coordinates as an additional rotamer.
143    */
144   private boolean useOrigCoordsRotamer;
145 
146   /**
147    * Constructor for RotamerLibrary.
148    *
149    * @param origCoords Whether to use original-coordinates rotamers.
150    */
151   public RotamerLibrary(boolean origCoords) {
152     this(DEFAULT_PROTEIN_LIB, DEFAULT_NA_LIB, origCoords);
153   }
154 
155   /**
156    * Constructor for RotamerLibrary.
157    *
158    * @param protLibrary A {@link ffx.potential.bonded.RotamerLibrary.ProteinLibrary} to use as
159    *     the idealized amino acid rotamer library.
160    * @param origCoords Whether to use original-coordinates rotamers.
161    */
162   public RotamerLibrary(ProteinLibrary protLibrary, boolean origCoords) {
163     this(protLibrary, DEFAULT_NA_LIB, origCoords);
164   }
165 
166   /**
167    * Constructor for RotamerLibrary.
168    *
169    * @param naLibrary A {@link ffx.potential.bonded.RotamerLibrary.NucleicAcidLibrary} to use as
170    *     the idealized nucleic acid rotamer library.
171    * @param origCoords Whether to use original-coordinates rotamers.
172    */
173   public RotamerLibrary(NucleicAcidLibrary naLibrary, boolean origCoords) {
174     this(DEFAULT_PROTEIN_LIB, naLibrary, origCoords);
175   }
176 
177   /**
178    * Constructor for RotamerLibrary.
179    *
180    * @param protLibrary A {@link ffx.potential.bonded.RotamerLibrary.ProteinLibrary} to use as
181    *     the idealized amino acid rotamer library.
182    * @param naLibrary A {@link ffx.potential.bonded.RotamerLibrary.NucleicAcidLibrary} to use as
183    *     the idealized nucleic acid rotamer library.
184    * @param origCoords Whether to use original-coordinates rotamers.
185    */
186   public RotamerLibrary(
187       ProteinLibrary protLibrary, NucleicAcidLibrary naLibrary, boolean origCoords) {
188     proteinLibrary = protLibrary;
189     nucleicAcidLibrary = naLibrary;
190     useOrigCoordsRotamer = origCoords;
191   }
192 
193   /**
194    * addRotPatch.
195    *
196    * @param rotFileName a {@link java.lang.String} object.
197    * @return a boolean.
198    */
199   public static boolean addRotPatch(String rotFileName) {
200     File rotPatchFile = new File(rotFileName);
201     if (rotPatchFile.exists() && rotPatchFile.canRead()) {
202       return addRotPatch(new File(rotFileName));
203     }
204     return false;
205   }
206 
207   /**
208    * Applies a Rotamer to a Residue by calling applyAARotamer or applyNARotamer.
209    *
210    * @param residue the Residue whose side-chain will be moved.
211    * @param rotamer the Rotamer defining the move.
212    */
213   public static void applyRotamer(Residue residue, Rotamer rotamer) {
214     applyRotamer(residue, rotamer, false);
215   }
216 
217   /**
218    * Version of applyRotamer which allows for chain context-independent drawing of nucleic acid
219    * Rotamers. Solely used in saveRotamers at this point, although it may be useful for debugging.
220    *
221    * @param residue the Residue to be moved.
222    * @param rotamer Rotamer to be applied.
223    * @param independent Whether to draw Rotamer independent of chain context.
224    */
225   public static void applyRotamer(Residue residue, Rotamer rotamer, boolean independent) {
226     residue.setRotamer(rotamer);
227 
228     /*
229      If the rotamer represents a titration state, update force field parameters for the
230      side-chain atoms of the residue.
231 
232      This is done before applying the rotamer, so that the conformation is based on the appropriate
233      equilibrium bond and angle values for the titration state of the rotamer.
234      */
235     if (rotamer.isTitrating) {
236       rotamer.updateParameters(residue);
237     }
238 
239     if (rotamer.isState) {
240       applyState(residue, rotamer);
241     } else {
242       switch (residue.getResidueType()) {
243         case AA:
244           applyAARotamer(residue, rotamer);
245           break;
246         case NA:
247           applyNARotamer(residue, rotamer, independent);
248           break;
249         default:
250           break;
251       }
252     }
253 
254   }
255 
256   /**
257    * If place is true, builds C2', C3', and O3' based on delta(i) and returns an empty double[]; if
258    * place is false, returns a double[] filled with the coordinates at which O3' would be placed by
259    * the specified pucker.
260    *
261    * <p>Presently uses default locations for C1', O4', and C4' to build these atoms.
262    *
263    * @param residue Nucleic acid Residue to which the pucker is to bea applied
264    * @param pucker An int specifying pucker (1=North, 2=South).
265    * @param isDeoxy Boolean
266    * @param place Flag for usage case.
267    * @return A double[] with O3' coordinates (place=false), or null (place=true).
268    */
269   public static double[] applySugarPucker(
270       Residue residue, NucleicSugarPucker pucker, boolean isDeoxy, boolean place) {
271     // Torsions from http://ndb-mirror-2.rutgers.edu/ndbmodule/archives/proj/valence/table6.html
272     // SP is short for Sugar Pucker (torsion).
273     final double C2_SP_SOUTH_RNA = 24.2;
274     final double C3_SP_SOUTH_RNA = 357.7;
275     final double O3_SP_SOUTH_RNA = 268.1;
276     final double C2_SP_NORTH_RNA = 324.7;
277     final double C3_SP_NORTH_RNA = 20.4;
278     final double O3_SP_NORTH_RNA = 201.8;
279 
280     final double C2_SP_SOUTH_DNA = 22.6;
281     final double C3_SP_SOUTH_DNA = 357.7;
282     final double O3_SP_SOUTH_DNA = 265.8;
283     final double C2_SP_NORTH_DNA = 327.7;
284     final double C3_SP_NORTH_DNA = 16.4;
285     final double O3_SP_NORTH_DNA = 205.4;
286 
287     // Ret will only be filled if place is false.
288     double[] ret = new double[3];
289 
290     // Constituents of the sugar
291     Atom C1s = (Atom) residue.getAtomNode("C1'");
292     // C2' will only be used if place is true.
293     Atom C3s = (Atom) residue.getAtomNode("C3'");
294     Atom O4s = (Atom) residue.getAtomNode("O4'");
295     Atom C4s = (Atom) residue.getAtomNode("C4'");
296     Atom O3s = (Atom) residue.getAtomNode("O3'");
297 
298     // Bonds and angles necessary to draw C3' and O3'.
299     Bond C3s_C4s = C4s.getBond(C3s);
300     double dC3s_C4s = C3s_C4s.bondType.distance;
301     Angle C3s_C4s_O4s = O4s.getAngle(C4s, C3s);
302     double dC3s_C4s_O4s = C3s_C4s_O4s.angleType.angle[C3s_C4s_O4s.nh];
303 
304     Bond C3s_O3s = C3s.getBond(O3s);
305     double dC3s_O3s = C3s_O3s.bondType.distance;
306     Angle C4s_C3s_O3s = C4s.getAngle(C3s, O3s);
307     double dC4s_C3s_O3s = C4s_C3s_O3s.angleType.angle[C4s_C3s_O3s.nh];
308 
309     /*
310      * If place is true, place C3', C2', and O3'. Else, determine the
311      * coordinates of O3' based on the invariant atoms.
312      *
313      * If deoxy, a different set of sugar pucker torsions is
314      * applied.
315      *
316      * Then, if a North pucker (delta (i) is in the range of 78-90),
317      * apply Cx_SP_NORTH torsion to place C3 and C2.  Else,
318      * assume a South pucker (delta is between 140 and 152).
319      *
320      * Then, use O3_SP_NORTH or SOUTH to place O3.
321      */
322     if (place) {
323       Atom C2s = (Atom) residue.getAtomNode("C2'");
324       Bond C3s_C2s = C3s.getBond(C2s);
325       double dC3s_C2s = C3s_C2s.bondType.distance;
326       Angle C4s_C3s_C2s = C4s.getAngle(C3s, C2s);
327       double dC4s_C3s_C2s = C4s_C3s_C2s.angleType.angle[C4s_C3s_C2s.nh];
328 
329       if (isDeoxy) {
330         if (pucker == NucleicSugarPucker.C3_ENDO) {
331           intxyz(C3s, C4s, dC3s_C4s, O4s, dC3s_C4s_O4s, C1s, C3_SP_NORTH_DNA, 0);
332           intxyz(C2s, C3s, dC3s_C2s, C4s, dC4s_C3s_C2s, O4s, C2_SP_NORTH_DNA, 0);
333           intxyz(O3s, C3s, dC3s_O3s, C4s, dC4s_C3s_O3s, O4s, O3_SP_NORTH_DNA, 0);
334         } // TODO: else-if for 3'-exo configuration (DNA only)
335         else {
336           intxyz(C3s, C4s, dC3s_C4s, O4s, dC3s_C4s_O4s, C1s, C3_SP_SOUTH_DNA, 0);
337           intxyz(C2s, C3s, dC3s_C2s, C4s, dC4s_C3s_C2s, O4s, C2_SP_SOUTH_DNA, 0);
338           intxyz(O3s, C3s, dC3s_O3s, C4s, dC4s_C3s_O3s, O4s, O3_SP_SOUTH_DNA, 0);
339         }
340       } else {
341         if (pucker == NucleicSugarPucker.C3_ENDO) {
342           intxyz(C3s, C4s, dC3s_C4s, O4s, dC3s_C4s_O4s, C1s, C3_SP_NORTH_RNA, 0);
343           intxyz(C2s, C3s, dC3s_C2s, C4s, dC4s_C3s_C2s, O4s, C2_SP_NORTH_RNA, 0);
344           intxyz(O3s, C3s, dC3s_O3s, C4s, dC4s_C3s_O3s, O4s, O3_SP_NORTH_RNA, 0);
345         } else {
346           intxyz(C3s, C4s, dC3s_C4s, O4s, dC3s_C4s_O4s, C1s, C3_SP_SOUTH_RNA, 0);
347           intxyz(C2s, C3s, dC3s_C2s, C4s, dC4s_C3s_C2s, O4s, C2_SP_SOUTH_RNA, 0);
348           intxyz(O3s, C3s, dC3s_O3s, C4s, dC4s_C3s_O3s, O4s, O3_SP_SOUTH_RNA, 0);
349         }
350       }
351     } else {
352       double[] C1sXYZ = new double[3];
353       double[] C3sXYZ;
354       double[] O4sXYZ = new double[3];
355       double[] C4sXYZ = new double[3];
356       C1s.getXYZ(C1sXYZ);
357       O4s.getXYZ(O4sXYZ);
358       C4s.getXYZ(C4sXYZ);
359 
360       // O3s coordinates will be filled into ret.
361       if (isDeoxy) {
362         if (pucker == NucleicSugarPucker.C3_ENDO) {
363           C3sXYZ =
364               determineIntxyz(C4sXYZ, dC3s_C4s, O4sXYZ, dC3s_C4s_O4s, C1sXYZ, C3_SP_NORTH_DNA, 0);
365           ret = determineIntxyz(C3sXYZ, dC3s_O3s, C4sXYZ, dC4s_C3s_O3s, O4sXYZ, O3_SP_NORTH_DNA, 0);
366         } // TODO: else-if for 3'-exo configuration (DNA only)
367         else {
368           C3sXYZ =
369               determineIntxyz(C4sXYZ, dC3s_C4s, O4sXYZ, dC3s_C4s_O4s, C1sXYZ, C3_SP_SOUTH_DNA, 0);
370           ret = determineIntxyz(C3sXYZ, dC3s_O3s, C4sXYZ, dC4s_C3s_O3s, O4sXYZ, O3_SP_SOUTH_DNA, 0);
371         }
372       } else {
373         if (pucker == NucleicSugarPucker.C3_ENDO) {
374           C3sXYZ =
375               determineIntxyz(C4sXYZ, dC3s_C4s, O4sXYZ, dC3s_C4s_O4s, C1sXYZ, C3_SP_NORTH_RNA, 0);
376           ret = determineIntxyz(C3sXYZ, dC3s_O3s, C4sXYZ, dC4s_C3s_O3s, O4sXYZ, O3_SP_NORTH_RNA, 0);
377         } else {
378           C3sXYZ =
379               determineIntxyz(C4sXYZ, dC3s_C4s, O4sXYZ, dC3s_C4s_O4s, C1sXYZ, C3_SP_SOUTH_RNA, 0);
380           ret = determineIntxyz(C3sXYZ, dC3s_O3s, C4sXYZ, dC4s_C3s_O3s, O4sXYZ, O3_SP_SOUTH_RNA, 0);
381         }
382       }
383     }
384     return ret;
385   }
386 
387   /**
388    * getDefaultLibrary.
389    *
390    * @return a {@link ffx.potential.bonded.RotamerLibrary} object.
391    */
392   public static RotamerLibrary getDefaultLibrary() {
393     return defaultRotamerLibrary;
394   }
395 
396   /**
397    * Initializes default coordinates (presently PDB coordinates) for key atoms in all nucleic acid
398    * Residues. This is necessary to preserve rotamer independence while still adjusting rotamers to
399    * correctly meet prior residues; C4', O4', and C1' are used to build the rest of the nucleic acid
400    * base, but are moved with each Rotamer to take part of the strain of correctly meeting O3' of
401    * residue i-1.
402    *
403    * <p>It also initializes the location of O3' in both North and South puckers; while in theory
404    * this could be recalculated each time based off of C4', O4', and C1', it is easier to just store
405    * these two locations and call them when needed.
406    *
407    * <p>This MUST be called before any applyRotamer calls are made, else invalid coordinates will be
408    * stored.
409    *
410    * @param polymers the Polymer array to examine.
411    */
412   public static void initializeDefaultAtomicCoordinates(Polymer[] polymers) {
413     for (Polymer polymer : polymers) {
414       List<Residue> current = polymer.getResidues();
415       for (Residue residuej : current) {
416         if (residuej.getResidueType() == ResidueType.NA) {
417           residuej.initializeDefaultAtomicCoordinates();
418         }
419       }
420     }
421   }
422 
423   /**
424    * Measures the torsions of an amino acid Residue's current configuration.
425    *
426    * @param residue To be measured.
427    * @param chi Array to be filled with torsion values.
428    * @param print Verbosity flag.
429    * @return The number of rotamers this Residue has.
430    */
431   public static int measureAARotamer(Residue residue, double[] chi, boolean print) {
432     if (residue instanceof MultiResidue) {
433       residue = ((MultiResidue) residue).getActive();
434     }
435     AminoAcid3 name = residue.getAminoAcid3();
436     switch (name) {
437       case VAL: {
438         Atom N = (Atom) residue.getAtomNode("N");
439         Atom CA = (Atom) residue.getAtomNode("CA");
440         Atom CB = (Atom) residue.getAtomNode("CB");
441         Atom CG1 = (Atom) residue.getAtomNode("CG1");
442         for (Torsion torsion : residue.getTorsionList()) {
443           if (torsion.compare(N, CA, CB, CG1)) {
444             chi[0] = torsion.measure();
445             if (print) {
446               logger.info(torsion.toString());
447             }
448             break;
449           }
450         }
451         return 1;
452       }
453       case LEU: {
454         Atom N = (Atom) residue.getAtomNode("N");
455         Atom CA = (Atom) residue.getAtomNode("CA");
456         Atom CB = (Atom) residue.getAtomNode("CB");
457         Atom CG = (Atom) residue.getAtomNode("CG");
458         Atom CD1 = (Atom) residue.getAtomNode("CD1");
459         for (Torsion torsion : residue.getTorsionList()) {
460           if (torsion.compare(N, CA, CB, CG)) {
461             chi[0] = torsion.measure();
462             if (print) {
463               logger.info(torsion.toString());
464             }
465           }
466           if (torsion.compare(CA, CB, CG, CD1)) {
467             chi[1] = torsion.measure();
468             if (print) {
469               logger.info(torsion.toString());
470             }
471           }
472         }
473         return 2;
474       }
475       case ILE: {
476         Atom N = (Atom) residue.getAtomNode("N");
477         Atom CA = (Atom) residue.getAtomNode("CA");
478         Atom CB = (Atom) residue.getAtomNode("CB");
479         Atom CD1 = (Atom) residue.getAtomNode("CD1");
480         Atom CG1 = (Atom) residue.getAtomNode("CG1");
481         for (Torsion torsion : residue.getTorsionList()) {
482           if (torsion.compare(N, CA, CB, CG1)) {
483             chi[0] = torsion.measure();
484             if (print) {
485               logger.info(torsion.toString());
486             }
487           }
488           if (torsion.compare(CA, CB, CG1, CD1)) {
489             chi[1] = torsion.measure();
490             if (print) {
491               logger.info(torsion.toString());
492             }
493           }
494         }
495         return 2;
496       }
497       case SER: {
498         Atom N = (Atom) residue.getAtomNode("N");
499         Atom CA = (Atom) residue.getAtomNode("CA");
500         Atom CB = (Atom) residue.getAtomNode("CB");
501         Atom OG = (Atom) residue.getAtomNode("OG");
502         Atom HG = (Atom) residue.getAtomNode("HG");
503         for (Torsion torsion : residue.getTorsionList()) {
504           if (torsion.compare(N, CA, CB, OG)) {
505             chi[0] = torsion.measure();
506             if (print) {
507               logger.info(torsion.toString());
508             }
509           }
510           if (torsion.compare(CA, CB, OG, HG)) {
511             chi[1] = torsion.measure();
512             if (Double.isNaN(chi[1])) {
513               chi[1] = 180.0; // Possible numeric instability?
514             }
515             if (print) {
516               logger.info(torsion.toString());
517             }
518           }
519         }
520         return 2;
521       }
522       case THR: {
523         Atom N = (Atom) residue.getAtomNode("N");
524         Atom CA = (Atom) residue.getAtomNode("CA");
525         Atom CB = (Atom) residue.getAtomNode("CB");
526         Atom OG1 = (Atom) residue.getAtomNode("OG1");
527         Atom HG1 = (Atom) residue.getAtomNode("HG1");
528         for (Torsion torsion : residue.getTorsionList()) {
529           if (torsion.compare(N, CA, CB, OG1)) {
530             chi[0] = torsion.measure();
531             if (print) {
532               logger.info(torsion.toString());
533             }
534           }
535           if (torsion.compare(CA, CB, OG1, HG1)) {
536             chi[1] = torsion.measure();
537             if (Double.isNaN(chi[1])) {
538               chi[1] = 180.0; // Possible numeric instability?
539             }
540             if (print) {
541               logger.info(torsion.toString());
542             }
543           }
544         }
545         return 2;
546       }
547       case CYS:
548       case CYX:
549       case CYD: {
550         Atom N = (Atom) residue.getAtomNode("N");
551         Atom CA = (Atom) residue.getAtomNode("CA");
552         Atom CB = (Atom) residue.getAtomNode("CB");
553         Atom SG = (Atom) residue.getAtomNode("SG");
554         for (Torsion torsion : residue.getTorsionList()) {
555           if (torsion.compare(N, CA, CB, SG)) {
556             chi[0] = torsion.measure();
557             if (print) {
558               logger.info(torsion.toString());
559             }
560             break;
561           }
562         }
563         return 1;
564       }
565       case PHE: {
566         Atom N = (Atom) residue.getAtomNode("N");
567         Atom CA = (Atom) residue.getAtomNode("CA");
568         Atom CB = (Atom) residue.getAtomNode("CB");
569         Atom CG = (Atom) residue.getAtomNode("CG");
570         for (Torsion torsion : residue.getTorsionList()) {
571           if (torsion.compare(N, CA, CB, CG)) {
572             chi[0] = torsion.measure();
573             if (print) {
574               logger.info(torsion.toString());
575             }
576             break;
577           }
578         }
579         return 1;
580       }
581       case PRO: {
582         Atom N = (Atom) residue.getAtomNode("N");
583         Atom CA = (Atom) residue.getAtomNode("CA");
584         Atom CB = (Atom) residue.getAtomNode("CB");
585         Atom CD = (Atom) residue.getAtomNode("CD");
586         Atom CG = (Atom) residue.getAtomNode("CG");
587         for (Torsion torsion : residue.getTorsionList()) {
588           if (torsion.compare(N, CA, CB, CG)) {
589             chi[0] = torsion.measure();
590             if (print) {
591               logger.info(torsion.toString());
592             }
593           }
594           if (torsion.compare(CA, CB, CG, CD)) {
595             chi[1] = torsion.measure();
596             if (print) {
597               logger.info(torsion.toString());
598             }
599           }
600         }
601         return 2;
602       }
603       case TYR: {
604         Atom N = (Atom) residue.getAtomNode("N");
605         Atom CA = (Atom) residue.getAtomNode("CA");
606         Atom CB = (Atom) residue.getAtomNode("CB");
607         Atom CD1 = (Atom) residue.getAtomNode("CD1");
608         Atom CE2 = (Atom) residue.getAtomNode("CE2");
609         Atom CG = (Atom) residue.getAtomNode("CG");
610         Atom CZ = (Atom) residue.getAtomNode("CZ");
611         Atom OH = (Atom) residue.getAtomNode("OH");
612         Atom HH = (Atom) residue.getAtomNode("HH");
613         for (Torsion torsion : residue.getTorsionList()) {
614           if (torsion.compare(N, CA, CB, CG)) {
615             chi[0] = torsion.measure();
616             if (print) {
617               logger.info(torsion.toString());
618             }
619           }
620           if (torsion.compare(CA, CB, CG, CD1)) {
621             chi[1] = torsion.measure();
622             if (print) {
623               logger.info(torsion.toString());
624             }
625           }
626           if (torsion.compare(CE2, CZ, OH, HH)) {
627             chi[2] = torsion.measure();
628             if (Double.isNaN(chi[2])) {
629               chi[2] = 180.0; // Possible numeric instability?
630             }
631             if (print) {
632               logger.info(torsion.toString());
633             }
634           }
635         }
636         return 3;
637       }
638       case TYD:
639       case TRP: {
640         Atom N = (Atom) residue.getAtomNode("N");
641         Atom CA = (Atom) residue.getAtomNode("CA");
642         Atom CB = (Atom) residue.getAtomNode("CB");
643         Atom CD1 = (Atom) residue.getAtomNode("CD1");
644         Atom CG = (Atom) residue.getAtomNode("CG");
645         for (Torsion torsion : residue.getTorsionList()) {
646           if (torsion.compare(N, CA, CB, CG)) {
647             chi[0] = torsion.measure();
648             if (print) {
649               logger.info(torsion.toString());
650             }
651           }
652           if (torsion.compare(CA, CB, CG, CD1)) {
653             chi[1] = torsion.measure();
654             if (print) {
655               logger.info(torsion.toString());
656             }
657           }
658         }
659         return 2;
660       }
661       case HIS:
662       case HIE:
663       case HID: {
664         Atom N = (Atom) residue.getAtomNode("N");
665         Atom CA = (Atom) residue.getAtomNode("CA");
666         Atom CB = (Atom) residue.getAtomNode("CB");
667         Atom CG = (Atom) residue.getAtomNode("CG");
668         Atom ND1 = (Atom) residue.getAtomNode("ND1");
669         for (Torsion torsion : residue.getTorsionList()) {
670           if (torsion.compare(N, CA, CB, CG)) {
671             chi[0] = torsion.measure();
672             if (print) {
673               logger.info(torsion.toString());
674             }
675           }
676           if (torsion.compare(CA, CB, CG, ND1)) {
677             chi[1] = torsion.measure();
678             if (print) {
679               logger.info(torsion.toString());
680             }
681           }
682         }
683         return 2;
684       }
685       case ASP: {
686         Atom N = (Atom) residue.getAtomNode("N");
687         Atom CA = (Atom) residue.getAtomNode("CA");
688         Atom CB = (Atom) residue.getAtomNode("CB");
689         Atom CG = (Atom) residue.getAtomNode("CG");
690         for (Torsion torsion : residue.getTorsionList()) {
691           if (torsion.compare(N, CA, CB, CG)) {
692             chi[0] = torsion.measure();
693             if (print) {
694               logger.info(torsion.toString());
695             }
696             break;
697           }
698         }
699         return 1;
700       }
701       case ASH:
702       case ASN: {
703         Atom N = (Atom) residue.getAtomNode("N");
704         Atom CA = (Atom) residue.getAtomNode("CA");
705         Atom CB = (Atom) residue.getAtomNode("CB");
706         Atom CG = (Atom) residue.getAtomNode("CG");
707         Atom OD1 = (Atom) residue.getAtomNode("OD1");
708         for (Torsion torsion : residue.getTorsionList()) {
709           if (torsion.compare(N, CA, CB, CG)) {
710             chi[0] = torsion.measure();
711             if (print) {
712               logger.info(torsion.toString());
713             }
714           }
715           if (torsion.compare(CA, CB, CG, OD1)) {
716             chi[1] = torsion.measure();
717             if (print) {
718               logger.info(torsion.toString());
719             }
720           }
721         }
722         return 2;
723       }
724       case GLU:
725       case GLN:
726       case GLH: {
727         Atom N = (Atom) residue.getAtomNode("N");
728         Atom CA = (Atom) residue.getAtomNode("CA");
729         Atom CB = (Atom) residue.getAtomNode("CB");
730         Atom CG = (Atom) residue.getAtomNode("CG");
731         Atom CD = (Atom) residue.getAtomNode("CD");
732         Atom OE1 = (Atom) residue.getAtomNode("OE1");
733         for (Torsion torsion : residue.getTorsionList()) {
734           if (torsion.compare(N, CA, CB, CG)) {
735             chi[0] = torsion.measure();
736             if (print) {
737               logger.info(torsion.toString());
738             }
739           }
740           if (torsion.compare(CA, CB, CG, CD)) {
741             chi[1] = torsion.measure();
742             if (print) {
743               logger.info(torsion.toString());
744             }
745           }
746           if (torsion.compare(CB, CG, CD, OE1)) {
747             chi[2] = torsion.measure();
748             if (print) {
749               logger.info(torsion.toString());
750             }
751           }
752         }
753         return 3;
754       }
755       case MET: {
756         Atom N = (Atom) residue.getAtomNode("N");
757         Atom CA = (Atom) residue.getAtomNode("CA");
758         Atom CB = (Atom) residue.getAtomNode("CB");
759         Atom CG = (Atom) residue.getAtomNode("CG");
760         Atom CE = (Atom) residue.getAtomNode("CE");
761         Atom SD = (Atom) residue.getAtomNode("SD");
762         for (Torsion torsion : residue.getTorsionList()) {
763           if (torsion.compare(N, CA, CB, CG)) {
764             chi[0] = torsion.measure();
765             if (print) {
766               logger.info(torsion.toString());
767             }
768           }
769           if (torsion.compare(CA, CB, CG, SD)) {
770             chi[1] = torsion.measure();
771             if (print) {
772               logger.info(torsion.toString());
773             }
774           }
775           if (torsion.compare(CB, CG, SD, CE)) {
776             chi[2] = torsion.measure();
777             if (print) {
778               logger.info(torsion.toString());
779             }
780           }
781         }
782         return 3;
783       }
784       case LYS:
785       case LYD: {
786         Atom N = (Atom) residue.getAtomNode("N");
787         Atom CA = (Atom) residue.getAtomNode("CA");
788         Atom CB = (Atom) residue.getAtomNode("CB");
789         Atom CD = (Atom) residue.getAtomNode("CD");
790         Atom CE = (Atom) residue.getAtomNode("CE");
791         Atom CG = (Atom) residue.getAtomNode("CG");
792         Atom NZ = (Atom) residue.getAtomNode("NZ");
793         for (Torsion torsion : residue.getTorsionList()) {
794           if (torsion.compare(N, CA, CB, CG)) {
795             chi[0] = torsion.measure();
796             if (print) {
797               logger.info(torsion.toString());
798             }
799           }
800           if (torsion.compare(CA, CB, CG, CD)) {
801             chi[1] = torsion.measure();
802             if (print) {
803               logger.info(torsion.toString());
804             }
805           }
806           if (torsion.compare(CB, CG, CD, CE)) {
807             chi[2] = torsion.measure();
808             if (print) {
809               logger.info(torsion.toString());
810             }
811           }
812           if (torsion.compare(CG, CD, CE, NZ)) {
813             chi[3] = torsion.measure();
814             if (print) {
815               logger.info(torsion.toString());
816             }
817           }
818         }
819         return 4;
820       }
821       case ARG: {
822         Atom N = (Atom) residue.getAtomNode("N");
823         Atom CA = (Atom) residue.getAtomNode("CA");
824         Atom CB = (Atom) residue.getAtomNode("CB");
825         Atom CD = (Atom) residue.getAtomNode("CD");
826         Atom CG = (Atom) residue.getAtomNode("CG");
827         Atom CZ = (Atom) residue.getAtomNode("CZ");
828         Atom NE = (Atom) residue.getAtomNode("NE");
829         for (Torsion torsion : residue.getTorsionList()) {
830           if (torsion.compare(N, CA, CB, CG)) {
831             chi[0] = torsion.measure();
832             if (print) {
833               logger.info(torsion.toString());
834             }
835           }
836           if (torsion.compare(CA, CB, CG, CD)) {
837             chi[1] = torsion.measure();
838             if (print) {
839               logger.info(torsion.toString());
840             }
841           }
842           if (torsion.compare(CB, CG, CD, NE)) {
843             chi[2] = torsion.measure();
844             if (print) {
845               logger.info(torsion.toString());
846             }
847           }
848           if (torsion.compare(CG, CD, NE, CZ)) {
849             chi[3] = torsion.measure();
850             if (print) {
851               logger.info(torsion.toString());
852             }
853           }
854         }
855         return 4;
856       }
857       case UNK:
858         chi = new double[7];
859         String resName = residue.getName().toUpperCase();
860         if (nonstdRotCache.containsKey(resName)) {
861           return nonstdRotCache.get(resName).measureNonstdRot(residue, chi, print);
862           // nonstdRotCache.get(resName).applyNonstdRotamer(residue, rotamer);
863         } else {
864           throw new IllegalArgumentException(format("(IAE) valueOf(%s)", residue.getName()));
865         }
866       default: {
867         return 0;
868       }
869     }
870   }
871 
872   /**
873    * Measures the delta torsion (sugar pucker) of a nucleic acid Residue.
874    *
875    * @param residue To be measured
876    * @return Delta torsion (sugar pucker angle).
877    */
878   public static double measureDelta(Residue residue) {
879     Atom C5s = (Atom) residue.getAtomNode("C5'");
880     Atom C4s = (Atom) residue.getAtomNode("C4'");
881     Atom C3s = (Atom) residue.getAtomNode("C3'");
882     Atom O3s = (Atom) residue.getAtomNode("O3'");
883     Torsion torsion = O3s.getTorsion(C3s, C4s, C5s);
884     return torsion.measure();
885   }
886 
887   /**
888    * Measures the torsional angles of a residue's side chain.
889    *
890    * @param residue a {@link ffx.potential.bonded.Residue} object.
891    * @param print a boolean.
892    * @return an array of {@link double} objects.
893    */
894   public static double[] measureRotamer(Residue residue, boolean print) {
895     if (residue != null) {
896       switch (residue.getResidueType()) {
897         case AA:
898           double[] chi = new double[4];
899           try {
900             measureRotamer(residue, chi, print);
901           } catch (ArrayIndexOutOfBoundsException e) {
902             String message = " Array passed to measureRotamer was not of sufficient size.";
903             logger.log(Level.WARNING, message, e);
904           }
905           return chi;
906         case NA:
907           chi = new double[7];
908           try {
909             measureRotamer(residue, chi, print);
910           } catch (ArrayIndexOutOfBoundsException e) {
911             String message = " Array passed to measureRotamer was not of sufficient size.";
912             logger.log(Level.WARNING, message, e);
913           }
914           return chi;
915         default:
916           return null;
917       }
918     }
919     return null;
920   }
921 
922   /**
923    * Measures the torsion angles of a Residue.
924    *
925    * @param residue To be measured
926    * @param chi Array to be filled with torsion values
927    * @param print Verbosity flag
928    * @return The number of rotamers this Residue has.
929    */
930   public static int measureRotamer(Residue residue, double[] chi, boolean print) {
931     if (residue == null) {
932       return -1;
933     }
934     int nRot = -1;
935     switch (residue.getResidueType()) {
936       case AA:
937         try {
938           nRot = measureAARotamer(residue, chi, print);
939         } catch (ArrayIndexOutOfBoundsException e) {
940           String message = " Array passed to measureRotamer was not of sufficient size.";
941           logger.log(Level.WARNING, message, e);
942         }
943         break;
944       case NA:
945         try {
946           nRot = measureNARotamer(residue, chi, print);
947         } catch (ArrayIndexOutOfBoundsException e) {
948           String message = "Array passed to measureRotamer was not of sufficient size.";
949           logger.log(Level.WARNING, message, e);
950         }
951         break;
952       default:
953         try {
954           measureUNKRotamer(residue, chi, print);
955         } catch (ArrayIndexOutOfBoundsException e) {
956           String message = "Array passed to measureRotamer was not of sufficient size.";
957           logger.log(Level.WARNING, message, e);
958         }
959         break;
960     }
961     return nRot;
962   }
963 
964   /**
965    * Measures the torsions in a list of Residues.
966    *
967    * @param residueList Residues to be measured.
968    * @param print Verbosity flag.
969    */
970   public static void measureRotamers(List<Residue> residueList, boolean print) {
971     double[] chi = new double[7];
972     for (Residue residue : residueList) {
973       chi[0] = chi[1] = chi[2] = chi[3] = chi[4] = chi[5] = chi[6] = 0.0;
974       measureRotamer(residue, chi, print);
975       switch (residue.getResidueType()) {
976         case AA:
977           logger.info(format(" %c %s %8.3f %8.3f %8.3f %8.3f", residue.getChainID(),
978               residue, chi[0], chi[1], chi[2], chi[3]));
979           break;
980         case NA:
981           logger.info(format(" %c %s %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f %8.3f",
982                   residue.getChainID(), residue,
983                   chi[0], chi[1], chi[2], chi[3], chi[4], chi[5], chi[6]));
984           break;
985         default:
986           logger.info(" Not recognized as a nucleic or amino acid residue");
987           break;
988       }
989     }
990   }
991 
992   public static void readRotFile(File rotamerFile, MolecularAssembly assembly) throws IOException {
993     readRotFile(rotamerFile, assembly, 1);
994   }
995 
996   private static boolean addRotPatch(File rpatchFile) {
997     try (BufferedReader br = new BufferedReader(new FileReader(rpatchFile))) {
998       String resName = null;
999       List<String> applyLines = new ArrayList<>();
1000       // List<Rotamer> rotamers = new ArrayList<>();
1001       List<String> rotLines = new ArrayList<>();
1002       ResidueType rType = Residue.ResidueType.AA;
1003       String line = br.readLine();
1004       while (line != null) {
1005         line = line.trim();
1006         if (line.startsWith("PLACE")) {
1007           applyLines.add(line);
1008         } else if (line.startsWith("RESNAME")) {
1009           String[] toks = line.split("\\s+");
1010           resName = toks[1];
1011         } else if (line.startsWith("RESTYPE")) {
1012           String[] toks = line.split("\\s+");
1013           switch (toks[1]) {
1014             case "AA":
1015               rType = Residue.ResidueType.AA;
1016               break;
1017             case "NA":
1018               rType = Residue.ResidueType.NA;
1019               break;
1020             case "UNK":
1021             default:
1022               rType = Residue.ResidueType.UNK;
1023               break;
1024           }
1025         } else if (line.startsWith("ROTAMER")) {
1026           rotLines.add(line);
1027         }
1028         line = br.readLine();
1029       }
1030       if (resName != null) {
1031         List<Rotamer> rotamers = new ArrayList<>();
1032         for (String string : rotLines) {
1033           String[] toks = string.split("\\s+");
1034           int nVals = toks.length - 1;
1035           double[] values = new double[nVals];
1036           for (int i = 0; i < nVals; i++) {
1037             values[i] = Double.parseDouble(toks[i + 1]);
1038           }
1039           switch (rType) {
1040             case AA:
1041               rotamers.add(new Rotamer(AminoAcidUtils.AminoAcid3.UNK, values));
1042               break;
1043             case NA:
1044               rotamers.add(new Rotamer(NucleicAcidUtils.NucleicAcid3.UNK, values));
1045               break;
1046             case UNK:
1047             default:
1048               rotamers.add(new Rotamer(values));
1049               break;
1050           }
1051         }
1052 
1053         if (nonstdRotCache.containsKey(resName)) {
1054           logger.warning(
1055               format(
1056                   " Rotamer library already contains " + "rotamer definition for residue %s!",
1057                   resName));
1058         } else {
1059           NonstandardRotLibrary nrlib =
1060               new NonstandardRotLibrary(
1061                   resName,
1062                   applyLines.toArray(new String[0]),
1063                   rotamers.toArray(new Rotamer[0]));
1064           nonstdRotCache.put(resName, nrlib);
1065         }
1066         return true;
1067       } else {
1068         return false;
1069       }
1070     } catch (IOException ex) {
1071       logger.warning(
1072           format(
1073               " Exception in parsing rotamer patch " + "file %s: %s",
1074               rpatchFile.getName(), ex));
1075       return false;
1076     }
1077   }
1078 
1079   /**
1080    * Obtains an idealized angle using the force field. Note: can be misleading! Often, idealized
1081    * angles are not equilibrium angles; for example, AMOEBA 2018 has phenylalanine ring interior
1082    * angles that sum to > 720 degrees. This does not mean that an idealized phenylalanine ring
1083    * violates geometry, it means that the ring is always under at least a little strain.
1084    *
1085    * @param a1 An Atom.
1086    * @param a2 Another Atom.
1087    * @param a3 Another Atom.
1088    * @return Force field-defined a1-a2-a3 angle in degrees.
1089    */
1090   private static double angleFromForceField(Atom a1, Atom a2, Atom a3) {
1091     Angle a = a1.getAngle(a2, a3);
1092     AngleType at = a.getAngleType();
1093     return at.angle[a.nh];
1094   }
1095 
1096   /**
1097    * Applies an amino acid Rotamer.
1098    *
1099    * @param residue Residue
1100    * @param rotamer Rotamer to be applied to Residue
1101    */
1102   private static void applyAARotamer(Residue residue, Rotamer rotamer) {
1103     if (residue == null || rotamer == null) {
1104       return;
1105     }
1106     AminoAcid3 name;
1107     if (residue instanceof MultiResidue) {
1108       name = rotamer.aminoAcid3;
1109       if (!((MultiResidue) residue).setActiveResidue(name)) {
1110         logger.warning(format(" Could not set residue %s for multi-residue %s", name, residue));
1111       }
1112     } else {
1113       name = rotamer.aminoAcid3;
1114     }
1115     switch (name) {
1116       case VAL: {
1117         Atom CA = (Atom) residue.getAtomNode("CA");
1118         Atom CB = (Atom) residue.getAtomNode("CB");
1119         Atom N = (Atom) residue.getAtomNode("N");
1120         Atom CG1 = (Atom) residue.getAtomNode("CG1");
1121         Atom CG2 = (Atom) residue.getAtomNode("CG2");
1122         Atom HB = (Atom) residue.getAtomNode("HB");
1123         Atom HG11 = (Atom) residue.getAtomNode("HG11");
1124         Atom HG12 = (Atom) residue.getAtomNode("HG12");
1125         Atom HG13 = (Atom) residue.getAtomNode("HG13");
1126         Atom HG21 = (Atom) residue.getAtomNode("HG21");
1127         Atom HG22 = (Atom) residue.getAtomNode("HG22");
1128         Atom HG23 = (Atom) residue.getAtomNode("HG23");
1129         Bond CG_CB = CB.getBond(CG1);
1130         Bond HB_CB = CB.getBond(HB);
1131         Bond HG_CG = HG11.getBond(CG1);
1132         double dCG_CB = CG_CB.bondType.distance;
1133         double dHB_CB = HB_CB.bondType.distance;
1134         double dHG_CG = HG_CG.bondType.distance;
1135         Angle CG_CB_CA = CG1.getAngle(CB, CA);
1136         Angle HB_CB_CA = HB.getAngle(CB, CA);
1137         Angle HG_CG_CB = HG11.getAngle(CG1, CB);
1138         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
1139         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1140         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
1141         intxyz(CG1, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1142         intxyz(CG2, CB, dCG_CB, CA, dCG_CB_CA, CG1, 109.5, -1);
1143         intxyz(HB, CB, dHB_CB, CA, dHB_CB_CA, CG1, 109.4, 1);
1144         intxyz(HG11, CG1, dHG_CG, CB, dHG_CG_CB, CA, 180.0, 0);
1145         intxyz(HG12, CG1, dHG_CG, CB, dHG_CG_CB, HG11, 109.4, 1);
1146         intxyz(HG13, CG1, dHG_CG, CB, dHG_CG_CB, HG11, 109.4, -1);
1147         intxyz(HG21, CG2, dHG_CG, CB, dHG_CG_CB, CA, 180.0, 0);
1148         intxyz(HG22, CG2, dHG_CG, CB, dHG_CG_CB, HG21, 109.4, 1);
1149         intxyz(HG23, CG2, dHG_CG, CB, dHG_CG_CB, HG21, 109.4, -1);
1150         break;
1151       }
1152       case LEU: {
1153         Atom CA = (Atom) residue.getAtomNode("CA");
1154         Atom CB = (Atom) residue.getAtomNode("CB");
1155         Atom N = (Atom) residue.getAtomNode("N");
1156         Atom CG = (Atom) residue.getAtomNode("CG");
1157         Atom CD1 = (Atom) residue.getAtomNode("CD1");
1158         Atom CD2 = (Atom) residue.getAtomNode("CD2");
1159         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1160         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1161         Atom HG = (Atom) residue.getAtomNode("HG");
1162         Atom HD11 = (Atom) residue.getAtomNode("HD11");
1163         Atom HD12 = (Atom) residue.getAtomNode("HD12");
1164         Atom HD13 = (Atom) residue.getAtomNode("HD13");
1165         Atom HD21 = (Atom) residue.getAtomNode("HD21");
1166         Atom HD22 = (Atom) residue.getAtomNode("HD22");
1167         Atom HD23 = (Atom) residue.getAtomNode("HD23");
1168         Bond CG_CB = CG.getBond(CB);
1169         Bond CD_CG = CD1.getBond(CG);
1170         Bond HB_CB = HB2.getBond(CB);
1171         Bond HG_CG = HG.getBond(CG);
1172         Bond HD_CD = HD11.getBond(CD1);
1173         double dCG_CB = CG_CB.bondType.distance;
1174         double dCD_CG = CD_CG.bondType.distance;
1175         double dHB_CB = HB_CB.bondType.distance;
1176         double dHG_CG = HG_CG.bondType.distance;
1177         double dHD_CD = HD_CD.bondType.distance;
1178         Angle CG_CB_CA = CG.getAngle(CB, CA);
1179         Angle CD_CG_CB = CD1.getAngle(CG, CB);
1180         Angle HB_CB_CA = HB2.getAngle(CB, CA);
1181         Angle HG_CG_CB = HG.getAngle(CG, CB);
1182         Angle HD_CD_CG = HD11.getAngle(CD1, CG);
1183         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
1184         double dCD_CG_CB = CD_CG_CB.angleType.angle[CD_CG_CB.nh];
1185         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1186         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
1187         double dHD_CD_CG = HD_CD_CG.angleType.angle[HD_CD_CG.nh];
1188         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1189         intxyz(CD1, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
1190         intxyz(CD2, CG, dCD_CG, CB, dCD_CG_CB, CD1, 109.5, -1);
1191         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1192         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1193         intxyz(HG, CG, dHG_CG, CB, dHG_CG_CB, CD1, 109.4, 1);
1194         intxyz(HD11, CD1, dHD_CD, CG, dHD_CD_CG, CB, 180.0, 0);
1195         intxyz(HD12, CD1, dHD_CD, CG, dHD_CD_CG, HD11, 109.4, 1);
1196         intxyz(HD13, CD1, dHD_CD, CG, dHD_CD_CG, HD11, 109.4, -1);
1197         intxyz(HD21, CD2, dHD_CD, CG, dHD_CD_CG, CB, 180.0, 0);
1198         intxyz(HD22, CD2, dHD_CD, CG, dHD_CD_CG, HD21, 109.4, 1);
1199         intxyz(HD23, CD2, dHD_CD, CG, dHD_CD_CG, HD21, 109.4, -1);
1200         break;
1201       }
1202       case ILE: {
1203         Atom CA = (Atom) residue.getAtomNode("CA");
1204         Atom CB = (Atom) residue.getAtomNode("CB");
1205         Atom N = (Atom) residue.getAtomNode("N");
1206         Atom CG1 = (Atom) residue.getAtomNode("CG1");
1207         Atom CG2 = (Atom) residue.getAtomNode("CG2");
1208         Atom CD1 = (Atom) residue.getAtomNode("CD1");
1209         Atom HB = (Atom) residue.getAtomNode("HB");
1210         Atom HG12 = (Atom) residue.getAtomNode("HG12");
1211         Atom HG13 = (Atom) residue.getAtomNode("HG13");
1212         Atom HG21 = (Atom) residue.getAtomNode("HG21");
1213         Atom HG22 = (Atom) residue.getAtomNode("HG22");
1214         Atom HG23 = (Atom) residue.getAtomNode("HG23");
1215         Atom HD11 = (Atom) residue.getAtomNode("HD11");
1216         Atom HD12 = (Atom) residue.getAtomNode("HD12");
1217         Atom HD13 = (Atom) residue.getAtomNode("HD13");
1218         Bond CG1_CB = CG1.getBond(CB);
1219         Bond CG2_CB = CG2.getBond(CB);
1220         Bond CD1_CG1 = CD1.getBond(CG1);
1221         Bond HB_CB = HB.getBond(CB);
1222         Bond HG1_CG = HG12.getBond(CG1);
1223         Bond HG2_CG = HG22.getBond(CG2);
1224         Bond HD_CD = HD12.getBond(CD1);
1225         double dCG1_CB = CG1_CB.bondType.distance;
1226         double dCG2_CB = CG2_CB.bondType.distance;
1227         double dCD1_CG1 = CD1_CG1.bondType.distance;
1228         double dHB_CB = HB_CB.bondType.distance;
1229         double dHG1_CG = HG1_CG.bondType.distance;
1230         double dHG2_CG = HG2_CG.bondType.distance;
1231         double dHD_CD = HD_CD.bondType.distance;
1232         Angle CG1_CB_CA = CG1.getAngle(CB, CA);
1233         Angle CG2_CB_CA = CG2.getAngle(CB, CA);
1234         Angle CD1_CG1_CB = CD1.getAngle(CG1, CB);
1235         Angle HB_CB_CA = HB.getAngle(CB, CA);
1236         Angle HG1_CG_CB = HG12.getAngle(CG1, CB);
1237         Angle HG2_CG_CB = HG21.getAngle(CG2, CB);
1238         Angle HD_CD1_CG1 = HD11.getAngle(CD1, CG1);
1239         double dCG1_CB_CA = CG1_CB_CA.angleType.angle[CG1_CB_CA.nh];
1240         double dCG2_CB_CA = CG2_CB_CA.angleType.angle[CG2_CB_CA.nh];
1241         double dCD1_CG1_CB = CD1_CG1_CB.angleType.angle[CD1_CG1_CB.nh];
1242         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1243         double dHG1_CG_CB = HG1_CG_CB.angleType.angle[HG1_CG_CB.nh];
1244         double dHG2_CG_CB = HG2_CG_CB.angleType.angle[HG2_CG_CB.nh];
1245         double dHD_CD1_CG1 = HD_CD1_CG1.angleType.angle[HD_CD1_CG1.nh];
1246         intxyz(CG1, CB, dCG1_CB, CA, dCG1_CB_CA, N, rotamer.chi1, 0);
1247         intxyz(CG2, CB, dCG2_CB, CA, dCG2_CB_CA, CG1, 109.5, 1);
1248         intxyz(CD1, CG1, dCD1_CG1, CB, dCD1_CG1_CB, CA, rotamer.chi2, 0);
1249         intxyz(HB, CB, dHB_CB, CA, dHB_CB_CA, CG2, 109.4, 1);
1250         intxyz(HG12, CG1, dHG1_CG, CB, dHG1_CG_CB, CD1, 109.4, 1);
1251         intxyz(HG13, CG1, dHG1_CG, CB, dHG1_CG_CB, CD1, 109.4, -1);
1252         intxyz(HG21, CG2, dHG2_CG, CB, dHG2_CG_CB, CG1, 180.0, 0);
1253         intxyz(HG22, CG2, dHG2_CG, CB, dHG2_CG_CB, HG21, 109.0, 1);
1254         intxyz(HG23, CG2, dHG2_CG, CB, dHG2_CG_CB, HG21, 109.0, -1);
1255         intxyz(HD11, CD1, dHD_CD, CG1, dHD_CD1_CG1, CB, 180.0, 0);
1256         intxyz(HD12, CD1, dHD_CD, CG1, dHD_CD1_CG1, HD11, 109.0, 1);
1257         intxyz(HD13, CD1, dHD_CD, CG1, dHD_CD1_CG1, HD11, 109.0, -1);
1258         break;
1259       }
1260       case SER: {
1261         Atom CA = (Atom) residue.getAtomNode("CA");
1262         Atom CB = (Atom) residue.getAtomNode("CB");
1263         Atom N = (Atom) residue.getAtomNode("N");
1264         Atom OG = (Atom) residue.getAtomNode("OG");
1265         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1266         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1267         Atom HG = (Atom) residue.getAtomNode("HG");
1268         Bond OG_CB = OG.getBond(CB);
1269         Bond HB_CB = HB2.getBond(CB);
1270         Bond HG_OG = HG.getBond(OG);
1271         double dOG_CB = OG_CB.bondType.distance;
1272         double dHB_CB = HB_CB.bondType.distance;
1273         double dHG_OG = HG_OG.bondType.distance;
1274         Angle OG_CB_CA = OG.getAngle(CB, CA);
1275         Angle HB_CB_CA = HB2.getAngle(CB, CA);
1276         Angle HG_OG_CB = HG.getAngle(OG, CB);
1277         double dOG_CB_CA = OG_CB_CA.angleType.angle[OG_CB_CA.nh];
1278         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1279         double dHG_OG_CB = HG_OG_CB.angleType.angle[HG_OG_CB.nh];
1280         intxyz(OG, CB, dOG_CB, CA, dOG_CB_CA, N, rotamer.chi1, 0);
1281         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, OG, 106.7, 1);
1282         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, OG, 106.7, -1);
1283         intxyz(HG, OG, dHG_OG, CB, dHG_OG_CB, CA, 180.0, 0);
1284         if (rotamer.length == 2) {
1285           intxyz(HG, OG, dHG_OG, CB, dHG_OG_CB, CA, rotamer.chi2, 0);
1286         } else {
1287           intxyz(HG, OG, dHG_OG, CB, dHG_OG_CB, CA, 180.0, 0);
1288         }
1289         break;
1290       }
1291       case THR: {
1292         Atom CA = (Atom) residue.getAtomNode("CA");
1293         Atom CB = (Atom) residue.getAtomNode("CB");
1294         Atom N = (Atom) residue.getAtomNode("N");
1295         Atom OG1 = (Atom) residue.getAtomNode("OG1");
1296         Atom CG2 = (Atom) residue.getAtomNode("CG2");
1297         Atom HB = (Atom) residue.getAtomNode("HB");
1298         Atom HG1 = (Atom) residue.getAtomNode("HG1");
1299         Atom HG21 = (Atom) residue.getAtomNode("HG21");
1300         Atom HG22 = (Atom) residue.getAtomNode("HG22");
1301         Atom HG23 = (Atom) residue.getAtomNode("HG23");
1302         Bond OG1_CB = OG1.getBond(CB);
1303         Bond CG2_CB = CG2.getBond(CB);
1304         Bond HB_CB = HB.getBond(CB);
1305         Bond HG1_OG1 = HG1.getBond(OG1);
1306         Bond HG2_CG2 = HG21.getBond(CG2);
1307         double dOG1_CB = OG1_CB.bondType.distance;
1308         double dCG2_CB = CG2_CB.bondType.distance;
1309         double dHB_CB = HB_CB.bondType.distance;
1310         double dHG1_OG1 = HG1_OG1.bondType.distance;
1311         double dHG2_CG2 = HG2_CG2.bondType.distance;
1312         Angle OG1_CB_CA = OG1.getAngle(CB, CA);
1313         Angle CG2_CB_CA = CG2.getAngle(CB, CA);
1314         Angle HB_CB_CA = HB.getAngle(CB, CA);
1315         Angle HG1_OG1_CB = HG1.getAngle(OG1, CB);
1316         Angle HG2_CG2_CB = HG21.getAngle(CG2, CB);
1317         double dOG1_CB_CA = OG1_CB_CA.angleType.angle[OG1_CB_CA.nh];
1318         double dCG2_CB_CA = CG2_CB_CA.angleType.angle[CG2_CB_CA.nh];
1319         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1320         double dHG1_OG1_CB = HG1_OG1_CB.angleType.angle[HG1_OG1_CB.nh];
1321         double dHG2_CG2_CB = HG2_CG2_CB.angleType.angle[HG2_CG2_CB.nh];
1322         intxyz(OG1, CB, dOG1_CB, CA, dOG1_CB_CA, N, rotamer.chi1, 0);
1323         intxyz(CG2, CB, dCG2_CB, CA, dCG2_CB_CA, OG1, 107.7, 1);
1324         intxyz(HB, CB, dHB_CB, CA, dHB_CB_CA, OG1, 106.7, -1);
1325         intxyz(HG1, OG1, dHG1_OG1, CB, dHG1_OG1_CB, CA, 180.0, 0);
1326         if (rotamer.length == 2) {
1327           intxyz(HG1, OG1, dHG1_OG1, CB, dHG1_OG1_CB, CA, rotamer.chi2, 0);
1328         } else {
1329           intxyz(HG1, OG1, dHG1_OG1, CB, dHG1_OG1_CB, CA, 180, 0);
1330         }
1331         intxyz(HG21, CG2, dHG2_CG2, CB, dHG2_CG2_CB, CA, 180.0, 0);
1332         intxyz(HG22, CG2, dHG2_CG2, CB, dHG2_CG2_CB, HG21, 109.0, 1);
1333         intxyz(HG23, CG2, dHG2_CG2, CB, dHG2_CG2_CB, HG21, 109.0, -1);
1334         break;
1335       }
1336       case CYS:
1337       case CYX: {
1338         Atom CA = (Atom) residue.getAtomNode("CA");
1339         Atom CB = (Atom) residue.getAtomNode("CB");
1340         Atom N = (Atom) residue.getAtomNode("N");
1341         Atom SG = (Atom) residue.getAtomNode("SG");
1342         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1343         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1344         Atom HG = (Atom) residue.getAtomNode("HG");
1345         if (CA == null
1346             || CB == null
1347             || N == null
1348             || SG == null
1349             || HB2 == null
1350             || HB3 == null
1351             || HG == null) {
1352           break;
1353         }
1354         Bond SG_CB = SG.getBond(CB);
1355         Bond HB_CB = HB2.getBond(CB);
1356         Bond HG_SG = HG.getBond(SG);
1357         double dSG_CB = SG_CB.bondType.distance;
1358         double dHB_CB = HB_CB.bondType.distance;
1359         double dHG_SG = HG_SG.bondType.distance;
1360         Angle SG_CB_CA = SG.getAngle(CB, CA);
1361         Angle HB_CB_CA = HB2.getAngle(CB, CA);
1362         Angle HG_SG_CB = HG.getAngle(SG, CB);
1363         double dSG_CB_CA = SG_CB_CA.angleType.angle[SG_CB_CA.nh];
1364         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1365         double dHG_SG_CB = HG_SG_CB.angleType.angle[HG_SG_CB.nh];
1366         intxyz(SG, CB, dSG_CB, CA, dSG_CB_CA, N, rotamer.chi1, 0);
1367         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, SG, 112.0, 1);
1368         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, SG, 112.0, -1);
1369         intxyz(HG, SG, dHG_SG, CB, dHG_SG_CB, CA, 180.0, 0);
1370         break;
1371       }
1372       case CYD: {
1373         Atom CA = (Atom) residue.getAtomNode("CA");
1374         Atom CB = (Atom) residue.getAtomNode("CB");
1375         Atom N = (Atom) residue.getAtomNode("N");
1376         Atom SG = (Atom) residue.getAtomNode("SG");
1377         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1378         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1379         Bond SG_CB = SG.getBond(CB);
1380         Bond HB_CB = HB2.getBond(CB);
1381         double dSG_CB = SG_CB.bondType.distance;
1382         double dHB_CB = HB_CB.bondType.distance;
1383         Angle SG_CB_CA = SG.getAngle(CB, CA);
1384         Angle HB_CB_CA = HB2.getAngle(CB, CA);
1385         double dSG_CB_CA = SG_CB_CA.angleType.angle[SG_CB_CA.nh];
1386         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1387         intxyz(SG, CB, dSG_CB, CA, dSG_CB_CA, N, rotamer.chi1, 0);
1388         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, SG, 112.0, 1);
1389         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, SG, 112.0, -1);
1390         break;
1391       }
1392       case PHE: {
1393         Atom CA = (Atom) residue.getAtomNode("CA");
1394         Atom CB = (Atom) residue.getAtomNode("CB");
1395         Atom N = (Atom) residue.getAtomNode("N");
1396         Atom CG = (Atom) residue.getAtomNode("CG");
1397         Atom CD1 = (Atom) residue.getAtomNode("CD1");
1398         Atom CD2 = (Atom) residue.getAtomNode("CD2");
1399         Atom CE1 = (Atom) residue.getAtomNode("CE1");
1400         Atom CE2 = (Atom) residue.getAtomNode("CE2");
1401         Atom CZ = (Atom) residue.getAtomNode("CZ");
1402         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1403         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1404         Atom HD1 = (Atom) residue.getAtomNode("HD1");
1405         Atom HD2 = (Atom) residue.getAtomNode("HD2");
1406         Atom HE1 = (Atom) residue.getAtomNode("HE1");
1407         Atom HE2 = (Atom) residue.getAtomNode("HE2");
1408         Atom HZ = (Atom) residue.getAtomNode("HZ");
1409         Bond CG_CB = CG.getBond(CB);
1410         Bond CD_CG = CD1.getBond(CG);
1411         Bond CE_CD = CE1.getBond(CD1);
1412         Bond HB_CB = HB2.getBond(CB);
1413         double dCG_CB = CG_CB.bondType.distance;
1414         double dCD_CG = CD_CG.bondType.distance;
1415         double dCE_CD = CE_CD.bondType.distance;
1416         double dHB_CB = HB_CB.bondType.distance;
1417 
1418         double dHD_CD = HD1.getBond(CD1).bondType.distance;
1419         double dHE_CE = HE1.getBond(CE1).bondType.distance;
1420         double dHZ_CZ = HZ.getBond(CZ).bondType.distance;
1421 
1422         double dCG_CB_CA = getAngle(name, CG, CB, CA);
1423         double dCD_CG_CB = getAngle(name, CD1, CG, CB);
1424         double dCE_CD_CG = getAngle(name, CE1, CD1, CG);
1425         double dHB_CB_CA = getAngle(name, HB2, CB, CA);
1426 
1427         double dHD_CD_CG = getAngle(name, HD1, CD1, CG);
1428         double dHD_CD_CE = getAngle(name, HD1, CD1, CE1);
1429         double dHE_CE_CD = getAngle(name, HE1, CE1, CD1);
1430         double dHE_CE_CZ = getAngle(name, HE1, CE1, CZ);
1431         double dHZ_CZ_CE = getAngle(name, HZ, CZ, CE1);
1432 
1433         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1434         intxyz(CD1, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
1435         intxyz(CD2, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2 + 180, 0);
1436         intxyz(CE1, CD1, dCE_CD, CG, dCE_CD_CG, CB, 180, 0);
1437         intxyz(CE2, CD2, dCE_CD, CG, dCE_CD_CG, CB, 180, 0);
1438         applyCZ(name, CZ, CG, CE1, CD1, CE2, CD2);
1439         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1440         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1441 
1442         intxyz(HD1, CD1, dHD_CD, CG, dHD_CD_CG, CE1, dHD_CD_CE, 3);
1443         intxyz(HD2, CD2, dHD_CD, CG, dHD_CD_CG, CE2, dHD_CD_CE, 3);
1444         intxyz(HE1, CE1, dHE_CE, CD1, dHE_CE_CD, CZ, dHE_CE_CZ, 3);
1445         intxyz(HE2, CE2, dHE_CE, CD2, dHE_CE_CD, CZ, dHE_CE_CZ, 3);
1446         intxyz(HZ, CZ, dHZ_CZ, CE1, dHZ_CZ_CE, CE2, dHZ_CZ_CE, 3);
1447         break;
1448       }
1449       case PRO: {
1450         Atom CA = (Atom) residue.getAtomNode("CA");
1451         Atom CB = (Atom) residue.getAtomNode("CB");
1452         Atom N = (Atom) residue.getAtomNode("N");
1453         Atom CG = (Atom) residue.getAtomNode("CG");
1454         Atom CD = (Atom) residue.getAtomNode("CD");
1455         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1456         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1457         Atom HG2 = (Atom) residue.getAtomNode("HG2");
1458         Atom HG3 = (Atom) residue.getAtomNode("HG3");
1459         Atom HD2 = (Atom) residue.getAtomNode("HD2");
1460         Atom HD3 = (Atom) residue.getAtomNode("HD3");
1461         Bond CG_CB = CG.getBond(CB);
1462         Bond CD_CG = CD.getBond(CG);
1463         Bond HB_CB = HB2.getBond(CB);
1464         Bond HG_CG = HG2.getBond(CG);
1465         Bond HD_CD = HD2.getBond(CD);
1466         double dCG_CB = CG_CB.bondType.distance;
1467         double dCD_CG = CD_CG.bondType.distance;
1468         double dHB_CB = HB_CB.bondType.distance;
1469         double dHG_CG = HG_CG.bondType.distance;
1470         double dHD_CD = HD_CD.bondType.distance;
1471         Angle CG_CB_CA = CG.getAngle(CB, CA);
1472         Angle CD_CG_CB = CD.getAngle(CG, CB);
1473         Angle HB_CB_CA = HB2.getAngle(CB, CA);
1474         Angle HG_CG_CB = HG2.getAngle(CG, CB);
1475         Angle HD_CD_CG = HD2.getAngle(CD, CG);
1476         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
1477         double dCD_CG_CB = CD_CG_CB.angleType.angle[CD_CG_CB.nh];
1478         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1479         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
1480         double dHD_CD_CG = HD_CD_CG.angleType.angle[HD_CD_CG.nh];
1481         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1482         intxyz(CD, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
1483         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1484         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1485         intxyz(HG2, CG, dHG_CG, CB, dHG_CG_CB, CD, 109.4, 1);
1486         intxyz(HG3, CG, dHG_CG, CB, dHG_CG_CB, CD, 109.4, -1);
1487         intxyz(HD2, CD, dHD_CD, CG, dHD_CD_CG, N, 109.4, 1);
1488         intxyz(HD3, CD, dHD_CD, CG, dHD_CD_CG, N, 109.4, -1);
1489         break;
1490       }
1491       case TYR: {
1492         Atom CA = (Atom) residue.getAtomNode("CA");
1493         Atom CB = (Atom) residue.getAtomNode("CB");
1494         Atom N = (Atom) residue.getAtomNode("N");
1495         Atom CG = (Atom) residue.getAtomNode("CG");
1496         Atom CD1 = (Atom) residue.getAtomNode("CD1");
1497         Atom CD2 = (Atom) residue.getAtomNode("CD2");
1498         Atom CE1 = (Atom) residue.getAtomNode("CE1");
1499         Atom CE2 = (Atom) residue.getAtomNode("CE2");
1500         Atom CZ = (Atom) residue.getAtomNode("CZ");
1501         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1502         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1503         Atom HD1 = (Atom) residue.getAtomNode("HD1");
1504         Atom HD2 = (Atom) residue.getAtomNode("HD2");
1505         Atom HE1 = (Atom) residue.getAtomNode("HE1");
1506         Atom HE2 = (Atom) residue.getAtomNode("HE2");
1507         Atom OH = (Atom) residue.getAtomNode("OH");
1508         Atom HH = (Atom) residue.getAtomNode("HH");
1509         Bond CG_CB = CG.getBond(CB);
1510         Bond CD_CG = CD1.getBond(CG);
1511         Bond CE_CD = CE1.getBond(CD1);
1512         Bond HB_CB = HB2.getBond(CB);
1513         double dCG_CB = CG_CB.bondType.distance;
1514         double dCD_CG = CD_CG.bondType.distance;
1515         double dCE_CD = CE_CD.bondType.distance;
1516         double dHB_CB = HB_CB.bondType.distance;
1517 
1518         double dHD_CD = HD1.getBond(CD1).bondType.distance;
1519         double dHE_CE = HE1.getBond(CE1).bondType.distance;
1520         double dOH_CZ = OH.getBond(CZ).bondType.distance;
1521         double dHH_OH = HH.getBond(OH).bondType.distance;
1522 
1523         double dCG_CB_CA = getAngle(name, CG, CB, CA);
1524         double dCD_CG_CB = getAngle(name, CD1, CG, CB);
1525         double dCE_CD_CG = getAngle(name, CE1, CD1, CG);
1526         double dHB_CB_CA = getAngle(name, HB2, CB, CA);
1527 
1528         double dHD_CD_CG = getAngle(name, HD1, CD1, CG);
1529         double dHD_CD_CE = getAngle(name, HD1, CD1, CE1);
1530         double dHE_CE_CD = getAngle(name, HE1, CE1, CD1);
1531         double dHE_CE_CZ = getAngle(name, HE1, CE1, CZ);
1532         double dOH_CZ_CE = getAngle(name, OH, CZ, CE1);
1533         double dHH_OH_CZ = getAngle(name, HH, OH, CZ);
1534 
1535         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1536         intxyz(CD1, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
1537         intxyz(CD2, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2 + 180, 0);
1538         intxyz(CE1, CD1, dCE_CD, CG, dCE_CD_CG, CB, 180, 0);
1539         intxyz(CE2, CD2, dCE_CD, CG, dCE_CD_CG, CB, 180, 0);
1540         applyCZ(name, CZ, CG, CE1, CD1, CE2, CD2);
1541         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1542         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1543 
1544         intxyz(HD1, CD1, dHD_CD, CG, dHD_CD_CG, CE1, dHD_CD_CE, 3);
1545         intxyz(HD2, CD2, dHD_CD, CG, dHD_CD_CG, CE2, dHD_CD_CE, 3);
1546         intxyz(HE1, CE1, dHE_CE, CD1, dHE_CE_CD, CZ, dHE_CE_CZ, 3);
1547         intxyz(HE2, CE2, dHE_CE, CD2, dHE_CE_CD, CZ, dHE_CE_CZ, 3);
1548         intxyz(OH, CZ, dOH_CZ, CE1, dOH_CZ_CE, CE2, dOH_CZ_CE, 3);
1549 
1550         if (rotamer.length == 3) {
1551           intxyz(HH, OH, dHH_OH, CZ, dHH_OH_CZ, CE2, rotamer.chi3, 0);
1552         } else {
1553           intxyz(HH, OH, dHH_OH, CZ, dHH_OH_CZ, CE2, 0.0, 0);
1554         }
1555         break;
1556       }
1557       case TYD: {
1558         Atom CA = (Atom) residue.getAtomNode("CA");
1559         Atom CB = (Atom) residue.getAtomNode("CB");
1560         Atom N = (Atom) residue.getAtomNode("N");
1561         Atom CG = (Atom) residue.getAtomNode("CG");
1562         Atom CD1 = (Atom) residue.getAtomNode("CD1");
1563         Atom CD2 = (Atom) residue.getAtomNode("CD2");
1564         Atom CE1 = (Atom) residue.getAtomNode("CE1");
1565         Atom CE2 = (Atom) residue.getAtomNode("CE2");
1566         Atom CZ = (Atom) residue.getAtomNode("CZ");
1567         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1568         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1569         Atom HD1 = (Atom) residue.getAtomNode("HD1");
1570         Atom HD2 = (Atom) residue.getAtomNode("HD2");
1571         Atom HE1 = (Atom) residue.getAtomNode("HE1");
1572         Atom HE2 = (Atom) residue.getAtomNode("HE2");
1573         Atom OH = (Atom) residue.getAtomNode("OH");
1574         Bond CG_CB = CG.getBond(CB);
1575         Bond CD_CG = CD1.getBond(CG);
1576         Bond CE_CD = CE1.getBond(CD1);
1577         Bond HB_CB = HB2.getBond(CB);
1578         double dCG_CB = CG_CB.bondType.distance;
1579         double dCD_CG = CD_CG.bondType.distance;
1580         double dCE_CD = CE_CD.bondType.distance;
1581         double dHB_CB = HB_CB.bondType.distance;
1582 
1583         double dHD_CD = HD1.getBond(CD1).bondType.distance;
1584         double dHE_CE = HE1.getBond(CE1).bondType.distance;
1585         double dOH_CZ = OH.getBond(CZ).bondType.distance;
1586 
1587         double dCG_CB_CA = getAngle(name, CG, CB, CA);
1588         double dCD_CG_CB = getAngle(name, CD1, CG, CB);
1589         double dCE_CD_CG = getAngle(name, CE1, CD1, CG);
1590         double dHB_CB_CA = getAngle(name, HB2, CB, CA);
1591 
1592         double dHD_CD_CG = getAngle(name, HD1, CD1, CG);
1593         double dHD_CD_CE = getAngle(name, HD1, CD1, CE1);
1594         double dHE_CE_CD = getAngle(name, HE1, CE1, CD1);
1595         double dHE_CE_CZ = getAngle(name, HE1, CE1, CZ);
1596         double dOH_CZ_CE = getAngle(name, OH, CZ, CE1);
1597 
1598         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1599         intxyz(CD1, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
1600         intxyz(CD2, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2 + 180, 0);
1601         intxyz(CE1, CD1, dCE_CD, CG, dCE_CD_CG, CB, 180, 0);
1602         intxyz(CE2, CD2, dCE_CD, CG, dCE_CD_CG, CB, 180, 0);
1603         applyCZ(name, CZ, CG, CE1, CD1, CE2, CD2);
1604         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1605         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1606 
1607         intxyz(HD1, CD1, dHD_CD, CG, dHD_CD_CG, CE1, dHD_CD_CE, 3);
1608         intxyz(HD2, CD2, dHD_CD, CG, dHD_CD_CG, CE2, dHD_CD_CE, 3);
1609         intxyz(HE1, CE1, dHE_CE, CD1, dHE_CE_CD, CZ, dHE_CE_CZ, 3);
1610         intxyz(HE2, CE2, dHE_CE, CD2, dHE_CE_CD, CZ, dHE_CE_CZ, 3);
1611         intxyz(OH, CZ, dOH_CZ, CE1, dOH_CZ_CE, CE2, dOH_CZ_CE, 3);
1612         break;
1613       }
1614       case TRP: {
1615         Atom CA = (Atom) residue.getAtomNode("CA");
1616         Atom CB = (Atom) residue.getAtomNode("CB");
1617         Atom N = (Atom) residue.getAtomNode("N");
1618         Atom CG = (Atom) residue.getAtomNode("CG");
1619         Atom CD1 = (Atom) residue.getAtomNode("CD1");
1620         Atom CD2 = (Atom) residue.getAtomNode("CD2");
1621         Atom NE1 = (Atom) residue.getAtomNode("NE1");
1622         Atom CE2 = (Atom) residue.getAtomNode("CE2");
1623         Atom CE3 = (Atom) residue.getAtomNode("CE3");
1624         Atom CZ2 = (Atom) residue.getAtomNode("CZ2");
1625         Atom CZ3 = (Atom) residue.getAtomNode("CZ3");
1626         Atom CH2 = (Atom) residue.getAtomNode("CH2");
1627         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1628         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1629         Atom HD1 = (Atom) residue.getAtomNode("HD1");
1630         Atom HE1 = (Atom) residue.getAtomNode("HE1");
1631         Atom HE3 = (Atom) residue.getAtomNode("HE3");
1632         Atom HZ2 = (Atom) residue.getAtomNode("HZ2");
1633         Atom HZ3 = (Atom) residue.getAtomNode("HZ3");
1634         Atom HH2 = (Atom) residue.getAtomNode("HH2");
1635         Bond CG_CB = CG.getBond(CB);
1636         Bond CD1_CG = CD1.getBond(CG);
1637         Bond CD2_CG = CD2.getBond(CG);
1638         Bond NE1_CD1 = NE1.getBond(CD1);
1639         Bond CE2_NE1 = CE2.getBond(NE1);
1640         Bond CE3_CD2 = CE3.getBond(CD2);
1641         Bond CZ2_CE2 = CZ2.getBond(CE2);
1642         Bond CZ3_CE3 = CZ3.getBond(CE3);
1643         Bond CH2_CZ2 = CH2.getBond(CZ2);
1644         Bond HB_CB = HB2.getBond(CB);
1645         Bond HD1_CD1 = HD1.getBond(CD1);
1646         Bond HE1_NE1 = HE1.getBond(NE1);
1647         Bond HE3_CE3 = HE3.getBond(CE3);
1648         Bond HZ2_CZ2 = HZ2.getBond(CZ2);
1649         Bond HZ3_CZ3 = HZ3.getBond(CZ3);
1650         Bond HH2_CH2 = HH2.getBond(CH2);
1651         double dCG_CB = CG_CB.bondType.distance;
1652         double dCD1_CG = CD1_CG.bondType.distance;
1653         double dCD2_CG = CD2_CG.bondType.distance;
1654         double dNE1_CD1 = NE1_CD1.bondType.distance;
1655         double dCE2_NE1 = CE2_NE1.bondType.distance;
1656         double dCE3_CD2 = CE3_CD2.bondType.distance;
1657         double dCZ2_CE2 = CZ2_CE2.bondType.distance;
1658         double dCZ3_CE3 = CZ3_CE3.bondType.distance;
1659         double dCH2_CZ2 = CH2_CZ2.bondType.distance;
1660         double dHB_CB = HB_CB.bondType.distance;
1661         double dHD1_CD1 = HD1_CD1.bondType.distance;
1662         double dHE1_NE1 = HE1_NE1.bondType.distance;
1663         double dHE3_CE3 = HE3_CE3.bondType.distance;
1664         double dHZ2_CZ2 = HZ2_CZ2.bondType.distance;
1665         double dHZ3_CZ3 = HZ3_CZ3.bondType.distance;
1666         double dHH2_CH2 = HH2_CH2.bondType.distance;
1667 
1668         double dCG_CB_CA = getAngle(name, CG, CB, CA);
1669         double dCD1_CG_CB = getAngle(name, CD1, CG, CB);
1670         double dCD2_CG_CB = getAngle(name, CD2, CG, CB);
1671         double dNE1_CD1_CG = getAngle(name, NE1, CD1, CG);
1672         double dCE2_NE1_CD1 = getAngle(name, CE2, NE1, CD1);
1673         double dCE3_CD2_CE2 = getAngle(name, CE3, CD2, CE2);
1674         double dCZ2_CE2_CD2 = getAngle(name, CZ2, CE2, CD2);
1675         double dCZ3_CE3_CD2 = getAngle(name, CZ3, CE3, CD2);
1676         double dCH2_CZ2_CE2 = getAngle(name, CH2, CZ2, CE2);
1677         double dHB_CB_CA = getAngle(name, HB2, CB, CA);
1678         double dHD1_CD1_CG = getAngle(name, HD1, CD1, CG);
1679         double dHD1_CD1_NE1 = getAngle(name, HD1, CD1, NE1);
1680         double dHE1_NE1_CD1 = getAngle(name, HE1, NE1, CD1);
1681         double dHE1_NE1_CE2 = getAngle(name, HE1, NE1, CE2);
1682         double dHE3_CE3_CD2 = getAngle(name, HE3, CE3, CD2);
1683         double dHE3_CE3_CZ3 = getAngle(name, HE3, CE3, CZ3);
1684         double dHZ2_CZ2_CE2 = getAngle(name, HZ2, CZ2, CE2);
1685         double dHZ2_CZ2_CH2 = getAngle(name, HZ2, CZ2, CH2);
1686         double dHZ3_CZ3_CE3 = getAngle(name, HZ3, CZ3, CE3);
1687         double dHZ3_CZ3_CH2 = getAngle(name, HZ3, CZ3, CH2);
1688         double dHH2_CH2_CZ2 = getAngle(name, HH2, CH2, CZ2);
1689         double dHH2_CH2_CZ3 = getAngle(name, HH2, CH2, CZ3);
1690 
1691         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1692         intxyz(CD1, CG, dCD1_CG, CB, dCD1_CG_CB, CA, rotamer.chi2, 0);
1693         intxyz(CD2, CG, dCD2_CG, CB, dCD2_CG_CB, CA, rotamer.chi2 + 180, 0);
1694         intxyz(NE1, CD1, dNE1_CD1, CG, dNE1_CD1_CG, CD2, 0.0, 0);
1695         intxyz(CE2, NE1, dCE2_NE1, CD1, dCE2_NE1_CD1, CG, 0.0, 0);
1696         intxyz(CE3, CD2, dCE3_CD2, CE2, dCE3_CD2_CE2, NE1, 180.0, 0);
1697         intxyz(CZ2, CE2, dCZ2_CE2, CD2, dCZ2_CE2_CD2, CE3, 0.0, 0);
1698         intxyz(CZ3, CE3, dCZ3_CE3, CD2, dCZ3_CE3_CD2, CE2, 0.0, 0);
1699         intxyz(CH2, CZ2, dCH2_CZ2, CE2, dCH2_CZ2_CE2, CD2, 0.0, 0);
1700         // Continue using 109.4 degrees for tetrahedral hydrogens.
1701         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1702         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1703         intxyz(HD1, CD1, dHD1_CD1, CG, dHD1_CD1_CG, NE1, dHD1_CD1_NE1, 3);
1704         intxyz(HE1, NE1, dHE1_NE1, CD1, dHE1_NE1_CD1, CE2, dHE1_NE1_CE2, 3);
1705         intxyz(HE3, CE3, dHE3_CE3, CD2, dHE3_CE3_CD2, CZ3, dHE3_CE3_CZ3, 3);
1706         intxyz(HZ2, CZ2, dHZ2_CZ2, CE2, dHZ2_CZ2_CE2, CH2, dHZ2_CZ2_CH2, 3);
1707         intxyz(HZ3, CZ3, dHZ3_CZ3, CE3, dHZ3_CZ3_CE3, CH2, dHZ3_CZ3_CH2, 3);
1708         intxyz(HH2, CH2, dHH2_CH2, CZ2, dHH2_CH2_CZ2, CZ3, dHH2_CH2_CZ3, 3);
1709         break;
1710       }
1711       case HIS: {
1712         Atom CA = (Atom) residue.getAtomNode("CA");
1713         Atom CB = (Atom) residue.getAtomNode("CB");
1714         Atom N = (Atom) residue.getAtomNode("N");
1715         Atom CG = (Atom) residue.getAtomNode("CG");
1716         Atom ND1 = (Atom) residue.getAtomNode("ND1");
1717         Atom CD2 = (Atom) residue.getAtomNode("CD2");
1718         Atom CE1 = (Atom) residue.getAtomNode("CE1");
1719         Atom NE2 = (Atom) residue.getAtomNode("NE2");
1720         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1721         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1722         Atom HD1 = (Atom) residue.getAtomNode("HD1");
1723         Atom HD2 = (Atom) residue.getAtomNode("HD2");
1724         Atom HE1 = (Atom) residue.getAtomNode("HE1");
1725         Atom HE2 = (Atom) residue.getAtomNode("HE2");
1726         Bond CG_CB = CG.getBond(CB);
1727         Bond ND1_CG = ND1.getBond(CG);
1728         Bond CD2_CG = CD2.getBond(CG);
1729         Bond CE1_ND1 = CE1.getBond(ND1);
1730         Bond NE2_CD2 = NE2.getBond(CD2);
1731         Bond HB_CB = HB2.getBond(CB);
1732         Bond HD1_ND1 = HD1.getBond(ND1);
1733         Bond HD2_CD2 = HD2.getBond(CD2);
1734         Bond HE1_CE1 = HE1.getBond(CE1);
1735         Bond HE2_NE2 = HE2.getBond(NE2);
1736         double dCG_CB = CG_CB.bondType.distance;
1737         double dND1_CG = ND1_CG.bondType.distance;
1738         double dCD2_CG = CD2_CG.bondType.distance;
1739         double dCE1_ND1 = CE1_ND1.bondType.distance;
1740         double dNE2_CD2 = NE2_CD2.bondType.distance;
1741         double dHB_CB = HB_CB.bondType.distance;
1742         double dHD1_ND1 = HD1_ND1.bondType.distance;
1743         double dHD2_CD2 = HD2_CD2.bondType.distance;
1744         double dHE1_CE1 = HE1_CE1.bondType.distance;
1745         double dHE2_NE2 = HE2_NE2.bondType.distance;
1746 
1747         double dCG_CB_CA = getAngle(name, CG, CB, CA);
1748         double dND1_CG_CB = getAngle(name, ND1, CG, CB);
1749         double dCD2_CG_CB = getAngle(name, CD2, CG, CB);
1750         double dCE1_ND1_CG = getAngle(name, CE1, ND1, CG);
1751         double dNE2_CD2_CG = getAngle(name, NE2, CD2, CG);
1752         double dHB_CB_CA = getAngle(name, HB2, CB, CA);
1753         double dHD1_ND1_CG = getAngle(name, HD1, ND1, CG);
1754         double dHD1_ND1_CE1 = getAngle(name, HD1, ND1, CE1);
1755         double dHD2_CD2_CG = getAngle(name, HD2, CD2, CG);
1756         double dHD2_CD2_NE2 = getAngle(name, HD2, CD2, NE2);
1757         double dHE1_CE1_ND1 = getAngle(name, HE1, CE1, ND1);
1758         double dHE1_CE1_NE2 = getAngle(name, HE1, CE1, NE2);
1759         double dHE2_NE2_CD2 = getAngle(name, HE2, NE2, CD2);
1760         double dHE2_NE2_CE1 = getAngle(name, HE2, NE2, CE1);
1761 
1762         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1763         intxyz(ND1, CG, dND1_CG, CB, dND1_CG_CB, CA, rotamer.chi2, 0);
1764         intxyz(CD2, CG, dCD2_CG, CB, dCD2_CG_CB, CA, rotamer.chi2 + 180, 0);
1765         intxyz(CE1, ND1, dCE1_ND1, CG, dCE1_ND1_CG, CD2, 0.0, 0);
1766         intxyz(NE2, CD2, dNE2_CD2, CG, dNE2_CD2_CG, ND1, 0.0, 0);
1767         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1768         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1769         intxyz(HD1, ND1, dHD1_ND1, CG, dHD1_ND1_CG, CE1, dHD1_ND1_CE1, 3);
1770         intxyz(HD2, CD2, dHD2_CD2, CG, dHD2_CD2_CG, NE2, dHD2_CD2_NE2, 3);
1771         intxyz(HE1, CE1, dHE1_CE1, ND1, dHE1_CE1_ND1, NE2, dHE1_CE1_NE2, 3);
1772         intxyz(HE2, NE2, dHE2_NE2, CD2, dHE2_NE2_CD2, CE1, dHE2_NE2_CE1, 3);
1773         break;
1774       }
1775       case HID: {
1776         Atom CA = (Atom) residue.getAtomNode("CA");
1777         Atom CB = (Atom) residue.getAtomNode("CB");
1778         Atom N = (Atom) residue.getAtomNode("N");
1779         Atom CG = (Atom) residue.getAtomNode("CG");
1780         Atom ND1 = (Atom) residue.getAtomNode("ND1");
1781         Atom CD2 = (Atom) residue.getAtomNode("CD2");
1782         Atom CE1 = (Atom) residue.getAtomNode("CE1");
1783         Atom NE2 = (Atom) residue.getAtomNode("NE2");
1784         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1785         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1786         Atom HD1 = (Atom) residue.getAtomNode("HD1");
1787         Atom HD2 = (Atom) residue.getAtomNode("HD2");
1788         Atom HE1 = (Atom) residue.getAtomNode("HE1");
1789         Bond CG_CB = CG.getBond(CB);
1790         Bond ND1_CG = ND1.getBond(CG);
1791         Bond CD2_CG = CD2.getBond(CG);
1792         Bond CE1_ND1 = CE1.getBond(ND1);
1793         Bond NE2_CD2 = NE2.getBond(CD2);
1794         Bond HB_CB = HB2.getBond(CB);
1795         Bond HD1_ND1 = HD1.getBond(ND1);
1796         Bond HD2_CD2 = HD2.getBond(CD2);
1797         Bond HE1_CE1 = HE1.getBond(CE1);
1798         double dCG_CB = CG_CB.bondType.distance;
1799         double dND1_CG = ND1_CG.bondType.distance;
1800         double dCD2_CG = CD2_CG.bondType.distance;
1801         double dCE1_ND1 = CE1_ND1.bondType.distance;
1802         double dNE2_CD2 = NE2_CD2.bondType.distance;
1803         double dHB_CB = HB_CB.bondType.distance;
1804         double dHD1_ND1 = HD1_ND1.bondType.distance;
1805         double dHD2_CD2 = HD2_CD2.bondType.distance;
1806         double dHE1_CE1 = HE1_CE1.bondType.distance;
1807 
1808         double dCG_CB_CA = getAngle(name, CG, CB, CA);
1809         double dND1_CG_CB = getAngle(name, ND1, CG, CB);
1810         double dCD2_CG_CB = getAngle(name, CD2, CG, CB);
1811         double dCE1_ND1_CG = getAngle(name, CE1, ND1, CG);
1812         double dNE2_CD2_CG = getAngle(name, NE2, CD2, CG);
1813         double dHB_CB_CA = getAngle(name, HB2, CB, CA);
1814         double dHD1_ND1_CG = getAngle(name, HD1, ND1, CG);
1815         double dHD1_ND1_CE1 = getAngle(name, HD1, ND1, CE1);
1816         double dHD2_CD2_CG = getAngle(name, HD2, CD2, CG);
1817         double dHD2_CD2_NE2 = getAngle(name, HD2, CD2, NE2);
1818         double dHE1_CE1_ND1 = getAngle(name, HE1, CE1, ND1);
1819         double dHE1_CE1_NE2 = getAngle(name, HE1, CE1, NE2);
1820 
1821         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1822         intxyz(ND1, CG, dND1_CG, CB, dND1_CG_CB, CA, rotamer.chi2, 0);
1823         intxyz(CD2, CG, dCD2_CG, CB, dCD2_CG_CB, CA, rotamer.chi2 + 180, 0);
1824         intxyz(CE1, ND1, dCE1_ND1, CG, dCE1_ND1_CG, CD2, 0.0, 0);
1825         intxyz(NE2, CD2, dNE2_CD2, CG, dNE2_CD2_CG, ND1, 0.0, 0);
1826         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1827         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1828         intxyz(HD1, ND1, dHD1_ND1, CG, dHD1_ND1_CG, CE1, dHD1_ND1_CE1, 3);
1829         intxyz(HD2, CD2, dHD2_CD2, CG, dHD2_CD2_CG, NE2, dHD2_CD2_NE2, 3);
1830         intxyz(HE1, CE1, dHE1_CE1, ND1, dHE1_CE1_ND1, NE2, dHE1_CE1_NE2, 3);
1831         if (rotamer.isTitrating) {
1832           // Place the HE2 atom (whose non-bonded interactions will be turned off).
1833           // This is to ensure the bond and angle energy values are constant.
1834           Atom HE2 = (Atom) residue.getAtomNode("HE2");
1835           Bond HE2_NE2 = HE2.getBond(NE2);
1836           double dHE2_NE2 = HE2_NE2.bondType.distance;
1837           double dHE2_NE2_CD2 = getAngle(name, HE2, NE2, CD2);
1838           double dHE2_NE2_CE1 = getAngle(name, HE2, NE2, CE1);
1839           intxyz(HE2, NE2, dHE2_NE2, CD2, dHE2_NE2_CD2, CE1, dHE2_NE2_CE1, 3);
1840         }
1841         break;
1842       }
1843       case HIE: {
1844         Atom CA = (Atom) residue.getAtomNode("CA");
1845         Atom CB = (Atom) residue.getAtomNode("CB");
1846         Atom N = (Atom) residue.getAtomNode("N");
1847         Atom CG = (Atom) residue.getAtomNode("CG");
1848         Atom ND1 = (Atom) residue.getAtomNode("ND1");
1849         Atom CD2 = (Atom) residue.getAtomNode("CD2");
1850         Atom CE1 = (Atom) residue.getAtomNode("CE1");
1851         Atom NE2 = (Atom) residue.getAtomNode("NE2");
1852         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1853         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1854         Atom HD2 = (Atom) residue.getAtomNode("HD2");
1855         Atom HE1 = (Atom) residue.getAtomNode("HE1");
1856         Atom HE2 = (Atom) residue.getAtomNode("HE2");
1857         Bond CG_CB = CG.getBond(CB);
1858         Bond ND1_CG = ND1.getBond(CG);
1859         Bond CD2_CG = CD2.getBond(CG);
1860         Bond CE1_ND1 = CE1.getBond(ND1);
1861         Bond NE2_CD2 = NE2.getBond(CD2);
1862         Bond HB_CB = HB2.getBond(CB);
1863         Bond HD2_CD2 = HD2.getBond(CD2);
1864         Bond HE1_CE1 = HE1.getBond(CE1);
1865         Bond HE2_NE2 = HE2.getBond(NE2);
1866         double dCG_CB = CG_CB.bondType.distance;
1867         double dND1_CG = ND1_CG.bondType.distance;
1868         double dCD2_CG = CD2_CG.bondType.distance;
1869         double dCE1_ND1 = CE1_ND1.bondType.distance;
1870         double dNE2_CD2 = NE2_CD2.bondType.distance;
1871         double dHB_CB = HB_CB.bondType.distance;
1872         double dHD2_CD2 = HD2_CD2.bondType.distance;
1873         double dHE1_CE1 = HE1_CE1.bondType.distance;
1874         double dHE2_NE2 = HE2_NE2.bondType.distance;
1875 
1876         double dCG_CB_CA = getAngle(name, CG, CB, CA);
1877         double dND1_CG_CB = getAngle(name, ND1, CG, CB);
1878         double dCD2_CG_CB = getAngle(name, CD2, CG, CB);
1879         double dCE1_ND1_CG = getAngle(name, CE1, ND1, CG);
1880         double dNE2_CD2_CG = getAngle(name, NE2, CD2, CG);
1881         double dHB_CB_CA = getAngle(name, HB2, CB, CA);
1882         double dHD2_CD2_CG = getAngle(name, HD2, CD2, CG);
1883         double dHD2_CD2_NE2 = getAngle(name, HD2, CD2, NE2);
1884         double dHE1_CE1_ND1 = getAngle(name, HE1, CE1, ND1);
1885         double dHE1_CE1_NE2 = getAngle(name, HE1, CE1, NE2);
1886         double dHE2_NE2_CD2 = getAngle(name, HE2, NE2, CD2);
1887         double dHE2_NE2_CE1 = getAngle(name, HE2, NE2, CE1);
1888 
1889         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1890         intxyz(ND1, CG, dND1_CG, CB, dND1_CG_CB, CA, rotamer.chi2, 0);
1891         intxyz(CD2, CG, dCD2_CG, CB, dCD2_CG_CB, CA, rotamer.chi2 + 180, 0);
1892         intxyz(CE1, ND1, dCE1_ND1, CG, dCE1_ND1_CG, CD2, 0.0, 0);
1893         intxyz(NE2, CD2, dNE2_CD2, CG, dNE2_CD2_CG, ND1, 0.0, 0);
1894         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
1895         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
1896         intxyz(HD2, CD2, dHD2_CD2, CG, dHD2_CD2_CG, NE2, dHD2_CD2_NE2, 3);
1897         intxyz(HE1, CE1, dHE1_CE1, ND1, dHE1_CE1_ND1, NE2, dHE1_CE1_NE2, 3);
1898         intxyz(HE2, NE2, dHE2_NE2, CD2, dHE2_NE2_CD2, CE1, dHE2_NE2_CE1, 3);
1899         if (rotamer.isTitrating) {
1900           // Place the HD1 atom (whose non-bonded interactions will be turned off).
1901           // This is to ensure the bond and angle energy values are constant.
1902           Atom HD1 = (Atom) residue.getAtomNode("HD1");
1903           Bond HD1_ND1 = HD1.getBond(ND1);
1904           double dHD1_ND1 = HD1_ND1.bondType.distance;
1905           double dHD1_ND1_CG = getAngle(name, HD1, ND1, CG);
1906           double dHD1_ND1_CE1 = getAngle(name, HD1, ND1, CE1);
1907           intxyz(HD1, ND1, dHD1_ND1, CG, dHD1_ND1_CG, CE1, dHD1_ND1_CE1, 3);
1908         }
1909         break;
1910       }
1911       case ASP: {
1912         Atom CA = (Atom) residue.getAtomNode("CA");
1913         Atom CB = (Atom) residue.getAtomNode("CB");
1914         Atom N = (Atom) residue.getAtomNode("N");
1915         Atom CG = (Atom) residue.getAtomNode("CG");
1916         Atom OD1 = (Atom) residue.getAtomNode("OD1");
1917         Atom OD2 = (Atom) residue.getAtomNode("OD2");
1918         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1919         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1920         Bond CG_CB = CG.getBond(CB);
1921         Bond OD1_CG = OD1.getBond(CG);
1922         Bond OD2_CG = OD2.getBond(CG);
1923         Bond HB_CB = HB2.getBond(CB);
1924         double dCG_CB = CG_CB.bondType.distance;
1925         double dOD1_CG = OD1_CG.bondType.distance;
1926         double dOD2_CG = OD2_CG.bondType.distance;
1927         double dHB_CB = HB_CB.bondType.distance;
1928 
1929         Angle CG_CB_CA = CG.getAngle(CB, CA);
1930         Angle OD1_CG_CB = OD1.getAngle(CG, CB);
1931         Angle OD2_CG_CB = OD2.getAngle(CG, CB);
1932         Angle HB_CB_CA = HB2.getAngle(CB, CA);
1933         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
1934         double dOD1_CG_CB = OD1_CG_CB.angleType.angle[OD1_CG_CB.nh];
1935         double dOD2_CG_CB = OD2_CG_CB.angleType.angle[OD2_CG_CB.nh];
1936         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1937 
1938         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1939         intxyz(OD1, CG, dOD1_CG, CB, dOD1_CG_CB, CA, 0.0, 0);
1940         intxyz(OD2, CG, dOD2_CG, CB, dOD2_CG_CB, OD1, 126.0, 1);
1941         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 107.9, 1);
1942         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 107.9, -1);
1943         if (rotamer.isTitrating) {
1944           // Place the HD2 atom (whose non-bonded interactions will be turned off).
1945           // This is to ensure the bond and angle energy values are constant.
1946           Atom HD2 = (Atom) residue.getAtomNode("HD2");
1947           Bond HD2_OD2 = HD2.getBond(OD2);
1948           double dHD2_OD2 = HD2_OD2.bondType.distance;
1949           Angle HD2_OD2_CG = HD2.getAngle(OD2, CG);
1950           double dHD2_OD2_CG = HD2_OD2_CG.angleType.angle[HD2_OD2_CG.nh];
1951           intxyz(HD2, OD2, dHD2_OD2, CG, dHD2_OD2_CG, OD1, 0.0, 0);
1952         }
1953         break;
1954       }
1955       case ASH: {
1956         Atom CA = (Atom) residue.getAtomNode("CA");
1957         Atom CB = (Atom) residue.getAtomNode("CB");
1958         Atom N = (Atom) residue.getAtomNode("N");
1959         Atom CG = (Atom) residue.getAtomNode("CG");
1960         Atom OD1 = (Atom) residue.getAtomNode("OD1");
1961         Atom OD2 = (Atom) residue.getAtomNode("OD2");
1962         Atom HB2 = (Atom) residue.getAtomNode("HB2");
1963         Atom HB3 = (Atom) residue.getAtomNode("HB3");
1964         Atom HD2 = (Atom) residue.getAtomNode("HD2");
1965         Bond CG_CB = CG.getBond(CB);
1966         Bond OD1_CG = OD1.getBond(CG);
1967         Bond OD2_CG = OD2.getBond(CG);
1968         Bond HB_CB = HB2.getBond(CB);
1969         Bond HD2_OD2 = HD2.getBond(OD2);
1970         double dCG_CB = CG_CB.bondType.distance;
1971         double dOD1_CG = OD1_CG.bondType.distance;
1972         double dOD2_CG = OD2_CG.bondType.distance;
1973         double dHB_CB = HB_CB.bondType.distance;
1974         double dHD2_OD2 = HD2_OD2.bondType.distance;
1975 
1976         Angle CG_CB_CA = CG.getAngle(CB, CA);
1977         Angle OD1_CG_CB = OD1.getAngle(CG, CB);
1978         Angle OD2_CG_CB = OD2.getAngle(CG, CB);
1979         Angle HB_CB_CA = HB2.getAngle(CB, CA);
1980         Angle HD2_OD2_CG = HD2.getAngle(OD2, CG);
1981 
1982         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
1983         double dOD1_CG_CB = OD1_CG_CB.angleType.angle[OD1_CG_CB.nh];
1984         double dOD2_CG_CB = OD2_CG_CB.angleType.angle[OD2_CG_CB.nh];
1985         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
1986         double dHD2_OD2_CG = HD2_OD2_CG.angleType.angle[HD2_OD2_CG.nh];
1987         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
1988         intxyz(OD1, CG, dOD1_CG, CB, dOD1_CG_CB, CA, rotamer.chi2, 0);
1989         intxyz(OD2, CG, dOD2_CG, CB, dOD2_CG_CB, OD1, 126.0, 1);
1990         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 107.9, 1);
1991         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 107.9, -1);
1992         intxyz(HD2, OD2, dHD2_OD2, CG, dHD2_OD2_CG, OD1, 0, 0);
1993         break;
1994       }
1995       case ASN: {
1996         Atom CA = (Atom) residue.getAtomNode("CA");
1997         Atom CB = (Atom) residue.getAtomNode("CB");
1998         Atom N = (Atom) residue.getAtomNode("N");
1999         Atom CG = (Atom) residue.getAtomNode("CG");
2000         Atom OD1 = (Atom) residue.getAtomNode("OD1");
2001         Atom ND2 = (Atom) residue.getAtomNode("ND2");
2002         Atom HB2 = (Atom) residue.getAtomNode("HB2");
2003         Atom HB3 = (Atom) residue.getAtomNode("HB3");
2004         Atom HD21 = (Atom) residue.getAtomNode("HD21");
2005         Atom HD22 = (Atom) residue.getAtomNode("HD22");
2006         Bond CG_CB = CG.getBond(CB);
2007         Bond OD1_CG = OD1.getBond(CG);
2008         Bond ND2_CG = ND2.getBond(CG);
2009         Bond HB_CB = HB2.getBond(CB);
2010         Bond HD2_ND2 = HD21.getBond(ND2);
2011         double dCG_CB = CG_CB.bondType.distance;
2012         double dOD1_CG = OD1_CG.bondType.distance;
2013         double dND2_CG = ND2_CG.bondType.distance;
2014         double dHB_CB = HB_CB.bondType.distance;
2015         double dHD2_ND2 = HD2_ND2.bondType.distance;
2016         Angle CG_CB_CA = CG.getAngle(CB, CA);
2017         Angle OD1_CG_CB = OD1.getAngle(CG, CB);
2018         Angle ND2_CG_CB = ND2.getAngle(CG, CB);
2019         Angle HB_CB_CA = HB2.getAngle(CB, CA);
2020         Angle HD2_ND2_CG = HD21.getAngle(ND2, CG);
2021         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
2022         double dOD1_CG_CB = OD1_CG_CB.angleType.angle[OD1_CG_CB.nh];
2023         double dND2_CG_CB = ND2_CG_CB.angleType.angle[ND2_CG_CB.nh];
2024         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
2025         double dHD2_ND2_CG = HD2_ND2_CG.angleType.angle[HD2_ND2_CG.nh];
2026         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
2027         intxyz(OD1, CG, dOD1_CG, CB, dOD1_CG_CB, CA, rotamer.chi2, 0);
2028         intxyz(ND2, CG, dND2_CG, CB, dND2_CG_CB, OD1, 124.0, 1);
2029         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 107.9, 1);
2030         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 107.9, -1);
2031         intxyz(HD21, ND2, dHD2_ND2, CG, dHD2_ND2_CG, CB, 0.0, 0);
2032         intxyz(HD22, ND2, dHD2_ND2, CG, dHD2_ND2_CG, HD21, 120.0, 1);
2033         break;
2034       }
2035       case GLU: {
2036         Atom CA = (Atom) residue.getAtomNode("CA");
2037         Atom CB = (Atom) residue.getAtomNode("CB");
2038         Atom N = (Atom) residue.getAtomNode("N");
2039         Atom CG = (Atom) residue.getAtomNode("CG");
2040         Atom CD = (Atom) residue.getAtomNode("CD");
2041         Atom OE1 = (Atom) residue.getAtomNode("OE1");
2042         Atom OE2 = (Atom) residue.getAtomNode("OE2");
2043         Atom HB2 = (Atom) residue.getAtomNode("HB2");
2044         Atom HB3 = (Atom) residue.getAtomNode("HB3");
2045         Atom HG2 = (Atom) residue.getAtomNode("HG2");
2046         Atom HG3 = (Atom) residue.getAtomNode("HG3");
2047         Bond CG_CB = CG.getBond(CB);
2048         Bond CD_CG = CD.getBond(CG);
2049         Bond OE1_CD = OE1.getBond(CD);
2050         Bond OE2_CD = OE2.getBond(CD);
2051         Bond HB_CB = HB2.getBond(CB);
2052         Bond HG_CG = HG2.getBond(CG);
2053         double dCG_CB = CG_CB.bondType.distance;
2054         double dCD_CG = CD_CG.bondType.distance;
2055         double dOE1_CD = OE1_CD.bondType.distance;
2056         double dOE2_CD = OE2_CD.bondType.distance;
2057         double dHB_CB = HB_CB.bondType.distance;
2058         double dHG_CG = HG_CG.bondType.distance;
2059         Angle CG_CB_CA = CG.getAngle(CB, CA);
2060         Angle CD_CG_CB = CD.getAngle(CG, CB);
2061         Angle OE1_CD_CG = OE1.getAngle(CD, CG);
2062         Angle OE2_CD_CG = OE2.getAngle(CD, CG);
2063         Angle HB_CB_CA = HB2.getAngle(CB, CA);
2064         Angle HG_CG_CB = HG2.getAngle(CG, CB);
2065         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
2066         double dCD_CG_CB = CD_CG_CB.angleType.angle[CD_CG_CB.nh];
2067         double dOE1_CD_CG = OE1_CD_CG.angleType.angle[OE1_CD_CG.nh];
2068         double dOE2_CD_CG = OE2_CD_CG.angleType.angle[OE2_CD_CG.nh];
2069         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
2070         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
2071         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
2072         intxyz(CD, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
2073         intxyz(OE1, CD, dOE1_CD, CG, dOE1_CD_CG, CB, rotamer.chi3, 0);
2074         intxyz(OE2, CD, dOE2_CD, CG, dOE2_CD_CG, OE1, 126.0, 1);
2075         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
2076         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
2077         intxyz(HG2, CG, dHG_CG, CB, dHG_CG_CB, CD, 107.9, 1);
2078         intxyz(HG3, CG, dHG_CG, CB, dHG_CG_CB, CD, 107.9, -1);
2079         if (rotamer.isTitrating) {
2080           // Place the HE2 atom (whose non-bonded interactions will be turned off).
2081           // This is to ensure the bond and angle energy values are constant.
2082           Atom HE2 = (Atom) residue.getAtomNode("HE2");
2083           Bond HE2_OE2 = HE2.getBond(OE2);
2084           double dHE2_OE2 = HE2_OE2.bondType.distance;
2085           Angle HE2_OE2_CD = HE2.getAngle(OE2, CD);
2086           double dHE2_OE2_CD = HE2_OE2_CD.angleType.angle[HE2_OE2_CD.nh];
2087           intxyz(HE2, OE2, dHE2_OE2, CD, dHE2_OE2_CD, OE1, 0.0, 0);
2088         }
2089         break;
2090       }
2091       case GLH: {
2092         Atom CA = (Atom) residue.getAtomNode("CA");
2093         Atom CB = (Atom) residue.getAtomNode("CB");
2094         Atom N = (Atom) residue.getAtomNode("N");
2095         Atom CG = (Atom) residue.getAtomNode("CG");
2096         Atom CD = (Atom) residue.getAtomNode("CD");
2097         Atom OE1 = (Atom) residue.getAtomNode("OE1");
2098         Atom OE2 = (Atom) residue.getAtomNode("OE2");
2099         Atom HB2 = (Atom) residue.getAtomNode("HB2");
2100         Atom HB3 = (Atom) residue.getAtomNode("HB3");
2101         Atom HG2 = (Atom) residue.getAtomNode("HG2");
2102         Atom HG3 = (Atom) residue.getAtomNode("HG3");
2103         Atom HE2 = (Atom) residue.getAtomNode("HE2");
2104         Bond CG_CB = CG.getBond(CB);
2105         Bond CD_CG = CD.getBond(CG);
2106         Bond OE1_CD = OE1.getBond(CD);
2107         Bond OE2_CD = OE2.getBond(CD);
2108         Bond HB_CB = HB2.getBond(CB);
2109         Bond HG_CG = HG2.getBond(CG);
2110         Bond HE2_OE2 = HE2.getBond(OE2);
2111         double dCG_CB = CG_CB.bondType.distance;
2112         double dCD_CG = CD_CG.bondType.distance;
2113         double dOE1_CD = OE1_CD.bondType.distance;
2114         double dOE2_CD = OE2_CD.bondType.distance;
2115         double dHB_CB = HB_CB.bondType.distance;
2116         double dHG_CG = HG_CG.bondType.distance;
2117         double dHE2_OE2 = HE2_OE2.bondType.distance;
2118         Angle CG_CB_CA = CG.getAngle(CB, CA);
2119         Angle CD_CG_CB = CD.getAngle(CG, CB);
2120         Angle OE1_CD_CG = OE1.getAngle(CD, CG);
2121         Angle OE2_CD_CG = OE2.getAngle(CD, CG);
2122         Angle HB_CB_CA = HB2.getAngle(CB, CA);
2123         Angle HG_CG_CB = HG2.getAngle(CG, CB);
2124         Angle HE2_OE2_CD = HE2.getAngle(OE2, CD);
2125         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
2126         double dCD_CG_CB = CD_CG_CB.angleType.angle[CD_CG_CB.nh];
2127         double dOE1_CD_CG = OE1_CD_CG.angleType.angle[OE1_CD_CG.nh];
2128         double dOE2_CD_CG = OE2_CD_CG.angleType.angle[OE2_CD_CG.nh];
2129         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
2130         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
2131         double dHE2_OE2_CD = HE2_OE2_CD.angleType.angle[HE2_OE2_CD.nh];
2132         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
2133         intxyz(CD, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
2134         intxyz(OE1, CD, dOE1_CD, CG, dOE1_CD_CG, CB, rotamer.chi3, 0);
2135         intxyz(OE2, CD, dOE2_CD, CG, dOE2_CD_CG, OE1, 126.0, 1);
2136         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
2137         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
2138         intxyz(HG2, CG, dHG_CG, CB, dHG_CG_CB, CD, 107.9, 1);
2139         intxyz(HG3, CG, dHG_CG, CB, dHG_CG_CB, CD, 107.9, -1);
2140         intxyz(HE2, OE2, dHE2_OE2, CD, dHE2_OE2_CD, OE1, 0.0, 0);
2141         break;
2142       }
2143       case GLN: {
2144         Atom CA = (Atom) residue.getAtomNode("CA");
2145         Atom CB = (Atom) residue.getAtomNode("CB");
2146         Atom N = (Atom) residue.getAtomNode("N");
2147         Atom CG = (Atom) residue.getAtomNode("CG");
2148         Atom CD = (Atom) residue.getAtomNode("CD");
2149         Atom OE1 = (Atom) residue.getAtomNode("OE1");
2150         Atom NE2 = (Atom) residue.getAtomNode("NE2");
2151         Atom HB2 = (Atom) residue.getAtomNode("HB2");
2152         Atom HB3 = (Atom) residue.getAtomNode("HB3");
2153         Atom HG2 = (Atom) residue.getAtomNode("HG2");
2154         Atom HG3 = (Atom) residue.getAtomNode("HG3");
2155         Atom HE21 = (Atom) residue.getAtomNode("HE21");
2156         Atom HE22 = (Atom) residue.getAtomNode("HE22");
2157         Bond CG_CB = CG.getBond(CB);
2158         Bond CD_CG = CD.getBond(CG);
2159         Bond OE1_CD = OE1.getBond(CD);
2160         Bond NE2_CD = NE2.getBond(CD);
2161         Bond HB_CB = HB2.getBond(CB);
2162         Bond HG_CG = HG2.getBond(CG);
2163         Bond HE2_NE2 = HE21.getBond(NE2);
2164         double dCG_CB = CG_CB.bondType.distance;
2165         double dCD_CG = CD_CG.bondType.distance;
2166         double dOE1_CD = OE1_CD.bondType.distance;
2167         double dNE2_CD = NE2_CD.bondType.distance;
2168         double dHB_CB = HB_CB.bondType.distance;
2169         double dHG_CG = HG_CG.bondType.distance;
2170         double dHE2_NE2 = HE2_NE2.bondType.distance;
2171         Angle CG_CB_CA = CG.getAngle(CB, CA);
2172         Angle CD_CG_CB = CD.getAngle(CG, CB);
2173         Angle OE1_CD_CG = OE1.getAngle(CD, CG);
2174         Angle NE2_CD_CG = NE2.getAngle(CD, CG);
2175         Angle HB_CB_CA = HB2.getAngle(CB, CA);
2176         Angle HG_CG_CB = HG2.getAngle(CG, CB);
2177         Angle HE2_NE2_CD = HE21.getAngle(NE2, CD);
2178         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
2179         double dCD_CG_CB = CD_CG_CB.angleType.angle[CD_CG_CB.nh];
2180         double dOE1_CD_CG = OE1_CD_CG.angleType.angle[OE1_CD_CG.nh];
2181         double dNE2_CD_CG = NE2_CD_CG.angleType.angle[NE2_CD_CG.nh];
2182         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
2183         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
2184         double dHE2_NE2_CD = HE2_NE2_CD.angleType.angle[HE2_NE2_CD.nh];
2185         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
2186         intxyz(CD, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
2187         intxyz(OE1, CD, dOE1_CD, CG, dOE1_CD_CG, CB, rotamer.chi3, 0);
2188         intxyz(NE2, CD, dNE2_CD, CG, dNE2_CD_CG, OE1, 124.0, 1);
2189         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
2190         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
2191         intxyz(HG2, CG, dHG_CG, CB, dHG_CG_CB, CD, 107.9, 1);
2192         intxyz(HG3, CG, dHG_CG, CB, dHG_CG_CB, CD, 107.9, -1);
2193         intxyz(HE21, NE2, dHE2_NE2, CD, dHE2_NE2_CD, CG, 0.0, 0);
2194         intxyz(HE22, NE2, dHE2_NE2, CD, dHE2_NE2_CD, HE21, 120.0, 1);
2195         break;
2196       }
2197       case MET: {
2198         Atom CA = (Atom) residue.getAtomNode("CA");
2199         Atom CB = (Atom) residue.getAtomNode("CB");
2200         Atom N = (Atom) residue.getAtomNode("N");
2201         Atom CG = (Atom) residue.getAtomNode("CG");
2202         Atom SD = (Atom) residue.getAtomNode("SD");
2203         Atom CE = (Atom) residue.getAtomNode("CE");
2204         Atom HB2 = (Atom) residue.getAtomNode("HB2");
2205         Atom HB3 = (Atom) residue.getAtomNode("HB3");
2206         Atom HG2 = (Atom) residue.getAtomNode("HG2");
2207         Atom HG3 = (Atom) residue.getAtomNode("HG3");
2208         Atom HE1 = (Atom) residue.getAtomNode("HE1");
2209         Atom HE2 = (Atom) residue.getAtomNode("HE2");
2210         Atom HE3 = (Atom) residue.getAtomNode("HE3");
2211         Bond CG_CB = CG.getBond(CB);
2212         Bond SD_CG = SD.getBond(CG);
2213         Bond CE_SD = CE.getBond(SD);
2214         Bond HB_CB = HB2.getBond(CB);
2215         Bond HG_CG = HG2.getBond(CG);
2216         Bond HE_CE = HE1.getBond(CE);
2217         double dCG_CB = CG_CB.bondType.distance;
2218         double dSD_CG = SD_CG.bondType.distance;
2219         double dCE_SD = CE_SD.bondType.distance;
2220         double dHB_CB = HB_CB.bondType.distance;
2221         double dHG_CG = HG_CG.bondType.distance;
2222         double dHE_CE = HE_CE.bondType.distance;
2223         Angle CG_CB_CA = CG.getAngle(CB, CA);
2224         Angle SD_CG_CB = SD.getAngle(CG, CB);
2225         Angle CE_SD_CG = CE.getAngle(SD, CG);
2226         Angle HB_CB_CA = HB2.getAngle(CB, CA);
2227         Angle HG_CG_CB = HG2.getAngle(CG, CB);
2228         Angle HE_CE_SD = HE1.getAngle(CE, SD);
2229         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
2230         double dSD_CG_CB = SD_CG_CB.angleType.angle[SD_CG_CB.nh];
2231         double dCE_SD_CG = CE_SD_CG.angleType.angle[CE_SD_CG.nh];
2232         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
2233         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
2234         double dHE_CE_SD = HE_CE_SD.angleType.angle[HE_CE_SD.nh];
2235         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
2236         intxyz(SD, CG, dSD_CG, CB, dSD_CG_CB, CA, rotamer.chi2, 0);
2237         intxyz(CE, SD, dCE_SD, CG, dCE_SD_CG, CB, rotamer.chi3, 0);
2238         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
2239         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
2240         intxyz(HG2, CG, dHG_CG, CB, dHG_CG_CB, SD, 112.0, 1);
2241         intxyz(HG3, CG, dHG_CG, CB, dHG_CG_CB, SD, 112.0, -1);
2242         intxyz(HE1, CE, dHE_CE, SD, dHE_CE_SD, CG, 180.0, 0);
2243         intxyz(HE2, CE, dHE_CE, SD, dHE_CE_SD, HE1, 109.4, 1);
2244         intxyz(HE3, CE, dHE_CE, SD, dHE_CE_SD, HE1, 109.4, -1);
2245         break;
2246       }
2247       case LYS: {
2248         Atom CA = (Atom) residue.getAtomNode("CA");
2249         Atom CB = (Atom) residue.getAtomNode("CB");
2250         Atom N = (Atom) residue.getAtomNode("N");
2251         Atom CG = (Atom) residue.getAtomNode("CG");
2252         Atom CD = (Atom) residue.getAtomNode("CD");
2253         Atom CE = (Atom) residue.getAtomNode("CE");
2254         Atom NZ = (Atom) residue.getAtomNode("NZ");
2255         Atom HB2 = (Atom) residue.getAtomNode("HB2");
2256         Atom HB3 = (Atom) residue.getAtomNode("HB3");
2257         Atom HG2 = (Atom) residue.getAtomNode("HG2");
2258         Atom HG3 = (Atom) residue.getAtomNode("HG3");
2259         Atom HD2 = (Atom) residue.getAtomNode("HD2");
2260         Atom HD3 = (Atom) residue.getAtomNode("HD3");
2261         Atom HE2 = (Atom) residue.getAtomNode("HE2");
2262         Atom HE3 = (Atom) residue.getAtomNode("HE3");
2263         Atom HZ1 = (Atom) residue.getAtomNode("HZ1");
2264         Atom HZ2 = (Atom) residue.getAtomNode("HZ2");
2265         Atom HZ3 = (Atom) residue.getAtomNode("HZ3");
2266         Bond CG_CB = CG.getBond(CB);
2267         Bond CD_CG = CD.getBond(CG);
2268         Bond CE_CD = CE.getBond(CD);
2269         Bond NZ_CE = NZ.getBond(CE);
2270         Bond HB_CB = HB2.getBond(CB);
2271         Bond HG_CG = HG2.getBond(CG);
2272         Bond HD_CD = HD2.getBond(CD);
2273         Bond HE_CE = HE2.getBond(CE);
2274         Bond HZ_NZ = HZ1.getBond(NZ);
2275         double dCG_CB = CG_CB.bondType.distance;
2276         double dCD_CG = CD_CG.bondType.distance;
2277         double dCE_CD = CE_CD.bondType.distance;
2278         double dNZ_CE = NZ_CE.bondType.distance;
2279         double dHB_CB = HB_CB.bondType.distance;
2280         double dHG_CG = HG_CG.bondType.distance;
2281         double dHD_CD = HD_CD.bondType.distance;
2282         double dHE_CE = HE_CE.bondType.distance;
2283         double dHZ_NZ = HZ_NZ.bondType.distance;
2284         Angle CG_CB_CA = CG.getAngle(CB, CA);
2285         Angle CD_CG_CB = CD.getAngle(CG, CB);
2286         Angle CE_CD_CG = CE.getAngle(CD, CG);
2287         Angle NZ_CE_CD = NZ.getAngle(CE, CD);
2288         Angle HB_CB_CA = HB2.getAngle(CB, CA);
2289         Angle HG_CG_CB = HG2.getAngle(CG, CB);
2290         Angle HD_CD_CG = HD2.getAngle(CD, CG);
2291         Angle HE_CE_CD = HE2.getAngle(CE, CD);
2292         Angle HZ_NZ_CE = HZ1.getAngle(NZ, CE);
2293         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
2294         double dCD_CG_CB = CD_CG_CB.angleType.angle[CD_CG_CB.nh];
2295         double dCE_CD_CG = CE_CD_CG.angleType.angle[CE_CD_CG.nh];
2296         double dNZ_CE_CD = NZ_CE_CD.angleType.angle[NZ_CE_CD.nh];
2297         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
2298         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
2299         double dHD_CD_CG = HD_CD_CG.angleType.angle[HD_CD_CG.nh];
2300         double dHE_CE_CD = HE_CE_CD.angleType.angle[HE_CE_CD.nh];
2301         double dHZ_NZ_CE = HZ_NZ_CE.angleType.angle[HZ_NZ_CE.nh];
2302         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
2303         intxyz(CD, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
2304         intxyz(CE, CD, dCE_CD, CG, dCE_CD_CG, CB, rotamer.chi3, 0);
2305         intxyz(NZ, CE, dNZ_CE, CD, dNZ_CE_CD, CG, rotamer.chi4, 0);
2306         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
2307         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
2308         intxyz(HG2, CG, dHG_CG, CB, dHG_CG_CB, CD, 109.4, 1);
2309         intxyz(HG3, CG, dHG_CG, CB, dHG_CG_CB, CD, 109.4, -1);
2310         intxyz(HD2, CD, dHD_CD, CG, dHD_CD_CG, CE, 109.4, 1);
2311         intxyz(HD3, CD, dHD_CD, CG, dHD_CD_CG, CE, 109.4, -1);
2312         intxyz(HE2, CE, dHE_CE, CD, dHE_CE_CD, NZ, 108.8, 1);
2313         intxyz(HE3, CE, dHE_CE, CD, dHE_CE_CD, NZ, 108.8, -1);
2314         intxyz(HZ1, NZ, dHZ_NZ, CE, dHZ_NZ_CE, CD, 180.0, 0);
2315         intxyz(HZ2, NZ, dHZ_NZ, CE, dHZ_NZ_CE, HZ1, 109.5, 1);
2316         intxyz(HZ3, NZ, dHZ_NZ, CE, dHZ_NZ_CE, HZ1, 109.5, -1);
2317         break;
2318       }
2319       case LYD: {
2320         Atom CA = (Atom) residue.getAtomNode("CA");
2321         Atom CB = (Atom) residue.getAtomNode("CB");
2322         Atom N = (Atom) residue.getAtomNode("N");
2323         Atom CG = (Atom) residue.getAtomNode("CG");
2324         Atom CD = (Atom) residue.getAtomNode("CD");
2325         Atom CE = (Atom) residue.getAtomNode("CE");
2326         Atom NZ = (Atom) residue.getAtomNode("NZ");
2327         Atom HB2 = (Atom) residue.getAtomNode("HB2");
2328         Atom HB3 = (Atom) residue.getAtomNode("HB3");
2329         Atom HG2 = (Atom) residue.getAtomNode("HG2");
2330         Atom HG3 = (Atom) residue.getAtomNode("HG3");
2331         Atom HD2 = (Atom) residue.getAtomNode("HD2");
2332         Atom HD3 = (Atom) residue.getAtomNode("HD3");
2333         Atom HE2 = (Atom) residue.getAtomNode("HE2");
2334         Atom HE3 = (Atom) residue.getAtomNode("HE3");
2335         Atom HZ1 = (Atom) residue.getAtomNode("HZ1");
2336         Atom HZ2 = (Atom) residue.getAtomNode("HZ2");
2337         Bond CG_CB = CG.getBond(CB);
2338         Bond CD_CG = CD.getBond(CG);
2339         Bond CE_CD = CE.getBond(CD);
2340         Bond NZ_CE = NZ.getBond(CE);
2341         Bond HB_CB = HB2.getBond(CB);
2342         Bond HG_CG = HG2.getBond(CG);
2343         Bond HD_CD = HD2.getBond(CD);
2344         Bond HE_CE = HE2.getBond(CE);
2345         Bond HZ_NZ = HZ1.getBond(NZ);
2346         double dCG_CB = CG_CB.bondType.distance;
2347         double dCD_CG = CD_CG.bondType.distance;
2348         double dCE_CD = CE_CD.bondType.distance;
2349         double dNZ_CE = NZ_CE.bondType.distance;
2350         double dHB_CB = HB_CB.bondType.distance;
2351         double dHG_CG = HG_CG.bondType.distance;
2352         double dHD_CD = HD_CD.bondType.distance;
2353         double dHE_CE = HE_CE.bondType.distance;
2354         double dHZ_NZ = HZ_NZ.bondType.distance;
2355         Angle CG_CB_CA = CG.getAngle(CB, CA);
2356         Angle CD_CG_CB = CD.getAngle(CG, CB);
2357         Angle CE_CD_CG = CE.getAngle(CD, CG);
2358         Angle NZ_CE_CD = NZ.getAngle(CE, CD);
2359         Angle HB_CB_CA = HB2.getAngle(CB, CA);
2360         Angle HG_CG_CB = HG2.getAngle(CG, CB);
2361         Angle HD_CD_CG = HD2.getAngle(CD, CG);
2362         Angle HE_CE_CD = HE2.getAngle(CE, CD);
2363         Angle HZ_NZ_CE = HZ1.getAngle(NZ, CE);
2364         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
2365         double dCD_CG_CB = CD_CG_CB.angleType.angle[CD_CG_CB.nh];
2366         double dCE_CD_CG = CE_CD_CG.angleType.angle[CE_CD_CG.nh];
2367         double dNZ_CE_CD = NZ_CE_CD.angleType.angle[NZ_CE_CD.nh];
2368         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
2369         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
2370         double dHD_CD_CG = HD_CD_CG.angleType.angle[HD_CD_CG.nh];
2371         double dHE_CE_CD = HE_CE_CD.angleType.angle[HE_CE_CD.nh];
2372         double dHZ_NZ_CE = HZ_NZ_CE.angleType.angle[HZ_NZ_CE.nh];
2373         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
2374         intxyz(CD, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
2375         intxyz(CE, CD, dCE_CD, CG, dCE_CD_CG, CB, rotamer.chi3, 0);
2376         intxyz(NZ, CE, dNZ_CE, CD, dNZ_CE_CD, CG, rotamer.chi4, 0);
2377         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
2378         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
2379         intxyz(HG2, CG, dHG_CG, CB, dHG_CG_CB, CD, 109.4, 1);
2380         intxyz(HG3, CG, dHG_CG, CB, dHG_CG_CB, CD, 109.4, -1);
2381         intxyz(HD2, CD, dHD_CD, CG, dHD_CD_CG, CE, 109.4, 1);
2382         intxyz(HD3, CD, dHD_CD, CG, dHD_CD_CG, CE, 109.4, -1);
2383         intxyz(HE2, CE, dHE_CE, CD, dHE_CE_CD, NZ, 108.8, 1);
2384         intxyz(HE3, CE, dHE_CE, CD, dHE_CE_CD, NZ, 108.8, -1);
2385         intxyz(HZ1, NZ, dHZ_NZ, CE, dHZ_NZ_CE, CD, 180.0, 0);
2386         intxyz(HZ2, NZ, dHZ_NZ, CE, dHZ_NZ_CE, HZ1, 109.5, 1);
2387         if (rotamer.isTitrating) {
2388           // Place the HZ3 atom (whose non-bonded interactions will be turned off).
2389           // This is to ensure the bond and angle energy values are constant.
2390           Atom HZ3 = (Atom) residue.getAtomNode("HZ3");
2391           intxyz(HZ3, NZ, dHZ_NZ, CE, dHZ_NZ_CE, HZ1, 109.5, -1);
2392         }
2393         break;
2394       }
2395       case ARG: {
2396         Atom CA = (Atom) residue.getAtomNode("CA");
2397         Atom CB = (Atom) residue.getAtomNode("CB");
2398         Atom N = (Atom) residue.getAtomNode("N");
2399         Atom CG = (Atom) residue.getAtomNode("CG");
2400         Atom CD = (Atom) residue.getAtomNode("CD");
2401         Atom NE = (Atom) residue.getAtomNode("NE");
2402         Atom CZ = (Atom) residue.getAtomNode("CZ");
2403         Atom NH1 = (Atom) residue.getAtomNode("NH1");
2404         Atom NH2 = (Atom) residue.getAtomNode("NH2");
2405         Atom HB2 = (Atom) residue.getAtomNode("HB2");
2406         Atom HB3 = (Atom) residue.getAtomNode("HB3");
2407         Atom HG2 = (Atom) residue.getAtomNode("HG2");
2408         Atom HG3 = (Atom) residue.getAtomNode("HG3");
2409         Atom HD2 = (Atom) residue.getAtomNode("HD2");
2410         Atom HD3 = (Atom) residue.getAtomNode("HD3");
2411         Atom HE = (Atom) residue.getAtomNode("HE");
2412         Atom HH11 = (Atom) residue.getAtomNode("HH11");
2413         Atom HH12 = (Atom) residue.getAtomNode("HH12");
2414         Atom HH21 = (Atom) residue.getAtomNode("HH21");
2415         Atom HH22 = (Atom) residue.getAtomNode("HH22");
2416         Bond CG_CB = CG.getBond(CB);
2417         Bond CD_CG = CD.getBond(CG);
2418         Bond NE_CD = NE.getBond(CD);
2419         Bond CZ_NE = CZ.getBond(NE);
2420         Bond NH_CZ = NH1.getBond(CZ);
2421         Bond HB_CB = HB2.getBond(CB);
2422         Bond HG_CG = HG2.getBond(CG);
2423         Bond HD_CD = HD2.getBond(CD);
2424         Bond HE_NE = HE.getBond(NE);
2425         Bond HH_NH = HH11.getBond(NH1);
2426         double dCG_CB = CG_CB.bondType.distance;
2427         double dCD_CG = CD_CG.bondType.distance;
2428         double dNE_CD = NE_CD.bondType.distance;
2429         double dCZ_NE = CZ_NE.bondType.distance;
2430         double dNH_CZ = NH_CZ.bondType.distance;
2431         double dHB_CB = HB_CB.bondType.distance;
2432         double dHG_CG = HG_CG.bondType.distance;
2433         double dHD_CD = HD_CD.bondType.distance;
2434         double dHE_NE = HE_NE.bondType.distance;
2435         double dHH_NH = HH_NH.bondType.distance;
2436         Angle CG_CB_CA = CG.getAngle(CB, CA);
2437         Angle CD_CG_CB = CD.getAngle(CG, CB);
2438         Angle NE_CD_CG = NE.getAngle(CD, CG);
2439         Angle CZ_NE_CD = CZ.getAngle(NE, CD);
2440         Angle NH_CZ_NE = NH1.getAngle(CZ, NE);
2441         Angle HB_CB_CA = HB2.getAngle(CB, CA);
2442         Angle HG_CG_CB = HG2.getAngle(CG, CB);
2443         Angle HD_CD_CG = HD2.getAngle(CD, CG);
2444         Angle HE_NE_CD = HE.getAngle(NE, CD);
2445         Angle HH_NH_CZ = HH11.getAngle(NH1, CZ);
2446         double dCG_CB_CA = CG_CB_CA.angleType.angle[CG_CB_CA.nh];
2447         double dCD_CG_CB = CD_CG_CB.angleType.angle[CD_CG_CB.nh];
2448         double dNE_CD_CG = NE_CD_CG.angleType.angle[NE_CD_CG.nh];
2449         double dCZ_NE_CD = CZ_NE_CD.angleType.angle[CZ_NE_CD.nh];
2450         double dNH_CZ_NE = NH_CZ_NE.angleType.angle[NH_CZ_NE.nh];
2451         double dHB_CB_CA = HB_CB_CA.angleType.angle[HB_CB_CA.nh];
2452         double dHG_CG_CB = HG_CG_CB.angleType.angle[HG_CG_CB.nh];
2453         double dHD_CD_CG = HD_CD_CG.angleType.angle[HD_CD_CG.nh];
2454         double dHE_NE_CD = HE_NE_CD.angleType.angle[HE_NE_CD.nh];
2455         double dHH_NH_CZ = HH_NH_CZ.angleType.angle[HH_NH_CZ.nh];
2456         intxyz(CG, CB, dCG_CB, CA, dCG_CB_CA, N, rotamer.chi1, 0);
2457         intxyz(CD, CG, dCD_CG, CB, dCD_CG_CB, CA, rotamer.chi2, 0);
2458         intxyz(NE, CD, dNE_CD, CG, dNE_CD_CG, CB, rotamer.chi3, 0);
2459         intxyz(CZ, NE, dCZ_NE, CD, dCZ_NE_CD, CG, rotamer.chi4, 0);
2460         intxyz(NH1, CZ, dNH_CZ, NE, dNH_CZ_NE, CD, 180, 0);
2461         intxyz(NH2, CZ, dNH_CZ, NE, dNH_CZ_NE, NH1, 120.0, 1);
2462         intxyz(HB2, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, 1);
2463         intxyz(HB3, CB, dHB_CB, CA, dHB_CB_CA, CG, 109.4, -1);
2464         intxyz(HG2, CG, dHG_CG, CB, dHG_CG_CB, CD, 109.4, 1);
2465         intxyz(HG3, CG, dHG_CG, CB, dHG_CG_CB, CD, 109.4, -1);
2466         intxyz(HD2, CD, dHD_CD, CG, dHD_CD_CG, NE, 109.4, 1);
2467         intxyz(HD3, CD, dHD_CD, CG, dHD_CD_CG, NE, 109.4, -1);
2468         intxyz(HE, NE, dHE_NE, CD, dHE_NE_CD, CZ, 120.0, 1);
2469         intxyz(HH11, NH1, dHH_NH, CZ, dHH_NH_CZ, NE, 180.0, 0);
2470         intxyz(HH12, NH1, dHH_NH, CZ, dHH_NH_CZ, HH11, 120.0, 1);
2471         intxyz(HH21, NH2, dHH_NH, CZ, dHH_NH_CZ, NE, 180.0, 0);
2472         intxyz(HH22, NH2, dHH_NH, CZ, dHH_NH_CZ, HH21, 120.0, 1);
2473         break;
2474       }
2475       case UNK:
2476         String resName = residue.getName().toUpperCase();
2477         if (nonstdRotCache.containsKey(resName)) {
2478           nonstdRotCache.get(resName).applyNonstdRotamer(residue, rotamer);
2479         }
2480         break;
2481       default:
2482         break;
2483     }
2484   }
2485 
2486   /**
2487    * Moves CZ of Phe/Tyr/Tyd to a mean position determined by both branches of the ring.
2488    *
2489    * @param resName Residue containing CZ.
2490    * @param CZ CZ to be placed.
2491    * @param CG CG atom.
2492    * @param CE1 CE1 atom.
2493    * @param CD1 CE2 atom.
2494    * @param CE2 CE2 atom.
2495    * @param CD2 CD2 atom.
2496    */
2497   private static void applyCZ(
2498       AminoAcid3 resName, Atom CZ, Atom CG, Atom CE1, Atom CD1, Atom CE2, Atom CD2) {
2499     CZ.moveTo(drawCZ(resName, CZ, CG, CE1, CD1, CE2, CD2));
2500   }
2501 
2502   /**
2503    * Draws the backbone of a nucleic acid Residue.
2504    *
2505    * @param residue Residue.
2506    * @param rotamer Rotamer being applied to Residue.
2507    * @param prevResidue Residue 5' of residue.
2508    */
2509   private static void applyNABackbone(Residue residue, Rotamer rotamer, Residue prevResidue) {
2510     Atom O3s = (Atom) residue.getAtomNode("O3'");
2511     Atom C3s = (Atom) residue.getAtomNode("C3'");
2512     Atom C4s = (Atom) residue.getAtomNode("C4'");
2513     Atom C5s = (Atom) residue.getAtomNode("C5'");
2514     Atom O5s = (Atom) residue.getAtomNode("O5'");
2515     /*
2516      * Two of the following atoms will be null, depending on whether
2517      * there is a previous residue, whether it is a 5' PO4 cap, or whether
2518      * it is a 5' OH cap.
2519      */
2520     Atom P = (Atom) residue.getAtomNode("P");
2521     Atom OP3 = (Atom) residue.getAtomNode("OP3");
2522     Atom HO5s = (Atom) residue.getAtomNode("HO5'");
2523 
2524     Bond C4s_C5s = C4s.getBond(C5s);
2525     double dC4s_C5s = C4s_C5s.bondType.distance;
2526     Angle C3s_C4s_C5s = C3s.getAngle(C4s, C5s);
2527     double dC3s_C4s_C5s = C3s_C4s_C5s.angleType.angle[C3s_C4s_C5s.nh];
2528     intxyz(C5s, C4s, dC4s_C5s, C3s, dC3s_C4s_C5s, O3s, rotamer.chi7, 0);
2529 
2530     Bond C5s_O5s = C5s.getBond(O5s);
2531     double dC5s_O5s = C5s_O5s.bondType.distance;
2532     Angle C4s_C5s_O5s = C4s.getAngle(C5s, O5s);
2533     double dC4s_C5s_O5s = C4s_C5s_O5s.angleType.angle[C4s_C5s_O5s.nh];
2534     intxyz(O5s, C5s, dC5s_O5s, C4s, dC4s_C5s_O5s, C3s, rotamer.chi6, 0);
2535 
2536     if (prevResidue == null) {
2537       // If capped by HO5s, draw HO5s and return. Else, assume OP3 capped.
2538       if (HO5s != null) {
2539         Bond O5s_HO5s = O5s.getBond(HO5s);
2540         double dO5s_HO5s = O5s_HO5s.bondType.distance;
2541         Angle C5s_O5s_HO5s = C5s.getAngle(O5s, HO5s);
2542         double dC5s_O5s_HO5s = C5s_O5s_HO5s.angleType.angle[C5s_O5s_HO5s.nh];
2543         intxyz(HO5s, O5s, dO5s_HO5s, C5s, dC5s_O5s_HO5s, C4s, rotamer.chi5, 0);
2544       } else {
2545         Bond O5s_P = O5s.getBond(P);
2546         double dO5s_P = O5s_P.bondType.distance;
2547         Angle C5s_O5s_P = C5s.getAngle(O5s, P);
2548         double dC5s_O5s_P = C5s_O5s_P.angleType.angle[C5s_O5s_P.nh];
2549         intxyz(P, O5s, dO5s_P, C5s, dC5s_O5s_P, C4s, rotamer.chi5, 0);
2550 
2551         Bond P_OP3 = P.getBond(OP3);
2552         double dP_OP3 = P_OP3.bondType.distance;
2553         Angle O5s_P_OP3 = C5s.getAngle(O5s, P);
2554         double dO5s_P_OP3 = O5s_P_OP3.angleType.angle[O5s_P_OP3.nh];
2555         intxyz(OP3, P, dP_OP3, O5s, dO5s_P_OP3, C5s, rotamer.chi4, 0);
2556       }
2557     } else {
2558       Bond O5s_P = O5s.getBond(P);
2559       double dO5s_P = O5s_P.bondType.distance;
2560       Angle C5s_O5s_P = C5s.getAngle(O5s, P);
2561       double dC5s_O5s_P = C5s_O5s_P.angleType.angle[C5s_O5s_P.nh];
2562       intxyz(P, O5s, dO5s_P, C5s, dC5s_O5s_P, C4s, rotamer.chi5, 0);
2563     }
2564   }
2565 
2566   /**
2567    * Applies Cartesian translations to nucleic acid backbone atoms to allow P to correctly join up
2568    * with O3' of the prior Residue.
2569    *
2570    * @param residue Residue.
2571    * @param prevResidue Residue 5' of residue.
2572    * @param rotamer Rotamer being applied to residue.
2573    * @param prevSugarPucker Expected sugar pucker of prevResidue.
2574    * @return The magnitude of any applied correction.
2575    */
2576   private static double applyNACorrections(
2577       Residue residue,
2578       Residue prevResidue,
2579       Rotamer rotamer,
2580       NucleicSugarPucker prevSugarPucker,
2581       boolean isDeoxy,
2582       boolean is3sTerminal) {
2583     // Backbone atoms of this residue to be adjusted
2584     Atom C3s = (Atom) residue.getAtomNode("C3'");
2585     Atom O4s = (Atom) residue.getAtomNode("O4'");
2586     Atom C4s = (Atom) residue.getAtomNode("C4'");
2587     Atom C5s = (Atom) residue.getAtomNode("C5'");
2588     Atom O5s = (Atom) residue.getAtomNode("O5'");
2589     Atom P = (Atom) residue.getAtomNode("P");
2590     Atom C1s = (Atom) residue.getAtomNode("C1'");
2591     Atom C2s = (Atom) residue.getAtomNode("C2'");
2592 
2593     // This reference being used solely to get ideal bond lengths & angles.
2594     Atom O3sPrev = (Atom) prevResidue.getAtomNode("O3'");
2595     double[] O3sPriorCoords;
2596 
2597     // Original position of O3' (i-1). Will be used to draw the correction
2598     // vector.
2599     if (prevSugarPucker == NucleicSugarPucker.C3_ENDO) {
2600       O3sPriorCoords = prevResidue.getO3sNorth();
2601     } else {
2602       O3sPriorCoords = prevResidue.getO3sSouth();
2603     } // TODO: Else-if block for the C3'-exo configuration of DNA sugars.
2604 
2605     Bond P_O3sPrev = P.getBond(O3sPrev);
2606     double dP_O3sPrev = P_O3sPrev.bondType.distance;
2607     Angle O5s_P_O3sPrev = O5s.getAngle(P, O3sPrev);
2608     double dO5s_P_O3sPrev = O5s_P_O3sPrev.angleType.angle[O5s_P_O3sPrev.nh];
2609     double[] O3sHypCoords =
2610         determineIntxyz(
2611             P.getXYZ(null),
2612             dP_O3sPrev,
2613             O5s.getXYZ(null),
2614             dO5s_P_O3sPrev,
2615             C5s.getXYZ(null),
2616             rotamer.chi4,
2617             0);
2618 
2619     // Index 5 will be full correction, and indices 0-4 will be 1/6 to 5/6
2620     // of the full correction in increasing order.  Index 6 is a 1/12
2621     // correction applied to other atoms in the sugar.
2622     double[][] corrections = new double[7][3];
2623     for (int i = 0; i < 3; i++) {
2624       corrections[5][i] = O3sPriorCoords[i] - O3sHypCoords[i];
2625       corrections[0][i] = (1.0 / 6.0) * corrections[5][i];
2626       corrections[1][i] = (1.0 / 3.0) * corrections[5][i];
2627       corrections[2][i] = (1.0 / 2.0) * corrections[5][i];
2628       corrections[3][i] = (2.0 / 3.0) * corrections[5][i];
2629       corrections[4][i] = (5.0 / 6.0) * corrections[5][i];
2630       corrections[6][i] = (1.0 / 12.0) * corrections[5][i];
2631     }
2632 
2633     /*
2634      * Move backbone atoms by an appropriate fraction of the correction
2635      * vector. Do this before checking the threshold, so that atoms are moved
2636      * in case that is needed before the exception gets thrown.
2637      */
2638     O4s.move(corrections[0]);
2639     C3s.move(corrections[0]);
2640     C4s.move(corrections[1]);
2641     C5s.move(corrections[2]);
2642     O5s.move(corrections[3]);
2643     P.move(corrections[4]);
2644     C1s.move(corrections[6]);
2645     C2s.move(corrections[6]);
2646 
2647     return ((corrections[5][0] * corrections[5][0])
2648         + (corrections[5][1] * corrections[5][1])
2649         + (corrections[5][2] * corrections[5][2]));
2650   }
2651 
2652   /**
2653    * Applies a nucleic acid Rotamer, returning the magnitude of the correction applied to make
2654    * residue i join i-1.
2655    *
2656    * <p>Note that the independent flag is separate from DEE independence: DEE independence is
2657    * preserved by applying corrections based on a non-variable set of coordinates, and is wholly
2658    * independent of what is happening to residue i-1.
2659    *
2660    * <p>Cannot presently handle 3' phosphate caps: I do not know what they would be labeled as in
2661    * PDB files. A template for how to handle 3' phosphate caps is written but commented out.
2662    *
2663    * @param residue Residue.
2664    * @param rotamer Rotamer to be applied to Residue.
2665    * @param independent Whether to draw NA rotamer independent of chain context.
2666    * @return Magnitude of the correction vector.
2667    */
2668   private static double applyNARotamer(Residue residue, Rotamer rotamer, boolean independent) {
2669     if (rotamer.isState) {
2670       applyState(residue, rotamer);
2671       return 0;
2672     }
2673     Residue prevResidue = residue.getPreviousResidue();
2674     boolean is3sTerminal = residue.getNextResidue() == null; // 3' terminal
2675     boolean isDeoxy = residue.getAtomNode("O2'") == null;
2676 
2677     // Note: chi values will generally be applied from chi7 to chi1.
2678     // Will have to add an else-if to handle DNA C3'-exo configurations.
2679     NucleicSugarPucker sugarPucker = NucleicSugarPucker.checkPucker(rotamer.chi7, isDeoxy);
2680     NucleicSugarPucker prevSugarPucker = NucleicSugarPucker.checkPucker(rotamer.chi1, isDeoxy);
2681 
2682     // Revert C1', O4', and C4' coordinates to PDB defaults.
2683     Atom C1s = (Atom) residue.getAtomNode("C1'");
2684     C1s.moveTo(residue.getC1sCoords());
2685     Atom O4s = (Atom) residue.getAtomNode("O4'");
2686     O4s.moveTo(residue.getO4sCoords());
2687     Atom C4s = (Atom) residue.getAtomNode("C4'");
2688     C4s.moveTo(residue.getC4sCoords());
2689 
2690     // Presently, the exterior method loadPriorAtomicCoordinates() directly
2691     // calls applySugarPucker instead of going through applyRotamer().
2692     applySugarPucker(residue, sugarPucker, isDeoxy, true);
2693     applyNABackbone(residue, rotamer, prevResidue);
2694 
2695     double naCorrection = 0;
2696     if (prevResidue != null && !independent) {
2697       naCorrection =
2698           applyNACorrections(residue, prevResidue, rotamer, prevSugarPucker, isDeoxy, is3sTerminal);
2699     } /* else if (!independent) {
2700       startingResidueConsistencyCheck(residue, rotamer, correctionThreshold);
2701       } */
2702 
2703     applyNASideAtoms(residue, rotamer, prevResidue, isDeoxy, is3sTerminal, prevSugarPucker);
2704     return naCorrection;
2705   }
2706 
2707   /**
2708    * Draws nucleic acid Atoms outside the backbone. Called after corrections have been applied, so
2709    * that these Atoms are drawn with ideal bond lengths and angles.
2710    *
2711    * @param residue Residue.
2712    * @param rotamer If 5' capped by HO5s, uses chi5 to draw HO5s.
2713    * @param prevResidue NA residue at the 5' end of residue.
2714    * @param isDeoxy If Residue is DNA; false means RNA.
2715    * @param is3sTerminal If Residue is at a 3' end.
2716    * @param prevSugarPucker Sugar pucker for prevResidue specified by Rotamer.
2717    */
2718   private static void applyNASideAtoms(
2719       Residue residue,
2720       Rotamer rotamer,
2721       Residue prevResidue,
2722       boolean isDeoxy,
2723       boolean is3sTerminal,
2724       NucleicSugarPucker prevSugarPucker) {
2725     Atom C1s = (Atom) residue.getAtomNode("C1'");
2726     Atom C2s = (Atom) residue.getAtomNode("C2'");
2727     Atom C3s = (Atom) residue.getAtomNode("C3'");
2728     Atom C4s = (Atom) residue.getAtomNode("C4'");
2729     Atom O4s = (Atom) residue.getAtomNode("O4'");
2730     Atom O3s = (Atom) residue.getAtomNode("O3'");
2731     // O2s will be null in DNA.
2732     Atom O2s = (Atom) residue.getAtomNode("O2'");
2733 
2734     // Hydrogens attached to the sugar
2735     // Hydrogens in DNA.  Will be null in RNA.
2736     Atom H2ss = (Atom) residue.getAtomNode("H2''");
2737     // Hydrogens in RNA.  Will be null in DNA.
2738     Atom H2s = (Atom) residue.getAtomNode("H2'");
2739     Atom HO2s = (Atom) residue.getAtomNode("HO2'");
2740     // Common hydrogens
2741     Atom H3s = (Atom) residue.getAtomNode("H3'");
2742     Atom H4s = (Atom) residue.getAtomNode("H4'");
2743     Atom H1s = (Atom) residue.getAtomNode("H1'");
2744     Atom H5s = (Atom) residue.getAtomNode("H5'");
2745     Atom H5ss = (Atom) residue.getAtomNode("H5''");
2746 
2747     Atom C5s = (Atom) residue.getAtomNode("C5'");
2748     Atom O5s = (Atom) residue.getAtomNode("O5'");
2749     Atom P = (Atom) residue.getAtomNode("P");
2750     Atom OP1 = (Atom) residue.getAtomNode("OP1");
2751     Atom OP2 = (Atom) residue.getAtomNode("OP2");
2752 
2753     // Build atachments to C2'.
2754     Bond C2s_H2s = C2s.getBond(H2s);
2755     double dC2s_H2s = C2s_H2s.bondType.distance;
2756     Angle C3s_C2s_H2s = C3s.getAngle(C2s, H2s);
2757     double dC3s_C2s_H2s = C3s_C2s_H2s.angleType.angle[C3s_C2s_H2s.nh];
2758 
2759     if (isDeoxy) {
2760       intxyz(H2s, C2s, dC2s_H2s, C3s, dC3s_C2s_H2s, C1s, 109.4, 1);
2761       Bond C2s_H2ss = C2s.getBond(H2ss);
2762       double dC2s_H2ss = C2s_H2ss.bondType.distance;
2763       Angle C3s_C2s_H2ss = C3s.getAngle(C2s, H2ss);
2764       double dC3s_C2s_H2ss = C3s_C2s_H2ss.angleType.angle[C3s_C2s_H2ss.nh];
2765       intxyz(H2ss, C2s, dC2s_H2ss, C3s, dC3s_C2s_H2ss, C1s, 109.4, -1);
2766     } else {
2767       intxyz(H2s, C2s, dC2s_H2s, C3s, dC3s_C2s_H2s, C1s, 109.4, -1);
2768 
2769       Bond C2s_O2s = C2s.getBond(O2s);
2770       double dC2s_O2s = C2s_O2s.bondType.distance;
2771       Angle C3s_C2s_O2s = C3s.getAngle(C2s, O2s);
2772       double dC3s_C2s_O2s = C3s_C2s_O2s.angleType.angle[C3s_C2s_O2s.nh];
2773       intxyz(O2s, C2s, dC2s_O2s, C3s, dC3s_C2s_O2s, C1s, 109.4, 1);
2774 
2775       /*
2776        * The placement of HO2' may eventually become a rotameric
2777        * function, but is presently being defaulted to 70 degrees.
2778        *
2779        * 70 degrees was just what I got from looking at 3ZD7 in
2780        * PyMol
2781        */
2782       Bond O2s_HO2s = O2s.getBond(HO2s);
2783       double dO2s_HO2s = O2s_HO2s.bondType.distance;
2784       Angle C2s_O2s_HO2s = C2s.getAngle(O2s, HO2s);
2785       double dC2s_O2s_HO2s = C2s_O2s_HO2s.angleType.angle[C2s_O2s_HO2s.nh];
2786       intxyz(HO2s, O2s, dO2s_HO2s, C2s, dC2s_O2s_HO2s, C1s, 70, 0);
2787     }
2788 
2789     Bond C1s_H1s = C1s.getBond(H1s);
2790     double dC1s_H1s = C1s_H1s.bondType.distance;
2791     Angle C2s_C1s_H1s = C2s.getAngle(C1s, H1s);
2792     double dC2s_C1s_H1s = C2s_C1s_H1s.angleType.angle[C2s_C1s_H1s.nh];
2793     intxyz(H1s, C1s, dC1s_H1s, C2s, dC2s_C1s_H1s, O4s, 109.4, 1);
2794 
2795     Bond C3s_H3s = C3s.getBond(H3s);
2796     double dC3s_H3s = C3s_H3s.bondType.distance;
2797     Angle C2s_C3s_H3s = C2s.getAngle(C3s, H3s);
2798     double dC2s_C3s_H3s = C2s_C3s_H3s.angleType.angle[C2s_C3s_H3s.nh];
2799     intxyz(H3s, C3s, dC3s_H3s, C2s, dC2s_C3s_H3s, C4s, 109.4, 1);
2800 
2801     Bond C4s_H4s = C4s.getBond(H4s);
2802     double dC4s_H4s = C4s_H4s.bondType.distance;
2803     Angle C3s_C4s_H4s = C3s.getAngle(C4s, H4s);
2804     double dC3s_C4s_H4s = C3s_C4s_H4s.angleType.angle[C3s_C4s_H4s.nh];
2805     intxyz(H4s, C4s, dC4s_H4s, C3s, dC3s_C4s_H4s, O4s, 109.4, -1);
2806 
2807     Bond C5s_H5s = C5s.getBond(H5s);
2808     double dC5s_H5s = C5s_H5s.bondType.distance;
2809     Angle C4s_C5s_H5s = C4s.getAngle(C5s, H5s);
2810     double dC4s_C5s_H5s = C4s_C5s_H5s.angleType.angle[C4s_C5s_H5s.nh];
2811     intxyz(H5s, C5s, dC5s_H5s, C4s, dC4s_C5s_H5s, O5s, 109.4, -1);
2812 
2813     Bond C5s_H5ss = C5s.getBond(H5ss);
2814     double dC5s_H5ss = C5s_H5ss.bondType.distance;
2815     Angle C4s_C5s_H5ss = C4s.getAngle(C5s, H5ss);
2816     double dC4s_C5s_H5ss = C4s_C5s_H5ss.angleType.angle[C4s_C5s_H5ss.nh];
2817     intxyz(H5ss, C5s, dC5s_H5ss, C4s, dC4s_C5s_H5ss, O5s, 109.4, 1);
2818 
2819     if (is3sTerminal) {
2820       // TODO: Determine proper labels for 3' phosphate caps so they may be implemented.
2821       Atom HO3s = (Atom) residue.getAtomNode("HO3'");
2822       // if (HO3s != null) {
2823       Bond O3s_HO3s = O3s.getBond(HO3s);
2824       double dO3s_HO3s = O3s_HO3s.bondType.distance;
2825       Angle C3s_O3s_HO3s = C3s.getAngle(O3s, HO3s);
2826       double dC3s_O3s_HO3s = C3s_O3s_HO3s.angleType.angle[C3s_O3s_HO3s.nh];
2827       // HO3s defaulted to the antiperiplanar value of 180 degrees.
2828       intxyz(HO3s, O3s, dO3s_HO3s, C3s, dC3s_O3s_HO3s, C4s, 180, 0);
2829     }
2830 
2831     if (P != null) {
2832       double[] PXYZ = new double[3];
2833       P.getXYZ(PXYZ);
2834       double[] O5sXYZ = new double[3];
2835       O5s.getXYZ(O5sXYZ);
2836       double[] C5sXYZ = new double[3];
2837       C5s.getXYZ(C5sXYZ);
2838 
2839       Bond P_OP1 = P.getBond(OP1);
2840       double dP_OP1 = P_OP1.bondType.distance;
2841       Angle O5s_P_OP1 = C5s.getAngle(O5s, P);
2842       double dO5s_P_OP1 = O5s_P_OP1.angleType.angle[O5s_P_OP1.nh];
2843 
2844       Bond P_OP2 = P.getBond(OP2);
2845       double dP_OP2 = P_OP2.bondType.distance;
2846       Angle O5s_P_OP2 = C5s.getAngle(O5s, P);
2847       double dO5s_P_OP2 = O5s_P_OP2.angleType.angle[O5s_P_OP2.nh];
2848 
2849       // TODO: Handle hydrogens attached to 5'-terminal phosphates.
2850 
2851       /*
2852        * If there is a prior residue, draw tetrahedrally based on O3'
2853        * (i-1).  Else, draw based on OP3.
2854        */
2855       if (prevResidue != null) {
2856         double[] O3sPriorCoords;
2857         if (prevSugarPucker == NucleicSugarPucker.C3_ENDO) {
2858           O3sPriorCoords = prevResidue.getO3sNorth();
2859         } else {
2860           O3sPriorCoords = prevResidue.getO3sSouth();
2861         }
2862         double[] OP1XYZ =
2863             determineIntxyz(PXYZ, dP_OP1, O5sXYZ, dO5s_P_OP1, O3sPriorCoords, 109.4, 1);
2864         double[] OP2XYZ =
2865             determineIntxyz(PXYZ, dP_OP2, O5sXYZ, dO5s_P_OP2, O3sPriorCoords, 109.4, -1);
2866         OP1.moveTo(OP1XYZ);
2867         OP2.moveTo(OP2XYZ);
2868       } else {
2869         Atom OP3 = (Atom) residue.getAtomNode("OP3");
2870         double[] OP3XYZ = new double[3];
2871         OP3.getXYZ(OP3XYZ);
2872         double[] OP1XYZ = determineIntxyz(PXYZ, dP_OP1, O5sXYZ, dO5s_P_OP1, OP3XYZ, 109.4, 1);
2873         double[] OP2XYZ = determineIntxyz(PXYZ, dP_OP2, O5sXYZ, dO5s_P_OP2, OP3XYZ, 109.4, -1);
2874         OP1.moveTo(OP1XYZ);
2875         OP2.moveTo(OP2XYZ);
2876       }
2877     } else {
2878       Atom HO5s = (Atom) residue.getAtomNode("HO5'");
2879       Bond O5s_HO5s = O5s.getBond(HO5s);
2880       double dO5s_HO5s = O5s_HO5s.bondType.distance;
2881       Angle C5s_O5s_HO5s = C5s.getAngle(O5s, HO5s);
2882       double dC5s_O5s_HO5s = C5s_O5s_HO5s.angleType.angle[C5s_O5s_HO5s.nh];
2883       intxyz(HO5s, O5s, dO5s_HO5s, C5s, dC5s_O5s_HO5s, C4s, rotamer.chi5, 0);
2884     }
2885   }
2886 
2887   /**
2888    * Applies a coordinates-based Rotamer (defined by Cartesian coordinates instead of by a set of
2889    * torsion angles); intended for use with original coordinates Rotamers and possibly other future
2890    * cases.
2891    *
2892    * @param residue Residue to apply Rotamer for
2893    * @param rotamer Coordinates-based Rotamer
2894    */
2895   private static void applyState(Residue residue, Rotamer rotamer) {
2896     if (rotamer.isState) {
2897       residue.revertState(rotamer.originalState);
2898     } else {
2899       logger.warning(format(" Attempting to apply a ResidueState for "
2900           + "a torsion-based rotamer %s for residue %s", rotamer, residue));
2901     }
2902   }
2903 
2904   /**
2905    * Draws CZ of Phe/Tyr/Tyd twice (from each branch of the ring), the cuts it down the middle.
2906    *
2907    * @param resName Residue containing CZ.
2908    * @param CZ CZ to be placed.
2909    * @param CG CG atom.
2910    * @param CE1 CE1 atom.
2911    * @param CD1 CD1 atom.
2912    * @param CE2 CE2 atom.
2913    * @param CD2 CD2 atom.
2914    * @return Mean coordinates for CZ based on internal geometry.
2915    */
2916   private static double[] drawCZ(
2917       AminoAcid3 resName, Atom CZ, Atom CG, Atom CE1, Atom CD1, Atom CE2, Atom CD2) {
2918     double bondLen = CZ.getBond(CE1).bondType.distance;
2919     double ang = getAngle(resName, CZ, CE1, CD1);
2920     double[] xCG = new double[3];
2921     xCG = CG.getXYZ(xCG);
2922 
2923     double[] xCE = new double[3];
2924     xCE = CE1.getXYZ(xCE);
2925     double[] xCD = new double[3];
2926     xCD = CD1.getXYZ(xCD);
2927     double[] xyz1 = determineIntxyz(xCE, bondLen, xCD, ang, xCG, 0.0, 0);
2928 
2929     xCE = CE2.getXYZ(xCE);
2930     xCD = CD2.getXYZ(xCD);
2931     double[] xyz2 = determineIntxyz(xCE, bondLen, xCD, ang, xCG, 0, 0);
2932 
2933     for (int i = 0; i < 3; i++) {
2934       xyz1[i] += xyz2[i];
2935       xyz1[i] *= 0.5;
2936     }
2937     return xyz1;
2938   }
2939 
2940   /**
2941    * Gets an Angle, using the default as set by property for whether to use idealized ring geometry
2942    * (default), or based on force field.
2943    *
2944    * @param resName AminoAcid3 for a1-a3.
2945    * @param a1 An Atom.
2946    * @param a2 Another Atom.
2947    * @param a3 A third Atom.
2948    * @return a1-a2-a3 angle for internal geometry.
2949    */
2950   private static double getAngle(AminoAcid3 resName, Atom a1, Atom a2, Atom a3) {
2951     if (useIdealRingGeometries) {
2952       return idealGeometryAngle(resName, a1, a2, a3);
2953     } else {
2954       return angleFromForceField(a1, a2, a3);
2955     }
2956   }
2957 
2958   /**
2959    * Obtains an idealized angle using a lookup map of stored, idealized geometries, with a fallback
2960    * to using the force field. This is intended for use with ring systems, where ring constraints
2961    * mean that optimum-energy rings may not have the values defined by the force field.
2962    *
2963    * <p>Current lookup map is only for PHE, TYR, TYD, HIS, HID, HIE, and TRP, using values obtained
2964    * from a tight bonded-terms-only optimization under AMOEBA BIO 2018.
2965    *
2966    * @param resName Name of the Residue containing a1-a3.
2967    * @param a1 An atom.
2968    * @param a2 Another Atom.
2969    * @param a3 Another Atom.
2970    * @return Stored idealized a1-a2-a3 angle in degrees.
2971    */
2972   private static double idealGeometryAngle(AminoAcid3 resName, Atom a1, Atom a2, Atom a3) {
2973     StringBuilder sb = new StringBuilder(a1.getName());
2974     sb.append("-").append(a2.getName()).append("-").append(a3.getName());
2975     Map<String, Double> resMap = idealAngleGeometries.get(resName);
2976     String atomString = sb.toString();
2977 
2978     if (resMap.containsKey(atomString)) {
2979       return resMap.get(atomString);
2980     } else {
2981       sb = new StringBuilder(a3.getName());
2982       sb.append("-").append(a2.getName()).append("-").append(a1.getName());
2983       atomString = sb.toString();
2984       if (resMap.containsKey(atomString)) {
2985         return resMap.get(atomString);
2986       } else {
2987         logger.finest(
2988             format(" Could not find an ideal-geometry angle for %s %s-%s-%s", resName, a1, a2, a3));
2989         return angleFromForceField(a1, a2, a3);
2990       }
2991     }
2992   }
2993 
2994   /**
2995    * Checks if a Residue has a PTM.
2996    *
2997    * @param residue The Residue to check.
2998    * @return True if this is a modified residue.
2999    */
3000   private static boolean isModRes(Residue residue) {
3001     List<Atom> resatoms = residue.getAtomList();
3002     return (resatoms != null && !resatoms.isEmpty() && resatoms.get(0).isModRes());
3003   }
3004 
3005   /**
3006    * Measure the current torsions of a nucleic acid Residue, starting from the 5'-most torsion.
3007    *
3008    * <p>Chi[0]-chi[6] in order are: delta (i-1), epsilon (i-1), zeta (i-1), alpha (i), beta (i),
3009    * gamma (i) and delta (i) for residue i.
3010    *
3011    * @param residue Residue to be measured.
3012    * @param chi Array to be filled with torsion values.
3013    * @param print Verbosity flag.
3014    * @return The number of rotamers this Residue has.
3015    */
3016   private static int measureNARotamer(Residue residue, double[] chi, boolean print) {
3017     NucleicAcid3 name = NucleicAcidUtils.NucleicAcid3.valueOf(residue.getName());
3018     Residue prevResidue = residue.getPreviousResidue();
3019     Torsion torsion;
3020 
3021     Atom C5s = (Atom) residue.getAtomNode("C5'");
3022     Atom C4s = (Atom) residue.getAtomNode("C4'");
3023     Atom C3s = (Atom) residue.getAtomNode("C3'");
3024     Atom O3s = (Atom) residue.getAtomNode("O3'");
3025     Atom O5s = (Atom) residue.getAtomNode("O5'");
3026     Atom P = (Atom) residue.getAtomNode("P");
3027 
3028     int nRot = 7;
3029 
3030     /*
3031      * Start by measuring delta (i-1) if available, working up to delta.  If
3032      * there is no prior residue, start measuring from the 5'-most torsion.
3033      */
3034     if (prevResidue == null) {
3035       switch (name) {
3036         case GUA:
3037         case ADE:
3038         case DGU:
3039         case DAD:
3040         case CYT:
3041         case URI:
3042         case THY:
3043         case DCY:
3044         case DTY:
3045           /*
3046            * If there is an HO5s, measure alpha based on HO5s.  Else,
3047            * measure zeta (i-1) based on OP3 and alpha on P.
3048            */
3049           Atom HO5s = (Atom) residue.getAtomNode("HO5'");
3050           if (HO5s != null) {
3051             torsion = HO5s.getTorsion(O5s, C5s, C4s);
3052             chi[4] = torsion.measure();
3053             if (print) {
3054               logger.info(torsion.toString());
3055             }
3056             nRot = 3;
3057           } else {
3058             Atom OP3 = (Atom) residue.getAtomNode("OP3");
3059             nRot = 3;
3060             if (OP3 != null) {
3061               torsion = OP3.getTorsion(P, O5s, C5s);
3062               chi[3] = torsion.measure();
3063               if (print) {
3064                 logger.info(torsion.toString());
3065               }
3066               nRot = 4;
3067             }
3068 
3069             torsion = P.getTorsion(O5s, C5s, C4s);
3070             chi[4] = torsion.measure();
3071             if (print) {
3072               logger.info(torsion.toString());
3073             }
3074           }
3075           break;
3076         default:
3077           break;
3078       }
3079     } else {
3080       switch (name) {
3081         case GUA:
3082         case ADE:
3083         case DGU:
3084         case DAD:
3085         case CYT:
3086         case URI:
3087         case THY:
3088         case DCY:
3089         case DTY:
3090           Atom O3sPrev = (Atom) prevResidue.getAtomNode("O3'");
3091           Atom C3sPrev = (Atom) prevResidue.getAtomNode("C3'");
3092           Atom C4sPrev = (Atom) prevResidue.getAtomNode("C4'");
3093           Atom C5sPrev = (Atom) prevResidue.getAtomNode("C5'");
3094 
3095           torsion = C5sPrev.getTorsion(C4sPrev, C3sPrev, O3sPrev);
3096           chi[0] = torsion.measure();
3097           if (print) {
3098             logger.info(torsion.toString());
3099           }
3100 
3101           torsion = C4sPrev.getTorsion(C3sPrev, O3sPrev, P);
3102           chi[1] = torsion.measure();
3103           if (print) {
3104             logger.info(torsion.toString());
3105           }
3106 
3107           torsion = C3sPrev.getTorsion(O3sPrev, P, O5s);
3108           chi[2] = torsion.measure();
3109           if (print) {
3110             logger.info(torsion.toString());
3111           }
3112 
3113           torsion = O3sPrev.getTorsion(P, O5s, C5s);
3114           chi[3] = torsion.measure();
3115           if (print) {
3116             logger.info(torsion.toString());
3117           }
3118 
3119           torsion = P.getTorsion(O5s, C5s, C4s);
3120           chi[4] = torsion.measure();
3121           if (print) {
3122             logger.info(torsion.toString());
3123           }
3124           break;
3125         default:
3126           break;
3127       }
3128     }
3129     /*
3130      * Measure torsions common to all nucleic acids (gamma, delta).
3131      */
3132     torsion = O5s.getTorsion(C5s, C4s, C3s);
3133     chi[5] = torsion.measure();
3134     if (print) {
3135       logger.info(torsion.toString());
3136     }
3137 
3138     torsion = C5s.getTorsion(C4s, C3s, O3s);
3139     chi[6] = torsion.measure();
3140     if (print) {
3141       logger.info(torsion.toString());
3142     }
3143     return nRot;
3144   }
3145 
3146   /**
3147    * measureUNKRotamer.
3148    *
3149    * @param residue a {@link ffx.potential.bonded.Residue} object.
3150    * @param chi an array of {@link double} objects.
3151    * @param print a boolean.
3152    */
3153   private static void measureUNKRotamer(Residue residue, double[] chi, boolean print) {
3154     String resName = residue.getName().toUpperCase();
3155     if (nonstdRotCache.containsKey(resName)) {
3156       nonstdRotCache.get(resName).measureNonstdRot(residue, chi, print);
3157     } else {
3158       logger.warning(
3159           format(" Could not measure chi angles " + "for residue %s", residue));
3160     }
3161   }
3162 
3163   private static void readRotFile(File rotamerFile, MolecularAssembly assembly, int boxWindowIndex)
3164       throws IOException {
3165     try (BufferedReader br = new BufferedReader(new FileReader(rotamerFile))) {
3166       Polymer[] polys = assembly.getChains();
3167       Residue currentRes = null;
3168       ResidueState origState = null;
3169 
3170       String line = br.readLine();
3171       boolean doRead = false;
3172       while (line != null) {
3173         String[] toks = line.trim().split(":");
3174         if (toks[0].equals("ALGORITHM")) {
3175           doRead = Integer.parseInt(toks[2]) == boxWindowIndex;
3176           logger.info(format(" Readabilifications %b with %s", doRead, line));
3177         } else if (doRead && !toks[0].startsWith("#")) {
3178           switch (toks[0]) {
3179             case "RES": {
3180               String segID = toks[2];
3181               int resnum = Integer.parseInt(toks[4]);
3182               for (Polymer poly : polys) {
3183                 if (poly.getName().equals(segID)) {
3184                   currentRes = poly.getResidue(resnum);
3185                   break;
3186                 }
3187               }
3188             }
3189             break;
3190             case "ENDROT": {
3191               // TODO: Publish rotamer & revert coordinates.
3192               currentRes.addRotamers(Rotamer.defaultRotamerFactory(currentRes));
3193               currentRes.revertState(origState);
3194               logger.info(format(" Adding a rotamer to %s", currentRes));
3195             }
3196             break;
3197             case "ROT": {
3198               origState = currentRes.storeState();
3199             }
3200             break;
3201             case "ATOM": {
3202               String name = toks[1];
3203               Atom atom = (Atom) currentRes.getAtomNode(name);
3204               double[] xyz = new double[3];
3205               for (int i = 0; i < 3; i++) {
3206                 xyz[i] = Double.parseDouble(toks[i + 2]);
3207               }
3208               atom.setXYZ(xyz);
3209             }
3210             break;
3211             default: {
3212               logger.warning(" Unrecognized line! " + line);
3213             }
3214           }
3215         }
3216         line = br.readLine();
3217       }
3218     }
3219   }
3220 
3221   /**
3222    * Get the protein rotamer library.
3223    *
3224    * @return the ProteinLibrary in use.
3225    */
3226   public ProteinLibrary getLibrary() {
3227     return proteinLibrary;
3228   }
3229 
3230   /**
3231    * Return an array of Rotamers for the given amino acid.
3232    *
3233    * @param name The name of the amino acid.
3234    * @return An array of Rotamers.
3235    */
3236   public Rotamer[] getRotamers(AminoAcid3 name) {
3237     return getRotamers(name, null);
3238   }
3239 
3240   /**
3241    * Return an array of Rotamers for the given amino acid.
3242    *
3243    * @param name The name of the amino acid.
3244    * @return An array of Rotamers.
3245    */
3246   public Rotamer[] getRotamers(AminoAcid3 name, TitrationUtils titrationUtils) {
3247     switch (proteinLibrary) {
3248       case PonderAndRichards:
3249         return getPonderAndRichardsRotamers(name, titrationUtils);
3250       case Richardson:
3251         return getRichardsonRotamers(name, titrationUtils);
3252       case None:
3253       default:
3254         return null;
3255     }
3256   }
3257 
3258   /**
3259    * Return an array of Rotamers for the given nucleic acid.
3260    *
3261    * @param name The name of the nucleic acid.
3262    * @return An array of Rotamers.
3263    */
3264   public Rotamer[] getRotamers(NucleicAcid3 name) {
3265     return getRichardsonRNARotamers(name);
3266   }
3267 
3268   /**
3269    * getUsingOrigCoordsRotamer.
3270    *
3271    * @return a boolean.
3272    */
3273   public boolean getUsingOrigCoordsRotamer() {
3274     return useOrigCoordsRotamer;
3275   }
3276 
3277   /**
3278    * Guess at what rotamer a residue is currently in.
3279    *
3280    * @param residue Residue to check.
3281    * @return Index of the rotamer it is in.
3282    */
3283   public RotamerGuess guessRotamer(Residue residue) {
3284     assert useOrigCoordsRotamer == false;
3285     if (residue == null) {
3286       throw new IllegalArgumentException(" Residue cannot be null!");
3287     }
3288     Rotamer[] rotamers = residue.getRotamers();
3289     if (rotamers == null) {
3290       rotamers = residue.setRotamers(this);
3291     }
3292     if (rotamers == null || rotamers.length == 0) {
3293       throw new IllegalArgumentException(format(" Residue %s does not have rotamers!", residue));
3294     }
3295     int nRot = rotamers.length;
3296 
3297     double[] currChi =
3298         residue.getResidueType().equals(Residue.ResidueType.AA) ? new double[4] : new double[7];
3299     int numChis = measureRotamer(residue, currChi, false);
3300     double[] chiRMSD = new double[nRot];
3301     double lowestRMSD = Double.MAX_VALUE;
3302     int indexLowest = -1;
3303 
3304     for (int i = 0; i < nRot; i++) {
3305       double rmsd = 0;
3306       Rotamer roti = rotamers[i];
3307       double[] rotChi = roti.angles;
3308 
3309       for (int j = 0; j < numChis; j++) {
3310         double dChi = Math.abs(currChi[j] - rotChi[j]);
3311         if (dChi > 180) {
3312           dChi = 360.0 - dChi;
3313         }
3314         dChi *= dChi;
3315         rmsd += dChi;
3316       }
3317 
3318       rmsd /= numChis;
3319       rmsd = FastMath.sqrt(rmsd);
3320       chiRMSD[i] = rmsd;
3321       if (rmsd < lowestRMSD) {
3322         lowestRMSD = rmsd;
3323         indexLowest = i;
3324       }
3325     }
3326 
3327     if (indexLowest < 0) {
3328       logger.warning(format(" Residue %s could not be IDd!", residue));
3329       logger.info(Arrays.toString(currChi));
3330       logger.info(format("%12.5g", lowestRMSD));
3331       logger.info(format("%d", nRot));
3332     }
3333 
3334     return new RotamerGuess(residue, rotamers[indexLowest], indexLowest, lowestRMSD);
3335   }
3336 
3337   /**
3338    * Setter for the field <code>useOrigCoordsRotamer</code>.
3339    *
3340    * @param set a boolean.
3341    */
3342   public void setUseOrigCoordsRotamer(boolean set) {
3343     useOrigCoordsRotamer = set;
3344   }
3345 
3346   /**
3347    * Return rotamer array for the given AA or NA residue.
3348    *
3349    * @param residue the Residue to examine.
3350    * @return Array of Rotamers for Residue's type.
3351    */
3352   Rotamer[] getRotamers(Residue residue) {
3353     return getRotamers(residue, null);
3354   }
3355 
3356   /**
3357    * Return rotamer array for the given AA or NA residue.
3358    *
3359    * @param residue the Residue to examine.
3360    * @return Array of Rotamers for Residue's type.
3361    */
3362   Rotamer[] getRotamers(Residue residue, TitrationUtils titrationUtils) {
3363     // Package-private; intended to be accessed only by Residue and extensions
3364     // thereof. Otherwise, use Residue.getRotamers(RotamerLibrary library).
3365     if (residue == null) {
3366       return null;
3367     }
3368     if (isModRes(residue)) {
3369       if (nonstdRotCache.containsKey(residue.getName().toUpperCase())) {
3370         return nonstdRotCache.get(residue.getName().toUpperCase()).getRotamers();
3371       }
3372       return null;
3373     }
3374     switch (residue.getResidueType()) {
3375       case AA:
3376         AminoAcid3 aa = AminoAcidUtils.AminoAcid3.valueOf(residue.getName());
3377         // Now check for cysteines in a disulfide bond.
3378         switch (aa) {
3379           case CYS:
3380           case CYX:
3381           case CYD: {
3382             List<Atom> cysAtoms = residue.getAtomList();
3383             // First find the sulfur on atomic number, then on starting with S.
3384             Optional<Atom> s =
3385                 cysAtoms.stream().filter(a -> a.getAtomType().atomicNumber == 16).findAny();
3386             if (!s.isPresent()) {
3387               s = cysAtoms.stream().filter(a -> a.getName().startsWith("S")).findAny();
3388             }
3389             if (s.isPresent()) {
3390               Atom theS = s.get();
3391               boolean attachedS =
3392                   theS.getBonds().stream()
3393                       .map(b -> b.get1_2(theS))
3394                       .anyMatch(
3395                           a -> a.getAtomType().atomicNumber == 16 || a.getName().startsWith("S"));
3396               if (attachedS) {
3397                 // Return a null rotamer array if it's disulfide-bonded.
3398                 return null;
3399               }
3400             } else {
3401               logger.warning(
3402                   format(" No sulfur atom found attached to %s residue %s!", aa, residue));
3403             }
3404           }
3405           break;
3406           // Default: no-op (we are checking for cysteine disulfide bonds).
3407         }
3408         return getRotamers(aa, titrationUtils);
3409       case NA:
3410         NucleicAcid3 na = NucleicAcidUtils.NucleicAcid3.valueOf(residue.getName());
3411         return getRotamers(na);
3412       default:
3413         if (nonstdRotCache.containsKey(residue.getName().toUpperCase())) {
3414           return nonstdRotCache.get(residue.getName().toUpperCase()).getRotamers();
3415         }
3416         return null;
3417     }
3418   }
3419 
3420   /**
3421    * Fills the idealized amino acid rotamer cache with the Ponder and Richards rotamers.
3422    *
3423    * <p>Ponder, J. W.; Richards, F. M., Tertiary templates for proteins: Use of packing criteria in
3424    * the enumeration of allowed sequences for different structural classes Journal of Molecular
3425    * Biology 1987, 193 (4), 775-791
3426    *
3427    * @param name Type of amino acid.
3428    * @param titrationUtils TitrationUtils for rotamers whose titation state can change.
3429    * @return Rotamer cache (double[] of torsions).
3430    */
3431   private Rotamer[] getPonderAndRichardsRotamers(AminoAcid3 name, TitrationUtils titrationUtils) {
3432     int n = name.ordinal();
3433     if (aminoAcidRotamerCache[n] != null) {
3434       return aminoAcidRotamerCache[n];
3435     }
3436     switch (name) {
3437       case VAL:
3438         aminoAcidRotamerCache[n] = new Rotamer[3];
3439         aminoAcidRotamerCache[n][0] = new Rotamer(name, 173.5, 9.0);
3440         aminoAcidRotamerCache[n][1] = new Rotamer(name, -63.4, 8.1);
3441         aminoAcidRotamerCache[n][2] = new Rotamer(name, 69.3, 9.6);
3442         break;
3443       case LEU:
3444         aminoAcidRotamerCache[n] = new Rotamer[4];
3445         aminoAcidRotamerCache[n][0] = new Rotamer(name, -64.9, 8.2, 176.0, 9.9);
3446         aminoAcidRotamerCache[n][1] = new Rotamer(name, -176.4, 10.2, 63.1, 8.2);
3447         aminoAcidRotamerCache[n][2] = new Rotamer(name, -165.3, 10.0, 168.2, 34.2);
3448         aminoAcidRotamerCache[n][3] = new Rotamer(name, 44.3, 20.0, 60.4, 18.8);
3449         break;
3450       case ILE:
3451         aminoAcidRotamerCache[n] = new Rotamer[5];
3452         aminoAcidRotamerCache[n][0] = new Rotamer(name, -60.9, 7.5, 168.7, 11.6);
3453         aminoAcidRotamerCache[n][1] = new Rotamer(name, -59.6, 9.6, -64.1, 14.3);
3454         aminoAcidRotamerCache[n][2] = new Rotamer(name, 61.7, 5.0, 163.8, 16.4);
3455         aminoAcidRotamerCache[n][3] = new Rotamer(name, -166.6, 10.1, 166.0, 8.9);
3456         aminoAcidRotamerCache[n][4] = new Rotamer(name, -174.8, 24.9, 72.1, 10.5);
3457         break;
3458       case SER:
3459         aminoAcidRotamerCache[n] = new Rotamer[3];
3460         aminoAcidRotamerCache[n][0] = new Rotamer(name, 64.7, 16.1);
3461         aminoAcidRotamerCache[n][1] = new Rotamer(name, -69.7, 14.6);
3462         aminoAcidRotamerCache[n][2] = new Rotamer(name, -176.1, 20.2);
3463         break;
3464       case THR:
3465         aminoAcidRotamerCache[n] = new Rotamer[3];
3466         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62.7, 8.5);
3467         aminoAcidRotamerCache[n][1] = new Rotamer(name, -59.7, 9.4);
3468         aminoAcidRotamerCache[n][2] = new Rotamer(name, -169.5, 6.6);
3469         break;
3470       case CYS:
3471       case CYD:
3472         if(titrationUtils == null){
3473           aminoAcidRotamerCache[n] = new Rotamer[3];
3474           aminoAcidRotamerCache[n][0] = new Rotamer(name, -65.2, 10.1);
3475           aminoAcidRotamerCache[n][1] = new Rotamer(name, -179.6, 9.5);
3476           aminoAcidRotamerCache[n][2] = new Rotamer(name, 63.5, 9.6);
3477         } else {
3478           aminoAcidRotamerCache[n] = new Rotamer[6];
3479           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.CYS, titrationUtils, -65.2, 10.1);
3480           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.CYS, titrationUtils, -179.6, 9.5);
3481           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.CYS, titrationUtils, 63.5, 9.6);
3482           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.CYD, titrationUtils, -65.2, 10.1);
3483           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.CYD, titrationUtils, -179.6, 9.5);
3484           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.CYD, titrationUtils, 63.5, 9.6);
3485         }
3486 
3487         break;
3488       /*
3489        * TODO: Figure out proline rotamers.  I have dihedrals from
3490        * the Richardson lab/Kinemages website (downloaded PDB, used
3491        * the get_dihedral function to extract the dihedrals), and they
3492        * conflict with these rotamers.  Plus, this library only
3493        * specifies one of the two necessary dihedrals.
3494        */
3495       case PRO:
3496         aminoAcidRotamerCache[n] = new Rotamer[3];
3497         aminoAcidRotamerCache[n][0] = new Rotamer(name, 24.0, 8.0);
3498         aminoAcidRotamerCache[n][1] = new Rotamer(name, 0.0, 8.0);
3499         aminoAcidRotamerCache[n][2] = new Rotamer(name, -24.0, 8.0);
3500         break;
3501       case PHE:
3502         aminoAcidRotamerCache[n] = new Rotamer[4];
3503         aminoAcidRotamerCache[n][0] = new Rotamer(name, -66.3, 10.2, 94.3, 19.5);
3504         aminoAcidRotamerCache[n][1] = new Rotamer(name, -179.2, 9.3, 78.9, 8.9);
3505         aminoAcidRotamerCache[n][2] = new Rotamer(name, 66.0, 12.0, 90.7, 9.4);
3506         aminoAcidRotamerCache[n][3] = new Rotamer(name, -71.9, 16.3, -0.4, 26.1);
3507         break;
3508       case TYR:
3509         aminoAcidRotamerCache[n] = new Rotamer[8];
3510         aminoAcidRotamerCache[n][0] = new Rotamer(name, -66.5, 11.4, 96.6, 21.8, 0, 0);
3511         aminoAcidRotamerCache[n][1] = new Rotamer(name, -179.7, 12.6, 71.9, 13.4, 0, 0);
3512         aminoAcidRotamerCache[n][2] = new Rotamer(name, 63.3, 9.4, 89.1, 13.0, 0, 0);
3513         aminoAcidRotamerCache[n][3] = new Rotamer(name, -67.2, 13.2, -1.0, 20.1, 0, 0);
3514         aminoAcidRotamerCache[n][4] = new Rotamer(name, -66.5, 11.4, 96.6, 21.8, 180.0, 0);
3515         aminoAcidRotamerCache[n][5] = new Rotamer(name, -179.7, 12.6, 71.9, 13.4, 180.0, 0);
3516         aminoAcidRotamerCache[n][6] = new Rotamer(name, 63.3, 9.4, 89.1, 13.0, 180.0, 0);
3517         aminoAcidRotamerCache[n][7] = new Rotamer(name, -67.2, 13.2, -1.0, 20.1, 180.0, 0);
3518         break;
3519       case TYD:
3520         aminoAcidRotamerCache[n] = new Rotamer[4];
3521         aminoAcidRotamerCache[n][0] = new Rotamer(name, -66.5, 11.4, 96.6, 21.8);
3522         aminoAcidRotamerCache[n][1] = new Rotamer(name, -179.7, 12.6, 71.9, 13.4);
3523         aminoAcidRotamerCache[n][2] = new Rotamer(name, 63.3, 9.4, 89.1, 13.0);
3524         aminoAcidRotamerCache[n][3] = new Rotamer(name, -67.2, 13.2, -1.0, 20.1);
3525         break;
3526       case TRP:
3527         aminoAcidRotamerCache[n] = new Rotamer[6];
3528         aminoAcidRotamerCache[n][0] = new Rotamer(name, -70.4, 7.0, 100.5, 18.2);
3529         aminoAcidRotamerCache[n][1] = new Rotamer(name, 64.8, 13.0, -88.9, 5.3);
3530         aminoAcidRotamerCache[n][2] = new Rotamer(name, -177.3, 7.9, -95.1, 7.6);
3531         aminoAcidRotamerCache[n][3] = new Rotamer(name, -179.5, 3.4, 87.5, 3.8);
3532         aminoAcidRotamerCache[n][4] = new Rotamer(name, -73.3, 6.5, -87.7, 8.1);
3533         aminoAcidRotamerCache[n][5] = new Rotamer(name, 62.2, 10.0, 112.5, 15.0);
3534         break;
3535       case HIS:
3536       case HIE:
3537       case HID:
3538         if (titrationUtils == null) {
3539           aminoAcidRotamerCache[n] = new Rotamer[6];
3540           aminoAcidRotamerCache[n][0] = new Rotamer(name, -62.8, 10.0, -74.3, 17.2);
3541           aminoAcidRotamerCache[n][1] = new Rotamer(name, -175.2, 15.4, -88.7, 43.5);
3542           aminoAcidRotamerCache[n][2] = new Rotamer(name, -69.8, 5.9, 96.1, 32.2);
3543           aminoAcidRotamerCache[n][3] = new Rotamer(name, 67.9, 17.4, -80.5, 40.7);
3544           aminoAcidRotamerCache[n][4] = new Rotamer(name, -177.3, 6.3, 100.5, 14.0);
3545           aminoAcidRotamerCache[n][5] = new Rotamer(name, 48.8, 10.0, 89.5, 30.0);
3546         } else {
3547           // 6 Rotamers x 3 states (HIS, HIE, HID)
3548           aminoAcidRotamerCache[n] = new Rotamer[18];
3549           // HIS
3550           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.HIS,
3551               titrationUtils, -62.8, 10.0, -74.3, 17.2);
3552           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.HIS,
3553               titrationUtils, -175.2, 15.4, -88.7, 43.5);
3554           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.HIS,
3555               titrationUtils, -69.8, 5.9, 96.1, 32.2);
3556           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.HIS,
3557               titrationUtils, 67.9, 17.4, -80.5, 40.7);
3558           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.HIS,
3559               titrationUtils, -177.3, 6.3, 100.5, 14.0);
3560           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.HIS,
3561               titrationUtils, 48.8, 10.0, 89.5, 30.0);
3562           // HIE
3563           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.HIE,
3564               titrationUtils, -62.8, 10.0, -74.3, 17.2);
3565           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.HIE,
3566               titrationUtils, -175.2, 15.4, -88.7, 43.5);
3567           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.HIE,
3568               titrationUtils, -69.8, 5.9, 96.1, 32.2);
3569           aminoAcidRotamerCache[n][9] = new Rotamer(AminoAcid3.HIE,
3570               titrationUtils, 67.9, 17.4, -80.5, 40.7);
3571           aminoAcidRotamerCache[n][10] = new Rotamer(AminoAcid3.HIE,
3572               titrationUtils, -177.3, 6.3, 100.5, 14.0);
3573           aminoAcidRotamerCache[n][11] = new Rotamer(AminoAcid3.HIE,
3574               titrationUtils, 48.8, 10.0, 89.5, 30.0);
3575           // HID
3576           aminoAcidRotamerCache[n][12] = new Rotamer(AminoAcid3.HID,
3577               titrationUtils, -62.8, 10.0, -74.3, 17.2);
3578           aminoAcidRotamerCache[n][13] = new Rotamer(AminoAcid3.HID,
3579               titrationUtils, -175.2, 15.4, -88.7, 43.5);
3580           aminoAcidRotamerCache[n][14] = new Rotamer(AminoAcid3.HID,
3581               titrationUtils, -69.8, 5.9, 96.1, 32.2);
3582           aminoAcidRotamerCache[n][15] = new Rotamer(AminoAcid3.HID,
3583               titrationUtils, 67.9, 17.4, -80.5, 40.7);
3584           aminoAcidRotamerCache[n][16] = new Rotamer(AminoAcid3.HID,
3585               titrationUtils, -177.3, 6.3, 100.5, 14.0);
3586           aminoAcidRotamerCache[n][17] = new Rotamer(AminoAcid3.HID,
3587               titrationUtils, 48.8, 10.0, 89.5, 30.0);
3588         }
3589         break;
3590       case ASH:
3591         if (titrationUtils == null) {
3592           aminoAcidRotamerCache[n] = new Rotamer[12];
3593           aminoAcidRotamerCache[n][0] = new Rotamer(name, -68.3, 9.2, -25.7, 31.1, 0, 0);
3594           aminoAcidRotamerCache[n][1] = new Rotamer(name, -169.1, 9.5, 3.9, 38.9, 0, 0);
3595           aminoAcidRotamerCache[n][2] = new Rotamer(name, 63.7, 9.9, 2.4, 29.4, 0, 0);
3596           aminoAcidRotamerCache[n][3] = new Rotamer(name, -68.3, 9.2, 154.3, 31.1, 0, 0);
3597           aminoAcidRotamerCache[n][4] = new Rotamer(name, -169.1, 9.5, -176.1, 38.9, 0, 0);
3598           aminoAcidRotamerCache[n][5] = new Rotamer(name, 63.7, 9.9, -177.6, 29.4, 0, 0);
3599           aminoAcidRotamerCache[n][6] = new Rotamer(name, -68.3, 9.2, -25.7, 31.1, 180, 0);
3600           aminoAcidRotamerCache[n][7] = new Rotamer(name, -169.1, 9.5, 3.9, 38.9, 180, 0);
3601           aminoAcidRotamerCache[n][8] = new Rotamer(name, 63.7, 9.9, 2.4, 29.4, 180, 0);
3602           aminoAcidRotamerCache[n][9] = new Rotamer(name, -68.3, 9.2, 154.3, 31.1, 180, 0);
3603           aminoAcidRotamerCache[n][10] = new Rotamer(name, -169.1, 9.5, -176.1, 38.9, 180, 0);
3604           aminoAcidRotamerCache[n][11] = new Rotamer(name, 63.7, 9.9, -177.6, 29.4, 180, 0);
3605 
3606         } else {
3607           // ASH Rotamers
3608           aminoAcidRotamerCache[n] = new Rotamer[15];
3609           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.ASH,
3610               titrationUtils, -68.3, 9.2, -25.7, 31.1, 0, 0);
3611           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.ASH,
3612               titrationUtils, -169.1, 9.5, 3.9, 38.9, 0, 0);
3613           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.ASH,
3614               titrationUtils, 63.7, 9.9, 2.4, 29.4, 0, 0);
3615           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.ASH,
3616               titrationUtils, -68.3, 9.2, 154.3, 31.1, 0, 0);
3617           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.ASH,
3618               titrationUtils, -169.1, 9.5, -176.1, 38.9, 0, 0);
3619           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.ASH,
3620               titrationUtils, 63.7, 9.9, -177.6, 29.4, 0, 0);
3621           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.ASH,
3622                   titrationUtils, -68.3, 9.2, -25.7, 31.1, 180, 0);
3623           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.ASH,
3624                   titrationUtils, -169.1, 9.5, 3.9, 38.9, 180, 0);
3625           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.ASH,
3626                   titrationUtils, 63.7, 9.9, 2.4, 29.4, 180, 0);
3627           aminoAcidRotamerCache[n][9] = new Rotamer(AminoAcid3.ASH,
3628                   titrationUtils, -68.3, 9.2, 154.3, 31.1, 180, 0);
3629           aminoAcidRotamerCache[n][10] = new Rotamer(AminoAcid3.ASH,
3630                   titrationUtils, -169.1, 9.5, -176.1, 38.9, 180, 0);
3631           aminoAcidRotamerCache[n][11] = new Rotamer(AminoAcid3.ASH,
3632                   titrationUtils, 63.7, 9.9, -177.6, 29.4, 180, 0);
3633           // ASP Rotamers
3634           aminoAcidRotamerCache[n][12] = new Rotamer(AminoAcid3.ASP,
3635               titrationUtils, -68.3, 9.2, -25.7, 31.1);
3636           aminoAcidRotamerCache[n][13] = new Rotamer(AminoAcid3.ASP,
3637               titrationUtils, -169.1, 9.5, 3.9, 38.9);
3638           aminoAcidRotamerCache[n][14] = new Rotamer(AminoAcid3.ASP,
3639               titrationUtils, 63.7, 9.9, 2.4, 29.4);
3640         }
3641         break;
3642       case ASP:
3643         aminoAcidRotamerCache[n] = new Rotamer[3];
3644         aminoAcidRotamerCache[n][0] = new Rotamer(name, -68.3, 9.2, -25.7, 31.1);
3645         aminoAcidRotamerCache[n][1] = new Rotamer(name, -169.1, 9.5, 3.9, 38.9);
3646         aminoAcidRotamerCache[n][2] = new Rotamer(name, 63.7, 9.9, 2.4, 29.4);
3647         break;
3648       case ASN:
3649         aminoAcidRotamerCache[n] = new Rotamer[6];
3650         aminoAcidRotamerCache[n][0] = new Rotamer(name, -68.3, 12.3, -36.8, 25.2);
3651         aminoAcidRotamerCache[n][1] = new Rotamer(name, -177.1, 8.8, 1.3, 34.1);
3652         aminoAcidRotamerCache[n][2] = new Rotamer(name, -67.2, 10.8, 128.8, 24.2);
3653         aminoAcidRotamerCache[n][3] = new Rotamer(name, 63.9, 3.7, -6.8, 13.5);
3654         aminoAcidRotamerCache[n][4] = new Rotamer(name, -174.9, 17.9, -156.8, 58.9);
3655         aminoAcidRotamerCache[n][5] = new Rotamer(name, 63.6, 6.6, 53.8, 17.1);
3656         break;
3657       case GLU:
3658         aminoAcidRotamerCache[n] = new Rotamer[7];
3659         aminoAcidRotamerCache[n][0] = new Rotamer(name, -69.6, 19.2, -177.2, 21.7, -11.4, 44.8);
3660         aminoAcidRotamerCache[n][1] = new Rotamer(name, -176.2, 14.9, 175.4, 10.6, -6.7, 39.0);
3661         aminoAcidRotamerCache[n][2] = new Rotamer(name, -64.6, 13.5, -69.1, 17.3, -33.4, 27.4);
3662         aminoAcidRotamerCache[n][3] = new Rotamer(name, -55.6, 10.6, 77.0, 6.8, 25.3, 32.6);
3663         aminoAcidRotamerCache[n][4] = new Rotamer(name, 69.8, 10.6, -179.0, 23.7, 6.6, 64.2);
3664         aminoAcidRotamerCache[n][5] = new Rotamer(name, -173.6, 14.6, 70.6, 8.7, 14.0, 37.1);
3665         aminoAcidRotamerCache[n][6] = new Rotamer(name, 63.0, 4.3, -80.4, 13.9, 16.3, 20.8);
3666         break;
3667       case GLH:
3668         if (titrationUtils == null) {
3669           aminoAcidRotamerCache[n] = new Rotamer[28];
3670           aminoAcidRotamerCache[n][0] = new Rotamer(name, -69.6, 19.2, -177.2, 21.7, -11.4, 44.8, 0, 0);
3671           aminoAcidRotamerCache[n][1] = new Rotamer(name, -176.2, 14.9, 175.4, 10.6, -6.7, 39.0, 0, 0);
3672           aminoAcidRotamerCache[n][2] = new Rotamer(name, -64.6, 13.5, -69.1, 17.3, -33.4, 27.4, 0, 0);
3673           aminoAcidRotamerCache[n][3] = new Rotamer(name, -55.6, 10.6, 77.0, 6.8, 25.3, 32.6, 0, 0);
3674           aminoAcidRotamerCache[n][4] = new Rotamer(name, 69.8, 10.6, -179.0, 23.7, 6.6, 64.2, 0, 0);
3675           aminoAcidRotamerCache[n][5] = new Rotamer(name, -173.6, 14.6, 70.6, 8.7, 14.0, 37.1, 0, 0);
3676           aminoAcidRotamerCache[n][6] = new Rotamer(name, 63.0, 4.3, -80.4, 13.9, 16.3, 20.8, 0, 0);
3677           aminoAcidRotamerCache[n][7] = new Rotamer(name, -69.6, 19.2, -177.2, 21.7, 168.6, 44.8, 0, 0);
3678           aminoAcidRotamerCache[n][8] = new Rotamer(name, -176.2, 14.9, 175.4, 10.6, 175.3, 39.0, 0, 0);
3679           aminoAcidRotamerCache[n][9] = new Rotamer(name, -64.6, 13.5, -69.1, 17.3, 146.6, 27.4, 0, 0);
3680           aminoAcidRotamerCache[n][10] = new Rotamer(name, -55.6, 10.6, 77.0, 6.8, -154.7, 32.6, 0, 0);
3681           aminoAcidRotamerCache[n][11] = new Rotamer(name, 69.8, 10.6, -179.0, 23.7, -173.4, 64.2, 0, 0);
3682           aminoAcidRotamerCache[n][12] = new Rotamer(name, -173.6, 14.6, 70.6, 8.7, -166.0, 37.1, 0, 0);
3683           aminoAcidRotamerCache[n][13] = new Rotamer(name, 63.0, 4.3, -80.4, 13.9, -163.7, 20.8, 0, 0);
3684           aminoAcidRotamerCache[n][14] = new Rotamer(name, -69.6, 19.2, -177.2, 21.7, -11.4, 44.8, 180, 0);
3685           aminoAcidRotamerCache[n][15] = new Rotamer(name, -176.2, 14.9, 175.4, 10.6, -6.7, 39.0, 180, 0);
3686           aminoAcidRotamerCache[n][16] = new Rotamer(name, -64.6, 13.5, -69.1, 17.3, -33.4, 27.4, 180, 0);
3687           aminoAcidRotamerCache[n][17] = new Rotamer(name, -55.6, 10.6, 77.0, 6.8, 25.3, 32.6, 180, 0);
3688           aminoAcidRotamerCache[n][18] = new Rotamer(name, 69.8, 10.6, -179.0, 23.7, 6.6, 64.2, 180, 0);
3689           aminoAcidRotamerCache[n][19] = new Rotamer(name, -173.6, 14.6, 70.6, 8.7, 14.0, 37.1, 180, 0);
3690           aminoAcidRotamerCache[n][20] = new Rotamer(name, 63.0, 4.3, -80.4, 13.9, 16.3, 20.8, 180, 0);
3691           aminoAcidRotamerCache[n][21] = new Rotamer(name, -69.6, 19.2, -177.2, 21.7, 168.6, 44.8, 180, 0);
3692           aminoAcidRotamerCache[n][22] = new Rotamer(name, -176.2, 14.9, 175.4, 10.6, 175.3, 39.0, 180, 0);
3693           aminoAcidRotamerCache[n][23] = new Rotamer(name, -64.6, 13.5, -69.1, 17.3, 146.6, 27.4, 180, 0);
3694           aminoAcidRotamerCache[n][23] = new Rotamer(name, -55.6, 10.6, 77.0, 6.8, -154.7, 32.6, 180, 0);
3695           aminoAcidRotamerCache[n][25] = new Rotamer(name, 69.8, 10.6, -179.0, 23.7, -173.4, 64.2, 180, 0);
3696           aminoAcidRotamerCache[n][26] = new Rotamer(name, -173.6, 14.6, 70.6, 8.7, -166.0, 37.1, 180, 0);
3697           aminoAcidRotamerCache[n][27] = new Rotamer(name, 63.0, 4.3, -80.4, 13.9, -163.7, 20.8, 180, 0);
3698         } else {
3699           aminoAcidRotamerCache[n] = new Rotamer[35];
3700           // GLH rotamers
3701           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.GLH,
3702                   titrationUtils, -69.6, 19.2, -177.2, 21.7, -11.4, 44.8, 0, 0);
3703           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.GLH,
3704                   titrationUtils, -176.2, 14.9, 175.4, 10.6, -6.7, 39.0, 0, 0);
3705           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.GLH,
3706                   titrationUtils,-64.6, 13.5, -69.1, 17.3, -33.4, 27.4, 0, 0);
3707           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.GLH,
3708                   titrationUtils, -55.6, 10.6, 77.0, 6.8, 25.3, 32.6, 0, 0);
3709           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.GLH,
3710                   titrationUtils,69.8, 10.6, -179.0, 23.7, 6.6, 64.2, 0, 0);
3711           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.GLH,
3712                   titrationUtils,-173.6, 14.6, 70.6, 8.7, 14.0, 37.1, 0, 0);
3713           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.GLH,
3714                   titrationUtils,63.0, 4.3, -80.4, 13.9, 16.3, 20.8, 0, 0);
3715           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.GLH,
3716                   titrationUtils,-69.6, 19.2, -177.2, 21.7, 168.6, 44.8, 0, 0);
3717           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.GLH,
3718                   titrationUtils,-176.2, 14.9, 175.4, 10.6, 175.3, 39.0, 0, 0);
3719           aminoAcidRotamerCache[n][9] = new Rotamer(AminoAcid3.GLH,
3720                   titrationUtils,-64.6, 13.5, -69.1, 17.3, 146.6, 27.4, 0, 0);
3721           aminoAcidRotamerCache[n][10] = new Rotamer(AminoAcid3.GLH,
3722                   titrationUtils,-55.6, 10.6, 77.0, 6.8, -154.7, 32.6, 0, 0);
3723           aminoAcidRotamerCache[n][11] = new Rotamer(AminoAcid3.GLH,
3724                   titrationUtils,69.8, 10.6, -179.0, 23.7, -173.4, 64.2, 0, 0);
3725           aminoAcidRotamerCache[n][12] = new Rotamer(AminoAcid3.GLH,
3726                   titrationUtils,-173.6, 14.6, 70.6, 8.7, -166.0, 37.1, 0, 0);
3727           aminoAcidRotamerCache[n][13] = new Rotamer(AminoAcid3.GLH,
3728                   titrationUtils,63.0, 4.3, -80.4, 13.9, -163.7, 20.8, 0, 0);
3729           aminoAcidRotamerCache[n][14] = new Rotamer(AminoAcid3.GLH,
3730                   titrationUtils,-69.6, 19.2, -177.2, 21.7, -11.4, 44.8, 180, 0);
3731           aminoAcidRotamerCache[n][15] = new Rotamer(AminoAcid3.GLH,
3732                   titrationUtils, -176.2, 14.9, 175.4, 10.6, -6.7, 39.0, 180, 0);
3733           aminoAcidRotamerCache[n][16] = new Rotamer(AminoAcid3.GLH,
3734                   titrationUtils, -64.6, 13.5, -69.1, 17.3, -33.4, 27.4, 180, 0);
3735           aminoAcidRotamerCache[n][17] = new Rotamer(AminoAcid3.GLH,
3736                   titrationUtils,-55.6, 10.6, 77.0, 6.8, 25.3, 32.6, 180, 0);
3737           aminoAcidRotamerCache[n][18] = new Rotamer(AminoAcid3.GLH,
3738                   titrationUtils, 69.8, 10.6, -179.0, 23.7, 6.6, 64.2, 180, 0);
3739           aminoAcidRotamerCache[n][19] = new Rotamer(AminoAcid3.GLH,
3740                   titrationUtils,-173.6, 14.6, 70.6, 8.7, 14.0, 37.1, 180, 0);
3741           aminoAcidRotamerCache[n][20] = new Rotamer(AminoAcid3.GLH,
3742                   titrationUtils, 63.0, 4.3, -80.4, 13.9, 16.3, 20.8, 180, 0);
3743           aminoAcidRotamerCache[n][21] = new Rotamer(AminoAcid3.GLH,
3744                   titrationUtils, -69.6, 19.2, -177.2, 21.7, 168.6, 44.8, 180, 0);
3745           aminoAcidRotamerCache[n][22] = new Rotamer(AminoAcid3.GLH,
3746                   titrationUtils, -176.2, 14.9, 175.4, 10.6, 175.3, 39.0, 180, 0);
3747           aminoAcidRotamerCache[n][23] = new Rotamer(AminoAcid3.GLH,
3748                   titrationUtils, -64.6, 13.5, -69.1, 17.3, 146.6, 27.4, 180, 0);
3749           aminoAcidRotamerCache[n][23] = new Rotamer(AminoAcid3.GLH,
3750                   titrationUtils, -55.6, 10.6, 77.0, 6.8, -154.7, 32.6, 180, 0);
3751           aminoAcidRotamerCache[n][25] = new Rotamer(AminoAcid3.GLH,
3752                   titrationUtils,69.8, 10.6, -179.0, 23.7, -173.4, 64.2, 180, 0);
3753           aminoAcidRotamerCache[n][26] = new Rotamer(AminoAcid3.GLH,
3754                   titrationUtils,-173.6, 14.6, 70.6, 8.7, -166.0, 37.1, 180, 0);
3755           aminoAcidRotamerCache[n][27] = new Rotamer(AminoAcid3.GLH,
3756                   titrationUtils, 63.0, 4.3, -80.4, 13.9, -163.7, 20.8, 180, 0);
3757           // GLU rotamers
3758           aminoAcidRotamerCache[n][28] = new Rotamer(AminoAcid3.GLU,
3759               titrationUtils, -69.6, 19.2, -177.2, 21.7, -11.4, 44.8);
3760           aminoAcidRotamerCache[n][29] = new Rotamer(AminoAcid3.GLU,
3761               titrationUtils, -176.2, 14.9, 175.4, 10.6, -6.7, 39.0);
3762           aminoAcidRotamerCache[n][30] = new Rotamer(AminoAcid3.GLU,
3763               titrationUtils, -64.6, 13.5, -69.1, 17.3, -33.4, 27.4);
3764           aminoAcidRotamerCache[n][31] = new Rotamer(AminoAcid3.GLU,
3765               titrationUtils, -55.6, 10.6, 77.0, 6.8, 25.3, 32.6);
3766           aminoAcidRotamerCache[n][32] = new Rotamer(AminoAcid3.GLU,
3767               titrationUtils, 69.8, 10.6, -179.0, 23.7, 6.6, 64.2);
3768           aminoAcidRotamerCache[n][33] = new Rotamer(AminoAcid3.GLU,
3769               titrationUtils, -173.6, 14.6, 70.6, 8.7, 14.0, 37.1);
3770           aminoAcidRotamerCache[n][34] = new Rotamer(AminoAcid3.GLU,
3771               titrationUtils, 63.0, 4.3, -80.4, 13.9, 16.3, 20.8);
3772         }
3773         break;
3774       case GLN:
3775         aminoAcidRotamerCache[n] = new Rotamer[10];
3776         aminoAcidRotamerCache[n][0] = new Rotamer(name, -66.7, 14.1, -178.5, 14.9, -24.0, 38.0);
3777         aminoAcidRotamerCache[n][1] = new Rotamer(name, -66.7, 14.1, -178.5, 14.9, 156.0, 38.0);
3778         aminoAcidRotamerCache[n][2] = new Rotamer(name, -174.6, 11.5, -177.7, 17.2, -24.0, 38.0);
3779         aminoAcidRotamerCache[n][3] = new Rotamer(name, -174.6, 11.5, -177.7, 17.2, 156.0, 38.0);
3780         aminoAcidRotamerCache[n][4] = new Rotamer(name, -58.7, 11.2, -63.8, 16.1, -46.3, 27.7);
3781         aminoAcidRotamerCache[n][5] = new Rotamer(name, -51.3, 7.3, -90.4, 22.8, 165.0, 38.2);
3782         aminoAcidRotamerCache[n][6] = new Rotamer(name, -179.4, 21.5, 67.3, 7.9, 26.8, 38.4);
3783         aminoAcidRotamerCache[n][7] = new Rotamer(name, 167.5, 14.8, 70.9, 3.7, 174.2, 7.1);
3784         aminoAcidRotamerCache[n][8] = new Rotamer(name, 70.8, 13.0, -165.6, 9.5, -24.0, 38.0);
3785         aminoAcidRotamerCache[n][9] = new Rotamer(name, 70.8, 13.0, -165.6, 9.5, 156.0, 38.0);
3786         break;
3787       case MET:
3788         aminoAcidRotamerCache[n] = new Rotamer[13];
3789         aminoAcidRotamerCache[n][0] = new Rotamer(name, -64.5, 12.7, -68.5, 6.0, -75.6, 14.1);
3790         aminoAcidRotamerCache[n][1] = new Rotamer(name, -78.3, 5.4, -174.7, 15.7, 65.0, 20.0);
3791         aminoAcidRotamerCache[n][2] = new Rotamer(name, -78.3, 5.4, -174.7, 15.7, 180.0, 20.0);
3792         aminoAcidRotamerCache[n][3] = new Rotamer(name, -78.3, 5.4, -174.7, 15.7, -65.0, 20.0);
3793         aminoAcidRotamerCache[n][4] = new Rotamer(name, 178.9, 8.7, 179.0, 13.4, 65.0, 20.0);
3794         aminoAcidRotamerCache[n][5] = new Rotamer(name, 178.9, 8.7, 179.0, 13.4, 65.0, 20.0);
3795         aminoAcidRotamerCache[n][6] = new Rotamer(name, 178.9, 8.7, 179.0, 13.4, -65.0, 20.0);
3796         aminoAcidRotamerCache[n][7] = new Rotamer(name, -70.0, 21.0, -65.0, 20.0, 65.0, 20.0);
3797         aminoAcidRotamerCache[n][8] = new Rotamer(name, -170.0, 24.0, 65.0, 20.0, 180.0, 20.0);
3798         aminoAcidRotamerCache[n][9] = new Rotamer(name, -170.0, 24.0, -65.0, 20.0, 180.0, 20.0);
3799         aminoAcidRotamerCache[n][10] = new Rotamer(name, -70.0, 21.0, 65.0, 20.0, 180.0, 20.0);
3800         aminoAcidRotamerCache[n][11] = new Rotamer(name, -70.0, 21.0, -65.0, 20.0, 180.0, 20.0);
3801         aminoAcidRotamerCache[n][12] = new Rotamer(name, 61.0, 21.0, 65.0, 20.0, 180.0, 20.0);
3802         break;
3803       case LYS:
3804       case LYD:
3805         if (titrationUtils == null) {
3806           aminoAcidRotamerCache[n] = new Rotamer[12];
3807           aminoAcidRotamerCache[n][0] = new Rotamer(name,
3808               -170.0, 24.0, 180.0, 20.0, 65.0, 20.0, 180.0, 20.0);
3809           aminoAcidRotamerCache[n][1] = new Rotamer(name,
3810               -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, 65.0, 20.0);
3811           aminoAcidRotamerCache[n][2] = new Rotamer(name,
3812               -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3813           aminoAcidRotamerCache[n][3] = new Rotamer(name,
3814               -170.0, 24.0, 180.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3815           aminoAcidRotamerCache[n][4] = new Rotamer(name,
3816               -170.0, 24.0, -65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3817           aminoAcidRotamerCache[n][5] = new Rotamer(name,
3818               -70.0, 21.0, 65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3819           aminoAcidRotamerCache[n][6] = new Rotamer(name,
3820               -70.0, 21.0, 180.0, 20.0, 65.0, 20.0, 180.0, 20.0);
3821           aminoAcidRotamerCache[n][7] = new Rotamer(name
3822               , -70.0, 21.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3823           aminoAcidRotamerCache[n][8] = new Rotamer(name,
3824               -70.0, 21.0, 180.0, 20.0, 180.0, 20.0, -65.0, 20.0);
3825           aminoAcidRotamerCache[n][9] = new Rotamer(name,
3826               -70.0, 21.0, 180.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3827           aminoAcidRotamerCache[n][10] = new Rotamer(name,
3828               -70.0, 21.0, -65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3829           aminoAcidRotamerCache[n][11] = new Rotamer(name,
3830               -70.0, 21.0, -65.0, 20.0, 180.0, 20.0, -65.0, 20.0);
3831         } else {
3832           aminoAcidRotamerCache[n] = new Rotamer[24];
3833           // LYS
3834           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.LYS,
3835               titrationUtils, -170.0, 24.0, 180.0, 20.0, 65.0, 20.0, 180.0, 20.0);
3836           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.LYS,
3837               titrationUtils, -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, 65.0, 20.0);
3838           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.LYS,
3839               titrationUtils, -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3840           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.LYS,
3841               titrationUtils, -170.0, 24.0, 180.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3842           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.LYS,
3843               titrationUtils, -170.0, 24.0, -65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3844           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.LYS,
3845               titrationUtils, -70.0, 21.0, 65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3846           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.LYS,
3847               titrationUtils, -70.0, 21.0, 180.0, 20.0, 65.0, 20.0, 180.0, 20.0);
3848           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.LYS,
3849               titrationUtils, -70.0, 21.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3850           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.LYS,
3851               titrationUtils, -70.0, 21.0, 180.0, 20.0, 180.0, 20.0, -65.0, 20.0);
3852           aminoAcidRotamerCache[n][9] = new Rotamer(AminoAcid3.LYS,
3853               titrationUtils, -70.0, 21.0, 180.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3854           aminoAcidRotamerCache[n][10] = new Rotamer(AminoAcid3.LYS,
3855               titrationUtils, -70.0, 21.0, -65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3856           aminoAcidRotamerCache[n][11] = new Rotamer(AminoAcid3.LYS,
3857               titrationUtils, -70.0, 21.0, -65.0, 20.0, 180.0, 20.0, -65.0, 20.0);
3858           // LYD
3859           aminoAcidRotamerCache[n][12] = new Rotamer(AminoAcid3.LYD,
3860               titrationUtils, -170.0, 24.0, 180.0, 20.0, 65.0, 20.0, 180.0, 20.0);
3861           aminoAcidRotamerCache[n][13] = new Rotamer(AminoAcid3.LYD,
3862               titrationUtils, -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, 65.0, 20.0);
3863           aminoAcidRotamerCache[n][14] = new Rotamer(AminoAcid3.LYD,
3864               titrationUtils, -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3865           aminoAcidRotamerCache[n][15] = new Rotamer(AminoAcid3.LYD,
3866               titrationUtils, -170.0, 24.0, 180.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3867           aminoAcidRotamerCache[n][16] = new Rotamer(AminoAcid3.LYD,
3868               titrationUtils, -170.0, 24.0, -65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3869           aminoAcidRotamerCache[n][17] = new Rotamer(AminoAcid3.LYD,
3870               titrationUtils, -70.0, 21.0, 65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3871           aminoAcidRotamerCache[n][18] = new Rotamer(AminoAcid3.LYD,
3872               titrationUtils, -70.0, 21.0, 180.0, 20.0, 65.0, 20.0, 180.0, 20.0);
3873           aminoAcidRotamerCache[n][19] = new Rotamer(AminoAcid3.LYD,
3874               titrationUtils, -70.0, 21.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3875           aminoAcidRotamerCache[n][20] = new Rotamer(AminoAcid3.LYD,
3876               titrationUtils, -70.0, 21.0, 180.0, 20.0, 180.0, 20.0, -65.0, 20.0);
3877           aminoAcidRotamerCache[n][21] = new Rotamer(AminoAcid3.LYD,
3878               titrationUtils, -70.0, 21.0, 180.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3879           aminoAcidRotamerCache[n][22] = new Rotamer(AminoAcid3.LYD,
3880               titrationUtils, -70.0, 21.0, -65.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3881           aminoAcidRotamerCache[n][23] = new Rotamer(AminoAcid3.LYD,
3882               titrationUtils, -70.0, 21.0, -65.0, 20.0, 180.0, 20.0, -65.0, 20.0);
3883         }
3884         break;
3885       case ARG:
3886         aminoAcidRotamerCache[n] = new Rotamer[14];
3887         aminoAcidRotamerCache[n][0] =
3888             new Rotamer(name, 61.0, 25.0, 180.0, 20.0, 65.0, 20.0, 90.0, 20.0);
3889         aminoAcidRotamerCache[n][1] =
3890             new Rotamer(name, 61.0, 25.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3891         aminoAcidRotamerCache[n][2] =
3892             new Rotamer(name, -170.0, 24.0, 180.0, 20.0, 65.0, 20.0, 90.0, 20.0);
3893         aminoAcidRotamerCache[n][3] =
3894             new Rotamer(name, -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, 90.0, 20.0);
3895         aminoAcidRotamerCache[n][4] =
3896             new Rotamer(name, -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3897         aminoAcidRotamerCache[n][5] =
3898             new Rotamer(name, -170.0, 24.0, 180.0, 20.0, 180.0, 20.0, -90.0, 20.0);
3899         aminoAcidRotamerCache[n][6] =
3900             new Rotamer(name, -170.0, 24.0, 180.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3901         aminoAcidRotamerCache[n][7] =
3902             new Rotamer(name, -70.0, 21.0, 180.0, 20.0, 65.0, 20.0, 90.0, 20.0);
3903         aminoAcidRotamerCache[n][8] =
3904             new Rotamer(name, -70.0, 21.0, 180.0, 20.0, 65.0, 20.0, 180.0, 20.0);
3905         aminoAcidRotamerCache[n][9] =
3906             new Rotamer(name, -70.0, 21.0, 180.0, 20.0, 180.0, 20.0, 180.0, 20.0);
3907         aminoAcidRotamerCache[n][10] =
3908             new Rotamer(name, -70.0, 21.0, 180.0, 20.0, 180.0, 20.0, -90.0, 20.0);
3909         aminoAcidRotamerCache[n][11] =
3910             new Rotamer(name, -70.0, 21.0, 180.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3911         aminoAcidRotamerCache[n][12] =
3912             new Rotamer(name, -170.0, 21.0, 65.0, 20.0, 65.0, 20.0, 180.0, 20.0);
3913         aminoAcidRotamerCache[n][13] =
3914             new Rotamer(name, -70.0, 21.0, -65.0, 20.0, -65.0, 20.0, 180.0, 20.0);
3915         break;
3916       default:
3917         // Handles GLY, ALA, CYX, ...
3918         break;
3919     }
3920     return aminoAcidRotamerCache[n];
3921   }
3922 
3923   /**
3924    * Fills the idealized amino acid rotamer cache with the Richardson rotamers.
3925    *
3926    * <p>Lovell, S. C.; Word, J. M.; Richardson, J. S.; Richardson, D. C., The penultimate rotamer
3927    * library. Proteins-Structure, Function, and Genetics 2000, 40 (3), 389-408.
3928    *
3929    * @param name Type of amino acid.
3930    * @return Rotamer cache (double[] of torsions).
3931    */
3932   private Rotamer[] getRichardsonRotamers(AminoAcid3 name, TitrationUtils titrationUtils) {
3933     int n = name.ordinal();
3934     if (aminoAcidRotamerCache[n] != null) {
3935       return aminoAcidRotamerCache[n];
3936     }
3937     switch (name) {
3938       case VAL:
3939         aminoAcidRotamerCache[n] = new Rotamer[3];
3940         aminoAcidRotamerCache[n][0] = new Rotamer(name, 64, 0);
3941         aminoAcidRotamerCache[n][1] = new Rotamer(name, 175, 0);
3942         aminoAcidRotamerCache[n][2] = new Rotamer(name, -60, 0);
3943         break;
3944       case LEU:
3945         aminoAcidRotamerCache[n] = new Rotamer[5];
3946         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 80, 0);
3947         aminoAcidRotamerCache[n][1] = new Rotamer(name, -177, 0, 65, 0);
3948         aminoAcidRotamerCache[n][2] = new Rotamer(name, -172, 0, 145, 0);
3949         aminoAcidRotamerCache[n][3] = new Rotamer(name, -85, 0, 65, 0);
3950         aminoAcidRotamerCache[n][4] = new Rotamer(name, -65, 0, 175, 0);
3951         break;
3952       case ILE:
3953         aminoAcidRotamerCache[n] = new Rotamer[7];
3954         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 100, 0);
3955         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 170, 0);
3956         aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, 66, 0);
3957         aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 165, 0);
3958         aminoAcidRotamerCache[n][4] = new Rotamer(name, -65, 0, 100, 0);
3959         aminoAcidRotamerCache[n][5] = new Rotamer(name, -65, 0, 170, 0);
3960         aminoAcidRotamerCache[n][6] = new Rotamer(name, -57, 0, -60, 0);
3961         break;
3962       case SER:
3963         aminoAcidRotamerCache[n] = new Rotamer[18];
3964         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 0, 0);
3965         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 60, 0);
3966         aminoAcidRotamerCache[n][2] = new Rotamer(name, 62, 0, 120, 0);
3967         aminoAcidRotamerCache[n][3] = new Rotamer(name, 62, 0, 180, 0);
3968         aminoAcidRotamerCache[n][4] = new Rotamer(name, 62, 0, -60, 0);
3969         aminoAcidRotamerCache[n][5] = new Rotamer(name, 62, 0, -120, 0);
3970         aminoAcidRotamerCache[n][6] = new Rotamer(name, -177, 0, 0, 0);
3971         aminoAcidRotamerCache[n][7] = new Rotamer(name, -177, 0, 60, 0);
3972         aminoAcidRotamerCache[n][8] = new Rotamer(name, -177, 0, 120, 0);
3973         aminoAcidRotamerCache[n][9] = new Rotamer(name, -177, 0, 180, 0);
3974         aminoAcidRotamerCache[n][10] = new Rotamer(name, -177, 0, -60, 0);
3975         aminoAcidRotamerCache[n][11] = new Rotamer(name, -177, 0, -120, 0);
3976         aminoAcidRotamerCache[n][12] = new Rotamer(name, -65, 0, 0, 0);
3977         aminoAcidRotamerCache[n][13] = new Rotamer(name, -65, 0, 60, 0);
3978         aminoAcidRotamerCache[n][14] = new Rotamer(name, -65, 0, 120, 0);
3979         aminoAcidRotamerCache[n][15] = new Rotamer(name, -65, 0, 180, 0);
3980         aminoAcidRotamerCache[n][16] = new Rotamer(name, -65, 0, -60, 0);
3981         aminoAcidRotamerCache[n][17] = new Rotamer(name, -65, 0, -120, 0);
3982         break;
3983       case THR:
3984         aminoAcidRotamerCache[n] = new Rotamer[18];
3985         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 0, 0);
3986         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 60, 0);
3987         aminoAcidRotamerCache[n][2] = new Rotamer(name, 62, 0, 120, 0);
3988         aminoAcidRotamerCache[n][3] = new Rotamer(name, 62, 0, 180, 0);
3989         aminoAcidRotamerCache[n][4] = new Rotamer(name, 62, 0, -60, 0);
3990         aminoAcidRotamerCache[n][5] = new Rotamer(name, 62, 0, -120, 0);
3991         aminoAcidRotamerCache[n][6] = new Rotamer(name, -175, 0, 0, 0);
3992         aminoAcidRotamerCache[n][7] = new Rotamer(name, -175, 0, 60, 0);
3993         aminoAcidRotamerCache[n][8] = new Rotamer(name, -175, 0, 120, 0);
3994         aminoAcidRotamerCache[n][9] = new Rotamer(name, -175, 0, 180, 0);
3995         aminoAcidRotamerCache[n][10] = new Rotamer(name, -175, 0, -60, 0);
3996         aminoAcidRotamerCache[n][11] = new Rotamer(name, -175, 0, -120, 0);
3997         aminoAcidRotamerCache[n][12] = new Rotamer(name, -65, 0, 0, 0);
3998         aminoAcidRotamerCache[n][13] = new Rotamer(name, -65, 0, 60, 0);
3999         aminoAcidRotamerCache[n][14] = new Rotamer(name, -65, 0, 120, 0);
4000         aminoAcidRotamerCache[n][15] = new Rotamer(name, -65, 0, 180, 0);
4001         aminoAcidRotamerCache[n][16] = new Rotamer(name, -65, 0, -60, 0);
4002         aminoAcidRotamerCache[n][17] = new Rotamer(name, -65, 0, -120, 0);
4003         break;
4004       case CYS:
4005       case CYD:
4006         if(titrationUtils == null){
4007           aminoAcidRotamerCache[n] = new Rotamer[3];
4008           aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0);
4009           aminoAcidRotamerCache[n][1] = new Rotamer(name, -177, 0);
4010           aminoAcidRotamerCache[n][2] = new Rotamer(name, -65, 0);
4011         } else {
4012           aminoAcidRotamerCache[n] = new Rotamer[9];
4013           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.CYS, titrationUtils,62, 0);
4014           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.CYS, titrationUtils,-177, 0);
4015           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.CYS, titrationUtils, -65, 0);
4016           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.CYS, titrationUtils,62, 180);
4017           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.CYS, titrationUtils,-177, 180);
4018           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.CYS, titrationUtils, -65, 18);
4019           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.CYD, titrationUtils,62, 0);
4020           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.CYD, titrationUtils,-177, 0);
4021           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.CYD, titrationUtils, -65, 0);
4022 
4023         }
4024 
4025         break;
4026       case PHE:
4027       case TYD:
4028         aminoAcidRotamerCache[n] = new Rotamer[4];
4029         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 90, 0);
4030         aminoAcidRotamerCache[n][1] = new Rotamer(name, -177, 0, 80, 0);
4031         aminoAcidRotamerCache[n][2] = new Rotamer(name, -65, 0, -85, 0);
4032         aminoAcidRotamerCache[n][3] = new Rotamer(name, -65, 0, -30, 0);
4033         break;
4034       case TYR:
4035         aminoAcidRotamerCache[n] = new Rotamer[8];
4036         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 90, 0, 0, 0);
4037         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 90, 0, 180, 0);
4038         aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, 80, 0, 0, 0);
4039         aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 80, 0, 180, 0);
4040         aminoAcidRotamerCache[n][4] = new Rotamer(name, -65, 0, -85, 0, 0, 0);
4041         aminoAcidRotamerCache[n][5] = new Rotamer(name, -65, 0, -85, 0, 180, 0);
4042         aminoAcidRotamerCache[n][6] = new Rotamer(name, -65, 0, -30, 0, 0, 0);
4043         aminoAcidRotamerCache[n][7] = new Rotamer(name, -65, 0, -30, 0, 180, 0);
4044         break;
4045       case TRP:
4046         aminoAcidRotamerCache[n] = new Rotamer[7];
4047         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, -90, 0);
4048         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 90, 0);
4049         aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, -105, 0);
4050         aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 90, 0);
4051         aminoAcidRotamerCache[n][4] = new Rotamer(name, -65, 0, -90, 0);
4052         aminoAcidRotamerCache[n][5] = new Rotamer(name, -65, 0, -5, 0);
4053         aminoAcidRotamerCache[n][6] = new Rotamer(name, -65, 0, 95, 0);
4054         break;
4055       case HIS:
4056       case HIE:
4057       case HID:
4058         if (titrationUtils == null) {
4059           aminoAcidRotamerCache[n] = new Rotamer[8];
4060           aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, -75, 0);
4061           aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 80, 0);
4062           aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, -165, 0);
4063           aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, -80, 0);
4064           aminoAcidRotamerCache[n][4] = new Rotamer(name, -177, 0, 60, 0);
4065           aminoAcidRotamerCache[n][5] = new Rotamer(name, -65, 0, -70, 0);
4066           aminoAcidRotamerCache[n][6] = new Rotamer(name, -65, 0, 165, 0);
4067           aminoAcidRotamerCache[n][7] = new Rotamer(name, -65, 0, 80, 0);
4068         } else {
4069           // 8 Rotamers x 3 states (HIS, HIE, HID)
4070           aminoAcidRotamerCache[n] = new Rotamer[24];
4071           //HIS
4072           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.HIS, titrationUtils, 62, 0, -75, 0);
4073           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.HIS, titrationUtils, 62, 0, 80, 0);
4074           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.HIS, titrationUtils, -177, 0, -165,
4075               0);
4076           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.HIS, titrationUtils, -177, 0, -80, 0);
4077           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.HIS, titrationUtils, -177, 0, 60, 0);
4078           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.HIS, titrationUtils, -65, 0, -70, 0);
4079           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.HIS, titrationUtils, -65, 0, 165, 0);
4080           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.HIS, titrationUtils, -65, 0, 80, 0);
4081           //HID
4082           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.HID, titrationUtils, 62, 0, -75, 0);
4083           aminoAcidRotamerCache[n][9] = new Rotamer(AminoAcid3.HID, titrationUtils, 62, 0, 80, 0);
4084           aminoAcidRotamerCache[n][10] = new Rotamer(AminoAcid3.HID, titrationUtils, -177, 0, -165,
4085               0);
4086           aminoAcidRotamerCache[n][11] = new Rotamer(AminoAcid3.HID, titrationUtils, -177, 0, -80,
4087               0);
4088           aminoAcidRotamerCache[n][12] = new Rotamer(AminoAcid3.HID, titrationUtils, -177, 0, 60, 0);
4089           aminoAcidRotamerCache[n][13] = new Rotamer(AminoAcid3.HID, titrationUtils, -65, 0, -70, 0);
4090           aminoAcidRotamerCache[n][14] = new Rotamer(AminoAcid3.HID, titrationUtils, -65, 0, 165, 0);
4091           aminoAcidRotamerCache[n][15] = new Rotamer(AminoAcid3.HID, titrationUtils, -65, 0, 80, 0);
4092           //HIE
4093           aminoAcidRotamerCache[n][16] = new Rotamer(AminoAcid3.HIE, titrationUtils, 62, 0, -75, 0);
4094           aminoAcidRotamerCache[n][17] = new Rotamer(AminoAcid3.HIE, titrationUtils, 62, 0, 80, 0);
4095           aminoAcidRotamerCache[n][18] = new Rotamer(AminoAcid3.HIE, titrationUtils, -177, 0, -165,
4096               0);
4097           aminoAcidRotamerCache[n][19] = new Rotamer(AminoAcid3.HIE, titrationUtils, -177, 0, -80,
4098               0);
4099           aminoAcidRotamerCache[n][20] = new Rotamer(AminoAcid3.HIE, titrationUtils, -177, 0, 60, 0);
4100           aminoAcidRotamerCache[n][21] = new Rotamer(AminoAcid3.HIE, titrationUtils, -65, 0, -70, 0);
4101           aminoAcidRotamerCache[n][22] = new Rotamer(AminoAcid3.HIE, titrationUtils, -65, 0, 165, 0);
4102           aminoAcidRotamerCache[n][23] = new Rotamer(AminoAcid3.HIE, titrationUtils, -65, 0, 80, 0);
4103         }
4104 
4105         break;
4106       case ASP:
4107         aminoAcidRotamerCache[n] = new Rotamer[5];
4108         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 10, 0);
4109         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 30, 0);
4110         aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, 0, 0);
4111         aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 65, 0);
4112         aminoAcidRotamerCache[n][4] = new Rotamer(name, -70, 0, -15, 0);
4113         break;
4114       case ASH:
4115         if (titrationUtils == null) {
4116           aminoAcidRotamerCache[n] = new Rotamer[20];
4117           aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 10, 0, 0, 0);
4118           aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 30, 0, 0, 0);
4119           aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, 0, 0, 0, 0);
4120           aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 65, 0, 0, 0);
4121           aminoAcidRotamerCache[n][4] = new Rotamer(name, -70, 0, -15, 0, 0, 0);
4122           aminoAcidRotamerCache[n][5] = new Rotamer(name, 62, 0, -170, 0, 0, 0);
4123           aminoAcidRotamerCache[n][6] = new Rotamer(name, 62, 0, -150, 0, 0, 0);
4124           aminoAcidRotamerCache[n][7] = new Rotamer(name, -177, 0, -180, 0, 0, 0);
4125           aminoAcidRotamerCache[n][8] = new Rotamer(name, -177, 0, -115, 0, 0, 0);
4126           aminoAcidRotamerCache[n][9] = new Rotamer(name, -70, 0, 165, 0, 0, 0);
4127           aminoAcidRotamerCache[n][10] = new Rotamer(name, 62, 0, 10, 0, 180, 0);
4128           aminoAcidRotamerCache[n][11] = new Rotamer(name, 62, 0, 30, 0, 180, 0);
4129           aminoAcidRotamerCache[n][12] = new Rotamer(name, -177, 0, 0, 0, 180, 0);
4130           aminoAcidRotamerCache[n][13] = new Rotamer(name, -177, 0, 65, 0, 180, 0);
4131           aminoAcidRotamerCache[n][14] = new Rotamer(name, -70, 0, -15, 0, 180, 0);
4132           aminoAcidRotamerCache[n][15] = new Rotamer(name, 62, 0, -170, 0, 180, 0);
4133           aminoAcidRotamerCache[n][16] = new Rotamer(name, 62, 0, -150, 0, 180, 0);
4134           aminoAcidRotamerCache[n][17] = new Rotamer(name, -177, 0, -180, 0, 180, 0);
4135           aminoAcidRotamerCache[n][18] = new Rotamer(name, -177, 0, -115, 0, 180, 0);
4136           aminoAcidRotamerCache[n][19] = new Rotamer(name, -70, 0, 165, 0, 180, 0);
4137         } else {
4138           aminoAcidRotamerCache[n] = new Rotamer[25];
4139           //ASH
4140           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.ASH, titrationUtils, 62, 0, 10, 0, 0, 0);
4141           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.ASH, titrationUtils, 62, 0, 30, 0, 0, 0);
4142           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.ASH, titrationUtils, -177, 0, 0, 0, 0, 0);
4143           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.ASH, titrationUtils, -177, 0, 65, 0, 0, 0);
4144           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.ASH, titrationUtils, -70, 0, -15, 0, 0, 0);
4145           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.ASH, titrationUtils, 62, 0, -170, 0, 0, 0);
4146           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.ASH, titrationUtils, 62, 0, -150, 0, 0, 0);
4147           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.ASH, titrationUtils, -177, 0, -180,
4148               0, 0, 0);
4149           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.ASH, titrationUtils, -177, 0, -115,
4150               0, 0, 0);
4151           aminoAcidRotamerCache[n][9] = new Rotamer(AminoAcid3.ASH, titrationUtils, -70, 0, 165, 0, 0, 0);
4152           aminoAcidRotamerCache[n][10] = new Rotamer(AminoAcid3.ASH, titrationUtils,62, 0, 10, 0, 180, 0);
4153           aminoAcidRotamerCache[n][11] = new Rotamer(AminoAcid3.ASH, titrationUtils,62, 0, 30, 0, 180, 0);
4154           aminoAcidRotamerCache[n][12] = new Rotamer(AminoAcid3.ASH, titrationUtils, -177, 0, 0, 0, 180, 0);
4155           aminoAcidRotamerCache[n][13] = new Rotamer(AminoAcid3.ASH, titrationUtils, -177, 0, 65, 0, 180, 0);
4156           aminoAcidRotamerCache[n][14] = new Rotamer(AminoAcid3.ASH, titrationUtils, -70, 0, -15, 0, 180, 0);
4157           aminoAcidRotamerCache[n][15] = new Rotamer(AminoAcid3.ASH, titrationUtils, 62, 0, -170, 0, 180, 0);
4158           aminoAcidRotamerCache[n][16] = new Rotamer(AminoAcid3.ASH, titrationUtils, 62, 0, -150, 0, 180, 0);
4159           aminoAcidRotamerCache[n][17] = new Rotamer(AminoAcid3.ASH, titrationUtils, -177, 0, -180, 0, 180, 0);
4160           aminoAcidRotamerCache[n][18] = new Rotamer(AminoAcid3.ASH, titrationUtils, -177, 0, -115, 0, 180, 0);
4161           aminoAcidRotamerCache[n][19] = new Rotamer(AminoAcid3.ASH, titrationUtils, -70, 0, 165, 0, 180, 0);
4162           //ASP
4163           aminoAcidRotamerCache[n][20] = new Rotamer(AminoAcid3.ASP, titrationUtils, 62, 0, 10, 0);
4164           aminoAcidRotamerCache[n][21] = new Rotamer(AminoAcid3.ASP, titrationUtils, 62, 0, 30, 0);
4165           aminoAcidRotamerCache[n][22] = new Rotamer(AminoAcid3.ASP, titrationUtils, -177, 0, 0, 0);
4166           aminoAcidRotamerCache[n][23] = new Rotamer(AminoAcid3.ASP, titrationUtils, -177, 0, 65, 0);
4167           aminoAcidRotamerCache[n][24] = new Rotamer(AminoAcid3.ASP, titrationUtils, -70, 0, -15, 0);
4168         }
4169 
4170         break;
4171       case ASN:
4172         aminoAcidRotamerCache[n] = new Rotamer[7];
4173         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, -10, 0);
4174         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 30, 0);
4175         aminoAcidRotamerCache[n][2] = new Rotamer(name, -174, 0, -20, 0);
4176         aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 30, 0);
4177         aminoAcidRotamerCache[n][4] = new Rotamer(name, -65, 0, -20, 0);
4178         aminoAcidRotamerCache[n][5] = new Rotamer(name, -65, 0, -75, 0);
4179         aminoAcidRotamerCache[n][6] = new Rotamer(name, -65, 0, 120, 0);
4180         break;
4181       case GLU:
4182         aminoAcidRotamerCache[n] = new Rotamer[8];
4183         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 180, 0, -20, 0);
4184         aminoAcidRotamerCache[n][1] = new Rotamer(name, 70, 0, -80, 0, 0, 0);
4185         aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, 65, 0, 10, 0);
4186         aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 180, 0, 0, 0);
4187         aminoAcidRotamerCache[n][4] = new Rotamer(name, -177, 0, -80, 0, -25, 0);
4188         aminoAcidRotamerCache[n][5] = new Rotamer(name, -65, 0, 85, 0, 0, 0);
4189         aminoAcidRotamerCache[n][6] = new Rotamer(name, -67, 0, -180, 0, -10, 0);
4190         aminoAcidRotamerCache[n][7] = new Rotamer(name, -65, 0, -65, 0, -40, 0);
4191         break;
4192       case GLH:
4193         if (titrationUtils == null) {
4194           aminoAcidRotamerCache[n] = new Rotamer[32];
4195           aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 180, 0, -20, 0, 0, 0);
4196           aminoAcidRotamerCache[n][1] = new Rotamer(name, 70, 0, -80, 0, 0, 0, 0, 0);
4197           aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, 65, 0, 10, 0, 0, 0);
4198           aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 180, 0, 0, 0, 0, 0);
4199           aminoAcidRotamerCache[n][4] = new Rotamer(name, -177, 0, -80, 0, -25, 0, 0, 0);
4200           aminoAcidRotamerCache[n][5] = new Rotamer(name, -65, 0, 85, 0, 0, 0, 0, 0);
4201           aminoAcidRotamerCache[n][6] = new Rotamer(name, -67, 0, -180, 0, -10, 0, 0, 0);
4202           aminoAcidRotamerCache[n][7] = new Rotamer(name, -65, 0, -65, 0, -40, 0, 0, 0);
4203           aminoAcidRotamerCache[n][8] = new Rotamer(name, 62, 0, 180, 0, 160, 0, 0, 0);
4204           aminoAcidRotamerCache[n][9] = new Rotamer(name, 70, 0, -80, 0, -180, 0, 0, 0);
4205           aminoAcidRotamerCache[n][10] = new Rotamer(name, -177, 0, 65, 0, -170, 0, 0, 0);
4206           aminoAcidRotamerCache[n][11] = new Rotamer(name, -177, 0, 180, 0, -180, 0, 0, 0);
4207           aminoAcidRotamerCache[n][12] = new Rotamer(name, -177, 0, -80, 0, 155, 0, 0, 0);
4208           aminoAcidRotamerCache[n][13] = new Rotamer(name, -65, 0, 85, 0, -180, 0, 0, 0);
4209           aminoAcidRotamerCache[n][14] = new Rotamer(name, -67, 0, -180, 0, 170, 0, 0, 0);
4210           aminoAcidRotamerCache[n][15] = new Rotamer(name, -65, 0, -65, 0, 140, 0, 0, 0);
4211           aminoAcidRotamerCache[n][16] = new Rotamer(name, 62, 0, 180, 0, -20, 0, 180, 0);
4212           aminoAcidRotamerCache[n][17] = new Rotamer(name, 70, 0, -80, 0, 0, 0, 180, 0);
4213           aminoAcidRotamerCache[n][18] = new Rotamer(name, -177, 0, 65, 0, 10, 0, 180, 0);
4214           aminoAcidRotamerCache[n][19] = new Rotamer(name, -177, 0, 180, 0, 0, 0, 180, 0);
4215           aminoAcidRotamerCache[n][20] = new Rotamer(name, -177, 0, -80, 0, -25, 0, 180, 0);
4216           aminoAcidRotamerCache[n][21] = new Rotamer(name, -65, 0, 85, 0, 0, 0, 180, 0);
4217           aminoAcidRotamerCache[n][22] = new Rotamer(name, -67, 0, -180, 0, -10, 0, 180, 0);
4218           aminoAcidRotamerCache[n][23] = new Rotamer(name, -65, 0, -65, 0, -40, 0, 180, 0);
4219           aminoAcidRotamerCache[n][24] = new Rotamer(name, 62, 0, 180, 0, 160, 0, 180, 0);
4220           aminoAcidRotamerCache[n][25] = new Rotamer(name, 70, 0, -80, 0, -180, 0, 180, 0);
4221           aminoAcidRotamerCache[n][26] = new Rotamer(name, -177, 0, 65, 0, -170, 0, 180, 0);
4222           aminoAcidRotamerCache[n][27] = new Rotamer(name, -177, 0, 180, 0, -180, 0, 180, 0);
4223           aminoAcidRotamerCache[n][28] = new Rotamer(name, -177, 0, -80, 0, 155, 0, 180, 0);
4224           aminoAcidRotamerCache[n][29] = new Rotamer(name, -65, 0, 85, 0, -180, 0, 180, 0);
4225           aminoAcidRotamerCache[n][30] = new Rotamer(name, -67, 0, -180, 0, 170, 0, 180, 0);
4226           aminoAcidRotamerCache[n][31] = new Rotamer(name, -65, 0, -65, 0, 140, 0, 180, 0);
4227         } else {
4228           aminoAcidRotamerCache[n] = new Rotamer[40];
4229           //GLH
4230           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.GLH, titrationUtils,  62, 0, 180, 0, -20, 0, 0, 0);
4231           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.GLH, titrationUtils,  70, 0, -80, 0, 0, 0, 0, 0);
4232           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, 65, 0, 10, 0, 0, 0);
4233           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, 180, 0, 0, 0, 0, 0);
4234           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, -80, 0, -25, 0, 0, 0);
4235           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -65, 0, 85, 0, 0, 0, 0, 0);
4236           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -67, 0, -180, 0, -10, 0, 0, 0);
4237           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -65, 0, -65, 0, -40, 0, 0, 0);
4238           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.GLH, titrationUtils,  62, 0, 180, 0, 160, 0, 0, 0);
4239           aminoAcidRotamerCache[n][9] = new Rotamer(AminoAcid3.GLH, titrationUtils,  70, 0, -80, 0, -180, 0, 0, 0);
4240           aminoAcidRotamerCache[n][10] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, 65, 0, -170, 0, 0, 0);
4241           aminoAcidRotamerCache[n][11] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, 180, 0, -180, 0, 0, 0);
4242           aminoAcidRotamerCache[n][12] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, -80, 0, 155, 0, 0, 0);
4243           aminoAcidRotamerCache[n][13] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -65, 0, 85, 0, -180, 0, 0, 0);
4244           aminoAcidRotamerCache[n][14] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -67, 0, -180, 0, 170, 0, 0, 0);
4245           aminoAcidRotamerCache[n][15] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -65, 0, -65, 0, 140, 0, 0, 0);
4246           aminoAcidRotamerCache[n][16] = new Rotamer(AminoAcid3.GLH, titrationUtils,  62, 0, 180, 0, -20, 0, 180, 0);
4247           aminoAcidRotamerCache[n][17] = new Rotamer(AminoAcid3.GLH, titrationUtils,  70, 0, -80, 0, 0, 0, 180, 0);
4248           aminoAcidRotamerCache[n][18] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, 65, 0, 10, 0, 180, 0);
4249           aminoAcidRotamerCache[n][19] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, 180, 0, 0, 0, 180, 0);
4250           aminoAcidRotamerCache[n][20] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, -80, 0, -25, 0, 180, 0);
4251           aminoAcidRotamerCache[n][21] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -65, 0, 85, 0, 0, 0, 180, 0);
4252           aminoAcidRotamerCache[n][22] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -67, 0, -180, 0, -10, 0, 180, 0);
4253           aminoAcidRotamerCache[n][23] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -65, 0, -65, 0, -40, 0, 180, 0);
4254           aminoAcidRotamerCache[n][24] = new Rotamer(AminoAcid3.GLH, titrationUtils,  62, 0, 180, 0, 160, 0, 180, 0);
4255           aminoAcidRotamerCache[n][25] = new Rotamer(AminoAcid3.GLH, titrationUtils,  70, 0, -80, 0, -180, 0, 180, 0);
4256           aminoAcidRotamerCache[n][26] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, 65, 0, -170, 0, 180, 0);
4257           aminoAcidRotamerCache[n][27] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, 180, 0, -180, 0, 180, 0);
4258           aminoAcidRotamerCache[n][28] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -177, 0, -80, 0, 155, 0, 180, 0);
4259           aminoAcidRotamerCache[n][29] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -65, 0, 85, 0, -180, 0, 180, 0);
4260           aminoAcidRotamerCache[n][30] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -67, 0, -180, 0, 170, 0, 180, 0);
4261           aminoAcidRotamerCache[n][31] = new Rotamer(AminoAcid3.GLH, titrationUtils,  -65, 0, -65, 0, 140, 0, 180, 0);
4262           //GLU
4263           aminoAcidRotamerCache[n][32] = new Rotamer(AminoAcid3.GLU, titrationUtils, 62, 0, 180, 0,
4264               -20, 0);
4265           aminoAcidRotamerCache[n][33] = new Rotamer(AminoAcid3.GLU, titrationUtils, 70, 0, -80, 0,
4266               0, 0);
4267           aminoAcidRotamerCache[n][34] = new Rotamer(AminoAcid3.GLU, titrationUtils, -177, 0, 65, 0,
4268               10, 0);
4269           aminoAcidRotamerCache[n][35] = new Rotamer(AminoAcid3.GLU, titrationUtils, -177, 0, 180, 0,
4270               0, 0);
4271           aminoAcidRotamerCache[n][36] = new Rotamer(AminoAcid3.GLU, titrationUtils, -177, 0, -80, 0,
4272               -25, 0);
4273           aminoAcidRotamerCache[n][37] = new Rotamer(AminoAcid3.GLU, titrationUtils, -65, 0, 85, 0,
4274               0, 0);
4275           aminoAcidRotamerCache[n][38] = new Rotamer(AminoAcid3.GLU, titrationUtils, -67, 0, -180, 0,
4276               -10, 0);
4277           aminoAcidRotamerCache[n][39] = new Rotamer(AminoAcid3.GLU, titrationUtils, -65, 0, -65, 0,
4278               -40, 0);
4279         }
4280 
4281         break;
4282       case GLN:
4283         aminoAcidRotamerCache[n] = new Rotamer[9];
4284         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 180, 0, 20, 0);
4285         aminoAcidRotamerCache[n][1] = new Rotamer(name, 70, 0, -75, 0, 0, 0);
4286         aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, 65, 0, -100, 0);
4287         aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 65, 0, 60, 0);
4288         aminoAcidRotamerCache[n][4] = new Rotamer(name, -177, 0, 180, 0, 0, 0);
4289         aminoAcidRotamerCache[n][5] = new Rotamer(name, -65, 0, 85, 0, 0, 0);
4290         aminoAcidRotamerCache[n][6] = new Rotamer(name, -67, 0, 180, 0, -25, 0);
4291         aminoAcidRotamerCache[n][7] = new Rotamer(name, -65, 0, -65, 0, -40, 0);
4292         aminoAcidRotamerCache[n][8] = new Rotamer(name, -65, 0, -65, 0, 100, 0);
4293         break;
4294       case MET:
4295         aminoAcidRotamerCache[n] = new Rotamer[13];
4296         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 180, 0, 75, 0);
4297         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 180, 0, -75, 0);
4298         aminoAcidRotamerCache[n][2] = new Rotamer(name, -177, 0, 65, 0, 75, 0);
4299         aminoAcidRotamerCache[n][3] = new Rotamer(name, -177, 0, 65, 0, 180, 0);
4300         aminoAcidRotamerCache[n][4] = new Rotamer(name, -177, 0, 180, 0, 75, 0);
4301         aminoAcidRotamerCache[n][5] = new Rotamer(name, -177, 0, 180, 0, 180, 0);
4302         aminoAcidRotamerCache[n][6] = new Rotamer(name, -177, 0, 180, 0, -75, 0);
4303         aminoAcidRotamerCache[n][7] = new Rotamer(name, -67, 0, 180, 0, 75, 0);
4304         aminoAcidRotamerCache[n][8] = new Rotamer(name, -67, 0, 180, 0, 180, 0);
4305         aminoAcidRotamerCache[n][9] = new Rotamer(name, -67, 0, 180, 0, -75, 0);
4306         aminoAcidRotamerCache[n][10] = new Rotamer(name, -65, 0, -65, 0, 103, 0);
4307         aminoAcidRotamerCache[n][11] = new Rotamer(name, -65, 0, -65, 0, 180, 0);
4308         aminoAcidRotamerCache[n][12] = new Rotamer(name, -65, 0, -65, 0, -70, 0);
4309         break;
4310       case LYS:
4311       case LYD:
4312         if (titrationUtils == null) {
4313           aminoAcidRotamerCache[n] = new Rotamer[27];
4314           aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 180, 0, 68, 0, 180, 0);
4315           aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 180, 0, 180, 0, 65.0, 0);
4316           aminoAcidRotamerCache[n][2] = new Rotamer(name, 62, 0, 180, 0, 180, 0, 180, 0);
4317           aminoAcidRotamerCache[n][3] = new Rotamer(name, 62, 0, 180, 0, 180, 0, -65, 0);
4318           aminoAcidRotamerCache[n][4] = new Rotamer(name, 62, 0, 180, 0, -68, 0, 180, 0);
4319           aminoAcidRotamerCache[n][5] = new Rotamer(name, -177, 0, 68, 0, 180, 0, 65, 0);
4320           aminoAcidRotamerCache[n][6] = new Rotamer(name, -177, 0, 68, 0, 180, 0, 180, 0);
4321           aminoAcidRotamerCache[n][7] = new Rotamer(name, -177, 0, 68, 0, 180, 0, -65, 0);
4322           aminoAcidRotamerCache[n][8] = new Rotamer(name, -177, 0, 180, 0, 68, 0, 65, 0);
4323           aminoAcidRotamerCache[n][9] = new Rotamer(name, -177, 0, 180, 0, 68, 0, 180, 0);
4324           aminoAcidRotamerCache[n][10] = new Rotamer(name, -177, 0, 180, 0, 180, 0, 65, 0);
4325           aminoAcidRotamerCache[n][11] = new Rotamer(name, -177, 0, 180, 0, 180, 0, 180, 0);
4326           aminoAcidRotamerCache[n][12] = new Rotamer(name, -177, 0, 180, 0, 180, 0, -65, 0);
4327           aminoAcidRotamerCache[n][13] = new Rotamer(name, -177, 0, 180, 0, -68, 0, 180, 0);
4328           aminoAcidRotamerCache[n][14] = new Rotamer(name, -177, 0, 180, 0, -68, 0, -65, 0);
4329           aminoAcidRotamerCache[n][15] = new Rotamer(name, -90, 0, 68, 0, 180, 0, 180);
4330           aminoAcidRotamerCache[n][16] = new Rotamer(name, -67, 0, 180, 0, 68, 0, -65, 0);
4331           aminoAcidRotamerCache[n][17] = new Rotamer(name, -67, 0, 180, 0, 68, 0, 180, 0);
4332           aminoAcidRotamerCache[n][18] = new Rotamer(name, -67, 0, 180, 0, 180, 0, 65, 0);
4333           aminoAcidRotamerCache[n][19] = new Rotamer(name, -67, 0, 180, 0, 180, 0, 180, 0);
4334           aminoAcidRotamerCache[n][20] = new Rotamer(name, -67, 0, 180, 0, 180, 0, -65, 0);
4335           aminoAcidRotamerCache[n][21] = new Rotamer(name, -67, 0, 180, 0, -68, 0, 180, 0);
4336           aminoAcidRotamerCache[n][22] = new Rotamer(name, -67, 0, 180, 0, -68, 0, -65, 0);
4337           aminoAcidRotamerCache[n][23] = new Rotamer(name, -62, 0, -68, 0, 180, 0, 65, 0);
4338           aminoAcidRotamerCache[n][24] = new Rotamer(name, -62, 0, -68, 0, 180, 0, 180, 0);
4339           aminoAcidRotamerCache[n][25] = new Rotamer(name, -62, 0, -68, 0, 180, 0, -65, 0);
4340           aminoAcidRotamerCache[n][26] = new Rotamer(name, -62, 0, -68, 0, -68, 0, 180, 0);
4341         } else {
4342           // 27 Rotamers X 2 states (LYD, LYS)
4343           aminoAcidRotamerCache[n] = new Rotamer[54];
4344           //LYD
4345           aminoAcidRotamerCache[n][0] = new Rotamer(AminoAcid3.LYD, titrationUtils, 62, 0, 180, 0,
4346               68, 0, 180, 0);
4347           aminoAcidRotamerCache[n][1] = new Rotamer(AminoAcid3.LYD, titrationUtils, 62, 0, 180, 0,
4348               180, 0, 65.0, 0);
4349           aminoAcidRotamerCache[n][2] = new Rotamer(AminoAcid3.LYD, titrationUtils, 62, 0, 180, 0,
4350               180, 0, 180, 0);
4351           aminoAcidRotamerCache[n][3] = new Rotamer(AminoAcid3.LYD, titrationUtils, 62, 0, 180, 0,
4352               180, 0, -65, 0);
4353           aminoAcidRotamerCache[n][4] = new Rotamer(AminoAcid3.LYD, titrationUtils, 62, 0, 180, 0,
4354               -68, 0, 180, 0);
4355           aminoAcidRotamerCache[n][5] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 68, 0,
4356               180, 0, 65, 0);
4357           aminoAcidRotamerCache[n][6] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 68, 0,
4358               180, 0, 180, 0);
4359           aminoAcidRotamerCache[n][7] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 68, 0,
4360               180, 0, -65, 0);
4361           aminoAcidRotamerCache[n][8] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 180, 0,
4362               68, 0, 65, 0);
4363           aminoAcidRotamerCache[n][9] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 180, 0,
4364               68, 0, 180, 0);
4365           aminoAcidRotamerCache[n][10] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 180, 0,
4366               180, 0, 65, 0);
4367           aminoAcidRotamerCache[n][11] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 180, 0,
4368               180, 0, 180, 0);
4369           aminoAcidRotamerCache[n][12] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 180, 0,
4370               180, 0, -65, 0);
4371           aminoAcidRotamerCache[n][13] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 180, 0,
4372               -68, 0, 180, 0);
4373           aminoAcidRotamerCache[n][14] = new Rotamer(AminoAcid3.LYD, titrationUtils, -177, 0, 180, 0,
4374               -68, 0, -65, 0);
4375           aminoAcidRotamerCache[n][15] = new Rotamer(AminoAcid3.LYD, titrationUtils, -90, 0, 68, 0,
4376               180, 0, 180);
4377           aminoAcidRotamerCache[n][16] = new Rotamer(AminoAcid3.LYD, titrationUtils, -67, 0, 180, 0,
4378               68, 0, -65, 0);
4379           aminoAcidRotamerCache[n][17] = new Rotamer(AminoAcid3.LYD, titrationUtils, -67, 0, 180, 0,
4380               68, 0, 180, 0);
4381           aminoAcidRotamerCache[n][18] = new Rotamer(AminoAcid3.LYD, titrationUtils, -67, 0, 180, 0,
4382               180, 0, 65, 0);
4383           aminoAcidRotamerCache[n][19] = new Rotamer(AminoAcid3.LYD, titrationUtils, -67, 0, 180, 0,
4384               180, 0, 180, 0);
4385           aminoAcidRotamerCache[n][20] = new Rotamer(AminoAcid3.LYD, titrationUtils, -67, 0, 180, 0,
4386               180, 0, -65, 0);
4387           aminoAcidRotamerCache[n][21] = new Rotamer(AminoAcid3.LYD, titrationUtils, -67, 0, 180, 0,
4388               -68, 0, 180, 0);
4389           aminoAcidRotamerCache[n][22] = new Rotamer(AminoAcid3.LYD, titrationUtils, -67, 0, 180, 0,
4390               -68, 0, -65, 0);
4391           aminoAcidRotamerCache[n][23] = new Rotamer(AminoAcid3.LYD, titrationUtils, -62, 0, -68, 0,
4392               180, 0, 65, 0);
4393           aminoAcidRotamerCache[n][24] = new Rotamer(AminoAcid3.LYD, titrationUtils, -62, 0, -68, 0,
4394               180, 0, 180, 0);
4395           aminoAcidRotamerCache[n][25] = new Rotamer(AminoAcid3.LYD, titrationUtils, -62, 0, -68, 0,
4396               180, 0, -65, 0);
4397           aminoAcidRotamerCache[n][26] = new Rotamer(AminoAcid3.LYD, titrationUtils, -62, 0, -68, 0,
4398               -68, 0, 180, 0);
4399           //LYS
4400           aminoAcidRotamerCache[n][27] = new Rotamer(AminoAcid3.LYS, titrationUtils, 62, 0, 180, 0,
4401               68, 0, 180, 0);
4402           aminoAcidRotamerCache[n][28] = new Rotamer(AminoAcid3.LYS, titrationUtils, 62, 0, 180, 0,
4403               180, 0, 65.0, 0);
4404           aminoAcidRotamerCache[n][29] = new Rotamer(AminoAcid3.LYS, titrationUtils, 62, 0, 180, 0,
4405               180, 0, 180, 0);
4406           aminoAcidRotamerCache[n][30] = new Rotamer(AminoAcid3.LYS, titrationUtils, 62, 0, 180, 0,
4407               180, 0, -65, 0);
4408           aminoAcidRotamerCache[n][31] = new Rotamer(AminoAcid3.LYS, titrationUtils, 62, 0, 180, 0,
4409               -68, 0, 180, 0);
4410           aminoAcidRotamerCache[n][32] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 68, 0,
4411               180, 0, 65, 0);
4412           aminoAcidRotamerCache[n][33] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 68, 0,
4413               180, 0, 180, 0);
4414           aminoAcidRotamerCache[n][34] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 68, 0,
4415               180, 0, -65, 0);
4416           aminoAcidRotamerCache[n][35] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 180, 0,
4417               68, 0, 65, 0);
4418           aminoAcidRotamerCache[n][36] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 180, 0,
4419               68, 0, 180, 0);
4420           aminoAcidRotamerCache[n][37] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 180, 0,
4421               180, 0, 65, 0);
4422           aminoAcidRotamerCache[n][38] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 180, 0,
4423               180, 0, 180, 0);
4424           aminoAcidRotamerCache[n][39] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 180, 0,
4425               180, 0, -65, 0);
4426           aminoAcidRotamerCache[n][40] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 180, 0,
4427               -68, 0, 180, 0);
4428           aminoAcidRotamerCache[n][41] = new Rotamer(AminoAcid3.LYS, titrationUtils, -177, 0, 180, 0,
4429               -68, 0, -65, 0);
4430           aminoAcidRotamerCache[n][42] = new Rotamer(AminoAcid3.LYS, titrationUtils, -90, 0, 68, 0,
4431               180, 0, 180);
4432           aminoAcidRotamerCache[n][43] = new Rotamer(AminoAcid3.LYS, titrationUtils, -67, 0, 180, 0,
4433               68, 0, -65, 0);
4434           aminoAcidRotamerCache[n][44] = new Rotamer(AminoAcid3.LYS, titrationUtils, -67, 0, 180, 0,
4435               68, 0, 180, 0);
4436           aminoAcidRotamerCache[n][45] = new Rotamer(AminoAcid3.LYS, titrationUtils, -67, 0, 180, 0,
4437               180, 0, 65, 0);
4438           aminoAcidRotamerCache[n][46] = new Rotamer(AminoAcid3.LYS, titrationUtils, -67, 0, 180, 0,
4439               180, 0, 180, 0);
4440           aminoAcidRotamerCache[n][47] = new Rotamer(AminoAcid3.LYS, titrationUtils, -67, 0, 180, 0,
4441               180, 0, -65, 0);
4442           aminoAcidRotamerCache[n][48] = new Rotamer(AminoAcid3.LYS, titrationUtils, -67, 0, 180, 0,
4443               -68, 0, 180, 0);
4444           aminoAcidRotamerCache[n][49] = new Rotamer(AminoAcid3.LYS, titrationUtils, -67, 0, 180, 0,
4445               -68, 0, -65, 0);
4446           aminoAcidRotamerCache[n][50] = new Rotamer(AminoAcid3.LYS, titrationUtils, -62, 0, -68, 0,
4447               180, 0, 65, 0);
4448           aminoAcidRotamerCache[n][51] = new Rotamer(AminoAcid3.LYS, titrationUtils, -62, 0, -68, 0,
4449               180, 0, 180, 0);
4450           aminoAcidRotamerCache[n][52] = new Rotamer(AminoAcid3.LYS, titrationUtils, -62, 0, -68, 0,
4451               180, 0, -65, 0);
4452           aminoAcidRotamerCache[n][53] = new Rotamer(AminoAcid3.LYS, titrationUtils, -62, 0, -68, 0,
4453               -68, 0, 180, 0);
4454         }
4455 
4456         break;
4457       case ARG:
4458         aminoAcidRotamerCache[n] = new Rotamer[34];
4459         aminoAcidRotamerCache[n][0] = new Rotamer(name, 62, 0, 180, 0, 65, 0, 85, 0);
4460         aminoAcidRotamerCache[n][1] = new Rotamer(name, 62, 0, 180, 0, 65, 0, -175, 0);
4461         aminoAcidRotamerCache[n][2] = new Rotamer(name, 62, 0, 180, 0, 180, 0, 85, 0);
4462         aminoAcidRotamerCache[n][3] = new Rotamer(name, 62, 0, 180, 0, 180, 0, 180, 0);
4463         aminoAcidRotamerCache[n][4] = new Rotamer(name, 62, 0, 180, 0, 180, 0, -85, 0);
4464         aminoAcidRotamerCache[n][5] = new Rotamer(name, 62, 0, 180, 0, -65, 0, 175, 0);
4465         aminoAcidRotamerCache[n][6] = new Rotamer(name, 62, 0, 180, 0, -65, 0, -85, 0);
4466         aminoAcidRotamerCache[n][7] = new Rotamer(name, -177, 0, 65, 0, 65, 0, 85, 0);
4467         aminoAcidRotamerCache[n][8] = new Rotamer(name, -177, 0, 65, 0, 65, 0, -175, 0);
4468         aminoAcidRotamerCache[n][9] = new Rotamer(name, -177, 0, 65, 0, 180, 0, 85, 0);
4469         aminoAcidRotamerCache[n][10] = new Rotamer(name, -177, 0, 65, 0, 180, 0, 180, 0);
4470         aminoAcidRotamerCache[n][11] = new Rotamer(name, -177, 0, 180, 0, 65, 0, 85, 0);
4471         aminoAcidRotamerCache[n][12] = new Rotamer(name, -177, 0, 180, 0, 65, 0, -175, 0);
4472         aminoAcidRotamerCache[n][13] = new Rotamer(name, -177, 0, 180, 0, 65, 0, -105, 0);
4473         aminoAcidRotamerCache[n][14] = new Rotamer(name, -177, 0, 180, 0, 180, 0, 85, 0);
4474         aminoAcidRotamerCache[n][15] = new Rotamer(name, -177, 0, 180, 0, 180, 0, 180, 0);
4475         aminoAcidRotamerCache[n][16] = new Rotamer(name, -177, 0, 180, 0, 180, 0, -85, 0);
4476         aminoAcidRotamerCache[n][17] = new Rotamer(name, -177, 0, 180, 0, -65, 0, 105, 0);
4477         aminoAcidRotamerCache[n][18] = new Rotamer(name, -177, 0, 180, 0, -65, 0, 175, 0);
4478         aminoAcidRotamerCache[n][19] = new Rotamer(name, -177, 0, 180, 0, -65, 0, -85, 0);
4479         aminoAcidRotamerCache[n][20] = new Rotamer(name, -67, 0, 180, 0, 65, 0, 85, 0);
4480         aminoAcidRotamerCache[n][21] = new Rotamer(name, -67, 0, 180, 0, 65, 0, -175, 0);
4481         aminoAcidRotamerCache[n][22] = new Rotamer(name, -67, 0, 180, 0, 65, 0, -105, 0);
4482         aminoAcidRotamerCache[n][23] = new Rotamer(name, -67, 0, 180, 0, 180, 0, 85, 0);
4483         aminoAcidRotamerCache[n][24] = new Rotamer(name, -67, 0, 180, 0, 180, 0, 180, 0);
4484         aminoAcidRotamerCache[n][25] = new Rotamer(name, -67, 0, 180, 0, 180, 0, -85, 0);
4485         aminoAcidRotamerCache[n][26] = new Rotamer(name, -67, 0, 180, 0, -65, 0, 105, 0);
4486         aminoAcidRotamerCache[n][27] = new Rotamer(name, -67, 0, 180, 0, -65, 0, 175, 0);
4487         aminoAcidRotamerCache[n][28] = new Rotamer(name, -67, 0, -167, 0, -65, 0, -85, 0);
4488         aminoAcidRotamerCache[n][29] = new Rotamer(name, -62, 0, -68, 0, 180, 0, 85, 0);
4489         aminoAcidRotamerCache[n][30] = new Rotamer(name, -62, 0, -68, 0, 180, 0, 180, 0);
4490         aminoAcidRotamerCache[n][31] = new Rotamer(name, -62, 0, -68, 0, 180, 0, -85, 0);
4491         aminoAcidRotamerCache[n][32] = new Rotamer(name, -62, 0, -68, 0, -65, 0, 175, 0);
4492         aminoAcidRotamerCache[n][33] = new Rotamer(name, -62, 0, -68, 0, -65, 0, -85, 0);
4493         break;
4494       default:
4495         // Handles GLY, ALA, CYX, PRO, ...
4496         break;
4497     }
4498     return aminoAcidRotamerCache[n];
4499   }
4500 
4501   /**
4502    * Returns the Rotamers for a specified nucleic acid type. Torsion angles are listed from delta
4503    * (i-1) to delta (i), along with standard deviations calculated by Richardson et al.
4504    *
4505    * <p>Citation: Richardson, J.S., et al., RNA backbone: Consensus all-angle conformers and modular
4506    * string nomenclature (an RNA Ontology Consortium contribution). Rna-a Publication of the Rna
4507    * Society, 2008. 14(3): p. 465-481.
4508    *
4509    * @param name Type of nucleic acid.
4510    * @return Rotamer cache (double[] of torsions).
4511    */
4512   private Rotamer[] getRichardsonRNARotamers(NucleicAcid3 name) {
4513     int n = name.ordinal();
4514     if (nucleicAcidRotamerCache[n] != null) {
4515       return nucleicAcidRotamerCache[n];
4516     }
4517     /*
4518      * Comments on rotamers can be found in Richardson et al, 2008.
4519      * Rotamers 0-45 are these rotamers in order.
4520      *
4521      * In the future, subsequent sets of 46 could be these rotamers with
4522      * rotations of either the base as a whole, or portions of the base
4523      * (such as the C6 amino group of adenine).  One suggestion is to use
4524      * %46 if only the backbone information is needed, or integer division
4525      * by 46 if the backbone information is unnecessary.
4526      *
4527      * Torsions are in order delta (i-1), epsilon (i-1), zeta (i-1), alpha,
4528      * beta, gamma, delta.  However, at this moment, only delta through alpha
4529      * (reverse order) are used to build the backbone, and delta (i-1) as
4530      * a binary function to determine what previous sugar pucker to expect.
4531      *
4532      * 1a, 1m, 1L, &a, 7a, 3a, 9a, 1g, 7d, 3d, 5d, 1e, 1c, 1f, 5j, 1b, 1{,
4533      * 3b, 1z, 5z, 7p, 1t, 5q, 1o, 7r, 2a, 4a, 0a, #a, 4g, 6g, 8d, 4d, 6d,
4534      * 2h, 4n, 0i, 6n, 6j, 2[, 4b, 0b, 4p, 6p, 4s, 2o
4535      */
4536     switch (name) {
4537       case ADE:
4538       case GUA:
4539       case CYT:
4540       case URI:
4541       case DAD:
4542       case DGU:
4543       case DCY:
4544       case DTY:
4545       case THY:
4546         nucleicAcidRotamerCache[n] = new Rotamer[46];
4547         nucleicAcidRotamerCache[n][0] =
4548             new Rotamer(name, 81, 4, -148, 10, -71, 7, -65, 8, 174, 8, 54, 6, 81, 3);
4549         nucleicAcidRotamerCache[n][1] =
4550             new Rotamer(name, 84, 5, -142, 16, -68, 15, -68, 16, -138, 12, 58, 10, 86, 7);
4551         nucleicAcidRotamerCache[n][2] =
4552             new Rotamer(name, 86, 4, -115, 6, -92, 13, -56, 8, 138, 4, 62, 10, 79, 5);
4553         nucleicAcidRotamerCache[n][3] =
4554             new Rotamer(name, 82, 5, -169, 7, -95, 6, -64, 9, -178, 10, 51, 7, 82, 5);
4555         nucleicAcidRotamerCache[n][4] =
4556             new Rotamer(name, 83, 4, -143, 23, -138, 14, -57, 9, 161, 15, 49, 6, 82, 3);
4557         nucleicAcidRotamerCache[n][5] =
4558             new Rotamer(name, 85, 4, -144, 24, 173, 14, -71, 12, 164, 16, 46, 7, 85, 6); //
4559         nucleicAcidRotamerCache[n][6] =
4560             new Rotamer(name, 83, 2, -150, 15, 121, 13, -71, 12, 157, 23, 49, 6, 81, 3);
4561         nucleicAcidRotamerCache[n][7] =
4562             new Rotamer(name, 81, 3, -141, 8, -69, 9, 167, 8, 160, 16, 51, 5, 85, 3);
4563         nucleicAcidRotamerCache[n][8] =
4564             new Rotamer(name, 84, 4, -121, 16, -103, 12, 70, 10, 170, 23, 53, 6, 85, 3);
4565         nucleicAcidRotamerCache[n][9] =
4566             new Rotamer(name, 85, 4, -116, 15, -156, 15, 66, 19, -179, 23, 55, 6, 86, 4);
4567         nucleicAcidRotamerCache[n][10] =
4568             new Rotamer(name, 80, 4, -158, 7, 63, 14, 68, 12, 143, 30, 50, 7, 83, 2);
4569         nucleicAcidRotamerCache[n][11] =
4570             new Rotamer(name, 81, 3, -159, 8, -79, 6, -111, 9, 83, 11, 168, 6, 86, 4);
4571         nucleicAcidRotamerCache[n][12] =
4572             new Rotamer(name, 80, 3, -163, 9, -69, 10, 153, 12, -166, 12, 179, 10, 84, 3);
4573         nucleicAcidRotamerCache[n][13] =
4574             new Rotamer(name, 81, 2, -157, 14, -66, 11, 172, 11, 139, 13, 176, 10, 84, 3);
4575         nucleicAcidRotamerCache[n][14] =
4576             new Rotamer(name, 87, 7, -136, 23, 80, 15, 67, 9, 109, 10, 176, 6, 84, 4);
4577         nucleicAcidRotamerCache[n][15] =
4578             new Rotamer(name, 84, 4, -145, 10, -71, 10, -60, 9, 177, 12, 58, 7, 145, 7);
4579         nucleicAcidRotamerCache[n][16] =
4580             new Rotamer(name, 83, 4, -140, 10, -71, 10, -63, 8, -138, 9, 54, 7, 144, 8);
4581         nucleicAcidRotamerCache[n][17] =
4582             new Rotamer(name, 85, 3, -134, 18, 168, 17, -67, 15, 178, 22, 49, 5, 148, 3);
4583         nucleicAcidRotamerCache[n][18] =
4584             new Rotamer(name, 83, 3, -154, 18, -82, 19, -164, 14, 162, 25, 51, 5, 145, 5);
4585         nucleicAcidRotamerCache[n][19] =
4586             new Rotamer(name, 83, 3, -154, 5, 53, 7, 164, 5, 148, 10, 50, 5, 148, 4);
4587         nucleicAcidRotamerCache[n][20] =
4588             new Rotamer(name, 84, 3, -123, 24, -140, 15, 68, 12, -160, 30, 54, 7, 146, 6);
4589         nucleicAcidRotamerCache[n][21] =
4590             new Rotamer(name, 81, 3, -161, 20, -71, 8, 180, 17, -165, 14, 178, 9, 147, 5);
4591         nucleicAcidRotamerCache[n][22] =
4592             new Rotamer(name, 82, 8, -155, 6, 69, 14, 63, 9, 115, 17, 176, 6, 146, 4);
4593         nucleicAcidRotamerCache[n][23] =
4594             new Rotamer(name, 84, 4, -143, 17, -73, 15, -63, 7, -135, 39, -66, 7, 151, 13);
4595         nucleicAcidRotamerCache[n][24] =
4596             new Rotamer(name, 85, 4, -127, 13, -112, 19, 63, 13, -178, 27, -64, 4, 150, 7);
4597         nucleicAcidRotamerCache[n][25] =
4598             new Rotamer(name, 145, 8, -100, 12, -71, 18, -72, 13, -167, 17, 53, 7, 84, 5);
4599         nucleicAcidRotamerCache[n][26] =
4600             new Rotamer(name, 146, 7, -100, 15, 170, 14, -62, 19, 170, 34, 51, 8, 84, 5);
4601         nucleicAcidRotamerCache[n][27] =
4602             new Rotamer(name, 149, 7, -137, 11, 139, 25, -75, 11, 158, 20, 48, 6, 84, 4);
4603         nucleicAcidRotamerCache[n][28] =
4604             new Rotamer(name, 148, 3, -168, 5, 146, 6, -71, 7, 151, 12, 42, 4, 85, 3);
4605         nucleicAcidRotamerCache[n][29] =
4606             new Rotamer(name, 148, 8, -103, 14, 165, 21, -155, 14, 165, 15, 49, 7, 83, 4);
4607         nucleicAcidRotamerCache[n][30] =
4608             new Rotamer(name, 145, 7, -97, 18, 80, 16, -156, 29, -170, 23, 58, 5, 85, 7);
4609         nucleicAcidRotamerCache[n][31] =
4610             new Rotamer(name, 149, 6, -89, 10, -119, 17, 62, 10, 176, 23, 54, 4, 87, 3);
4611         nucleicAcidRotamerCache[n][32] =
4612             new Rotamer(name, 150, 6, -110, 26, -172, 7, 80, 20, -162, 20, 61, 8, 89, 4);
4613         nucleicAcidRotamerCache[n][33] =
4614             new Rotamer(name, 147, 6, -119, 23, 89, 16, 59, 14, 161, 23, 52, 7, 83, 4);
4615         nucleicAcidRotamerCache[n][34] =
4616             new Rotamer(name, 148, 4, -99, 8, -70, 12, -64, 10, 177, 17, 176, 14, 87, 4);
4617         nucleicAcidRotamerCache[n][35] =
4618             new Rotamer(name, 144, 7, -133, 14, -156, 14, 74, 12, -143, 20, -166, 9, 81, 3);
4619         nucleicAcidRotamerCache[n][36] =
4620             new Rotamer(name, 149, 2, -85, 20, 100, 13, 81, 11, -112, 12, -178, 3, 83, 2);
4621         nucleicAcidRotamerCache[n][37] =
4622             new Rotamer(name, 150, 6, -92, 11, 85, 8, 64, 5, -169, 8, 177, 9, 86, 5);
4623         nucleicAcidRotamerCache[n][38] =
4624             new Rotamer(name, 142, 8, -116, 28, 66, 15, 72, 8, 122, 22, -178, 6, 84, 3);
4625         nucleicAcidRotamerCache[n][39] =
4626             new Rotamer(name, 146, 8, -101, 16, -69, 17, -68, 12, -150, 21, 54, 7, 148, 7);
4627         nucleicAcidRotamerCache[n][40] =
4628             new Rotamer(name, 145, 7, -115, 20, 163, 13, -66, 6, 172, 14, 46, 6, 146, 6);
4629         nucleicAcidRotamerCache[n][41] =
4630             new Rotamer(name, 148, 4, -112, 20, 112, 14, -85, 17, 165, 16, 57, 12, 146, 6);
4631         nucleicAcidRotamerCache[n][42] =
4632             new Rotamer(name, 150, 10, -100, 16, -146, 19, 72, 13, -152, 27, 57, 14, 148, 4);
4633         nucleicAcidRotamerCache[n][43] =
4634             new Rotamer(name, 146, 7, -102, 21, 90, 15, 68, 12, 173, 18, 56, 8, 148, 4);
4635         nucleicAcidRotamerCache[n][44] =
4636             new Rotamer(name, 150, 2, -112, 16, 170, 12, -82, 13, 84, 7, 176, 6, 148, 2);
4637         nucleicAcidRotamerCache[n][45] =
4638             new Rotamer(name, 147, 6, -104, 15, -64, 16, -73, 4, -165, 26, -66, 7, 150, 3);
4639         break;
4640       case MP1:
4641       case DP2:
4642       case TP3:
4643       case UNK:
4644       case M2MG:
4645       case H2U:
4646       case M2G:
4647       case OMC:
4648       case OMG:
4649       case PSU:
4650       case M5MC:
4651       case M7MG:
4652       case M5MU:
4653       case M1MA:
4654       case YYG:
4655       default:
4656         break;
4657     }
4658     return nucleicAcidRotamerCache[n];
4659   }
4660 
4661   public enum ProteinLibrary {
4662     PonderAndRichards(1),
4663     Richardson(2),
4664     None(-1);
4665 
4666     private final int oldIntegerConstant;
4667 
4668     ProteinLibrary(int oldConst) {
4669       this.oldIntegerConstant = oldConst;
4670     }
4671 
4672     /**
4673      * Parses a String input to a ProteinLibrary. Can be either a name, or an integer constant.
4674      *
4675      * <p>The name is preferred, but the integer constant is allowed for legacy reasons.
4676      *
4677      * @param input Input to parse.
4678      * @return A ProteinLibrary.
4679      * @throws IllegalArgumentException If no matching ProteinLibrary found.
4680      */
4681     public static ProteinLibrary getProteinLibrary(String input) throws IllegalArgumentException {
4682       if (input.matches("^\\d+$")) {
4683         return int2Library(Integer.parseInt(input));
4684       } else {
4685         return Arrays.stream(ProteinLibrary.values())
4686             .filter((ProteinLibrary pl) -> pl.toString().equalsIgnoreCase(input))
4687             .findAny()
4688             .orElseThrow(
4689                 () ->
4690                     new IllegalArgumentException(
4691                         " No protein library found that corresponds to " + input));
4692       }
4693     }
4694 
4695     /**
4696      * Converts an integer to a corresponding ProteinLibrary.
4697      *
4698      * @param library Index of the library.
4699      * @return A ProteinLibrary.
4700      * @throws IllegalArgumentException If no matching ProteinLibrary found.
4701      */
4702     public static ProteinLibrary intToProteinLibrary(int library) throws IllegalArgumentException {
4703       return int2Library(library);
4704     }
4705 
4706     /**
4707      * Converts an integer to a corresponding ProteinLibrary.
4708      *
4709      * @param library Index of the library.
4710      * @return A ProteinLibrary.
4711      * @throws IllegalArgumentException If no matching ProteinLibrary found.
4712      */
4713     private static ProteinLibrary int2Library(int library) throws IllegalArgumentException {
4714       for (ProteinLibrary lib : ProteinLibrary.values()) {
4715         if (library == lib.oldIntegerConstant) {
4716           return lib;
4717         }
4718       }
4719       throw new IllegalArgumentException(
4720           format(" Could not find a " + "protein rotamer library to correspond with %d!", library));
4721     }
4722   }
4723 
4724   public enum NucleicAcidLibrary {
4725     RICHARDSON
4726   }
4727 
4728   public enum NucleicSugarPucker {
4729     // Used to be 2, 1, and 3 respectively.
4730     C2_ENDO("south"),
4731     C3_ENDO("north"),
4732     C3_EXO();
4733     private final List<String> alternateNames;
4734 
4735     NucleicSugarPucker() {
4736       alternateNames = Collections.emptyList();
4737     }
4738 
4739     NucleicSugarPucker(String aName) {
4740       alternateNames = Collections.singletonList(aName);
4741     }
4742 
4743     /**
4744      * Returns the sugar pucker associated with a delta torsion. Currently does not support the
4745      * C3'-exo DNA-only pucker.
4746      *
4747      * @param delta Delta torsion to check
4748      * @param isDeoxy If DNA (vs. RNA). Presently ignored.
4749      * @return Pucker
4750      */
4751     public static NucleicSugarPucker checkPucker(double delta, boolean isDeoxy) {
4752       /*
4753        * Midpoint between North, South is 115 degrees.
4754        *
4755        * 0-360: North is 0-115 or 295-360.
4756        * -180 to 180: North is -65 to 115.
4757        */
4758       delta = mod(delta, 360.0);
4759       if (delta <= 115 || delta > 295) {
4760         return C3_ENDO;
4761       } else {
4762         return C2_ENDO;
4763       } // TODO: Add else-if to handle C3'-exo pucker.
4764     }
4765   }
4766 
4767   public static class RotamerGuess {
4768 
4769     private final Residue residue;
4770     private final Rotamer rotamer;
4771     private final int rotIndex;
4772     private final double rmsd;
4773 
4774     RotamerGuess(Residue res, Rotamer rot, int index, double rmsDev) {
4775       residue = res;
4776       rotamer = rot;
4777       rotIndex = index;
4778       rmsd = rmsDev;
4779     }
4780 
4781     public double getRMSD() {
4782       return rmsd;
4783     }
4784 
4785     public Residue getResidue() {
4786       return residue;
4787     }
4788 
4789     public Rotamer getRotamer() {
4790       return rotamer;
4791     }
4792 
4793     public String toString() {
4794       return format(
4795           " Residue %7s is most likely in rotamer %2d (%s), with an RMSD of %9.5f degrees.",
4796           residue, rotIndex, rotamer, rmsd);
4797     }
4798   }
4799 
4800   /** Class contains rotamer information for a nonstandard amino acid. */
4801   private static class NonstandardRotLibrary {
4802 
4803     private final String resName;
4804     private final String[] placeRecords; // Must be ordered correctly!
4805     private final List<Rotamer> stdRotamers; // "Library" rotamers for this residue.
4806 
4807     NonstandardRotLibrary(String resname, String[] placeRecords, Rotamer[] stdRotamers) {
4808       this.resName = resname.toUpperCase();
4809       this.placeRecords = Arrays.copyOf(placeRecords, placeRecords.length);
4810       this.stdRotamers = new ArrayList<>(Arrays.asList(stdRotamers));
4811     }
4812 
4813     Rotamer[] getRotamers() {
4814       return stdRotamers.toArray(new Rotamer[0]);
4815     }
4816 
4817     /**
4818      * Checks the angles for a nonstandard residue.
4819      *
4820      * @param residue Residue to measure.
4821      * @param chi Array to be filled up with chi values.
4822      * @param print Verbosity flag.
4823      * @return Number of dihedral angles.
4824      */
4825     int measureNonstdRot(Residue residue, double[] chi, boolean print) {
4826       for (String placeRec : placeRecords) {
4827         String[] toks = placeRec.split("\\s+");
4828         if (toks[0].equalsIgnoreCase("PLACECHI")) {
4829           int chiNum = Integer.parseInt(toks[5]) - 1;
4830           Atom at1 = (Atom) residue.getAtomNode(toks[1]);
4831           Atom at2 = (Atom) residue.getAtomNode(toks[2]);
4832           Atom at3 = (Atom) residue.getAtomNode(toks[3]);
4833           Atom at4 = (Atom) residue.getAtomNode(toks[4]);
4834           Torsion tors = at1.getTorsion(at2, at3, at4);
4835           chi[chiNum] = tors.getValue();
4836           if (print) {
4837             logger.info(tors.toString());
4838           }
4839         }
4840       }
4841       return placeRecords.length;
4842     }
4843 
4844     /**
4845      * Applies a nonstandard rotamer to an amino acid.
4846      *
4847      * @param residue Residue to apply rotamer to.
4848      * @param rotamer The rotamer to apply.
4849      */
4850     void applyNonstdRotamer(Residue residue, Rotamer rotamer) {
4851       if (!residue.getName().equalsIgnoreCase(resName)) {
4852         throw new IllegalArgumentException(
4853             format(" Residue %s is " + "not of type %s", residue, resName));
4854       }
4855       for (String record : placeRecords) {
4856         String[] toks = record.split("\\s+");
4857         Atom at1 = (Atom) residue.getAtomNode(toks[1]);
4858         Atom at2 = (Atom) residue.getAtomNode(toks[2]);
4859         Atom at3 = (Atom) residue.getAtomNode(toks[3]);
4860         Atom at4 = (Atom) residue.getAtomNode(toks[4]);
4861         Bond b12 = at1.getBond(at2);
4862         double dbond = b12.bondType.distance;
4863         Angle a123 = at1.getAngle(at2, at3);
4864         double dang = a123.angleType.angle[a123.nh];
4865         double dtors;
4866         if (toks[0].equalsIgnoreCase("PLACECHI")) {
4867           int chiNum = Integer.parseInt(toks[5]);
4868           dtors = rotamer.angles[chiNum - 1];
4869         } else {
4870           dtors = Double.parseDouble(toks[5]);
4871         }
4872         int chirality = Integer.parseInt(toks[6]);
4873         intxyz(at1, at2, dbond, at3, dang, at4, dtors, chirality);
4874       }
4875     }
4876   }
4877 }