View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2024.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.potential.parameters;
39  
40  import static ffx.potential.parameters.ForceField.ForceFieldType.BIOTYPE;
41  import static ffx.utilities.PropertyGroup.PotentialFunctionParameter;
42  import static java.lang.Integer.parseInt;
43  import static java.lang.String.format;
44  import static java.lang.System.arraycopy;
45  
46  import ffx.utilities.FFXProperty;
47  
48  import java.util.Comparator;
49  import java.util.Objects;
50  import java.util.logging.Level;
51  import java.util.logging.Logger;
52  
53  /**
54   * The BioType class maps PDB identifiers to atom types.
55   *
56   * @author Michael J. Schnieders
57   * @since 1.0
58   */
59  @FFXProperty(name = "biotype", clazz = String.class, propertyGroup = PotentialFunctionParameter, description = """
60      [integer, name, quoted string and integer]
61      Provides the values to define the correspondence between a single bio-polymer atom type and its force field atom type.
62      """)
63  public final class BioType extends BaseType implements Comparator<String> {
64  
65    /**
66     * A Logger for the BioType class.
67     */
68    private static final Logger logger = Logger.getLogger(BioType.class.getName());
69    /**
70     * The PDB atom name for this BioType.
71     */
72    public final String atomName;
73    /**
74     * The PDB molecule name for this BioType.
75     */
76    public final String moleculeName;
77    /**
78     * Bonds are required to listed atom names.
79     */
80    public final String[] bonds;
81    /**
82     * The index of this BioType.
83     */
84    public int index;
85    /**
86     * The force field atom type to be used for the molecule / atom name combination.
87     */
88    public int atomType;
89  
90    /**
91     * BioType Constructor.
92     *
93     * @param index        int
94     * @param atomName     String
95     * @param moleculeName String
96     * @param atomType     int
97     * @param bonds        an array of {@link java.lang.String} objects.
98     */
99    public BioType(int index, String atomName, String moleculeName, int atomType, String[] bonds) {
100     super(BIOTYPE, Integer.toString(index));
101     this.index = index;
102     this.atomName = atomName;
103     if (moleculeName != null) {
104       this.moleculeName = moleculeName.replace(',', ' ').replace('"', ' ').trim();
105     } else {
106       this.moleculeName = null;
107     }
108     this.atomType = atomType;
109     this.bonds = bonds;
110   }
111 
112   /**
113    * Construct an BioType from an input string.
114    *
115    * @param input  The overall input String.
116    * @param tokens The input String tokenized.
117    * @return an BioType instance.
118    */
119   public static BioType parse(String input, String[] tokens) {
120     if (tokens.length < 5) {
121       logger.log(Level.WARNING, "Invalid BIOTYPE type:\n{0}", input);
122     } else {
123       try {
124         int index = parseInt(tokens[1]);
125         String atomName = tokens[2];
126         // The "residue" string may contain spaces,
127         // and is therefore surrounded in quotes located at "first" and
128         // "last".
129         int first = input.indexOf("\"");
130         int last = input.lastIndexOf("\"");
131         if (first >= last) {
132           logger.log(Level.WARNING, "Invalid BIOTYPE type:\n{0}", input);
133           return null;
134         }
135         // Environment
136         String moleculeName = input.substring(first, last + 1).intern();
137         // Shrink the tokens array to only include entries
138         // after the environment field.
139         tokens = input.substring(last + 1).trim().split(" +");
140         int atomType = parseInt(tokens[0]);
141         int bondCount = tokens.length - 1;
142         String[] bonds = null;
143         if (bondCount > 0) {
144           bonds = new String[bondCount];
145           arraycopy(tokens, 1, bonds, 0, bondCount);
146         }
147         return new BioType(index, atomName, moleculeName, atomType, bonds);
148       } catch (NumberFormatException e) {
149         String message = "Exception parsing BIOTYPE type:\n" + input + "\n";
150         logger.log(Level.SEVERE, message, e);
151       }
152     }
153     return null;
154   }
155 
156   /**
157    * {@inheritDoc}
158    */
159   @Override
160   public int compare(String s1, String s2) {
161     int t1 = parseInt(s1);
162     int t2 = parseInt(s2);
163     return Integer.compare(t1, t2);
164   }
165 
166   /**
167    * {@inheritDoc}
168    */
169   @Override
170   public boolean equals(Object o) {
171     if (this == o) {
172       return true;
173     }
174     if (o == null || getClass() != o.getClass()) {
175       return false;
176     }
177     BioType bioType = (BioType) o;
178     return bioType.index == this.index;
179   }
180 
181   /**
182    * {@inheritDoc}
183    */
184   @Override
185   public int hashCode() {
186     return Objects.hash(index);
187   }
188 
189   /**
190    * {@inheritDoc}
191    *
192    * <p>Nicely formatted biotype.
193    */
194   @Override
195   public String toString() {
196     StringBuilder sb =
197         new StringBuilder(
198             format("biotype  %5d  %-4s  \"%-23s\"  %5d", index, atomName, moleculeName, atomType));
199     if (bonds != null) {
200       for (String bond : bonds) {
201         sb.append(format("  %-4s", bond));
202       }
203     }
204     return sb.toString();
205   }
206 
207   /**
208    * incrementIndexAndType
209    *
210    * @param indexIncrement The index increment.
211    * @param typeIncrement  The type increment.
212    */
213   void incrementIndexAndType(int indexIncrement, int typeIncrement) {
214     index += indexIncrement;
215     atomType += typeIncrement;
216     setKey(Integer.toString(index));
217   }
218 }