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.crystal;
39  
40  import static org.apache.commons.math3.util.FastMath.abs;
41  import static org.apache.commons.math3.util.FastMath.random;
42  
43  /**
44   * Enumeration of the 7 lattice systems.
45   * <p>
46   * Currently, the SpaceGroup class uses the HEXAGONAL_LATTICE in all cases where its also possible to
47   * use a RHOMBOHEDRAL_LATTICE.
48   * <p>
49   * This includes space groups 146, 148, 155, 160, 161, 166 and 167.
50   *
51   * @author Michael J. Schnieders
52   * @since 1.0
53   */
54  public enum LatticeSystem {
55    TRICLINIC_LATTICE,
56    MONOCLINIC_LATTICE,
57    ORTHORHOMBIC_LATTICE,
58    TETRAGONAL_LATTICE,
59    RHOMBOHEDRAL_LATTICE,
60    HEXAGONAL_LATTICE,
61    CUBIC_LATTICE;
62  
63    /**
64     * Tolerance for checking if the lattice system restrictions are satisfied.
65     * <p>
66     * Set this to 0.0 for strict checking of lattice parameters.
67     * <p>
68     * For an acetamide crystal minimization, 1.0e-16 was too small a tolerance for equivalent lattice
69     * parameters to equate as equal.
70     */
71    private static final double tolerance = 1.0e-15;
72  
73    /**
74     * If the two passed values are the same, within the tolerance, return true.
75     *
76     * @param x1 First value.
77     * @param x2 Second value.
78     * @return Return true if the two values are the same within specified tolerance.
79     */
80    public static boolean check(double x1, double x2) {
81      return abs(x1 - x2) < tolerance;
82    }
83  
84    /**
85     * Reset lattice parameters for the given lattice systems.
86     *
87     * @return New unit cell parameters.
88     */
89    public double[] resetUnitCellParams() {
90      double alpha = 60.0 + random() * 60.0;
91      double beta = 60.0 + random() * 60.0;
92      double gamma = 60.0 + random() * 60.0;
93      double[] params = {0.25 + random(), 0.25 + random(), 0.25 + random(), alpha, beta, gamma};
94      double ab = 0.5 * (params[0] + params[1]);
95      double abc = (params[0] + params[1] + params[2]) / 3.0;
96      switch (this) {
97        default -> {
98          // TRICLINIC -- No restrictions.
99        }
100       case MONOCLINIC_LATTICE -> {
101         // alpha = gamma = 90
102         params[3] = 90.0;
103         params[5] = 90.0;
104       }
105       case ORTHORHOMBIC_LATTICE -> {
106         // alpha = beta = gamma = 90
107         params[3] = 90.0;
108         params[4] = 90.0;
109         params[5] = 90.0;
110       }
111       case TETRAGONAL_LATTICE -> {
112         // a = b, alpha = beta = gamma = 90
113         params[0] = ab;
114         params[1] = ab;
115         params[3] = 90.0;
116         params[4] = 90.0;
117         params[5] = 90.0;
118       }
119       case RHOMBOHEDRAL_LATTICE -> {
120         // a = b = c, alpha = beta = gamma.
121         double angles = (params[3] + params[4] + params[5]) / 3.0;
122         params[0] = abc;
123         params[1] = abc;
124         params[2] = abc;
125         params[3] = angles;
126         params[4] = angles;
127         params[5] = angles;
128       }
129       case HEXAGONAL_LATTICE -> {
130         // a = b, alpha = beta = 90, gamma = 120
131         params[0] = ab;
132         params[1] = ab;
133         params[3] = 90.0;
134         params[4] = 90.0;
135         params[5] = 120.0;
136       }
137       case CUBIC_LATTICE -> {
138         // a = b = c, alpha = beta = gamma = 90
139         params[0] = abc;
140         params[1] = abc;
141         params[2] = abc;
142         params[3] = 90.0;
143         params[4] = 90.0;
144         params[5] = 90.0;
145       }
146     }
147     return params;
148   }
149 
150   /**
151    * Check that the lattice parameters satisfy the restrictions of the lattice systems.
152    *
153    * @param a     the a-axis length.
154    * @param b     the b-axis length.
155    * @param c     the c-axis length.
156    * @param alpha the alpha angle.
157    * @param beta  the beta angle.
158    * @param gamma the gamma angle.
159    * @return True if the restrictions are satisfied, false otherwise.
160    */
161   public boolean validParameters(double a, double b, double c, double alpha, double beta,
162                                  double gamma) {
163     switch (this) {
164       default -> {
165         // TRICLINIC -- No restrictions.
166         return true;
167       }
168       case MONOCLINIC_LATTICE -> {
169         // alpha = gamma = 90
170         return check(alpha, 90.0) && check(gamma, 90.0);
171       }
172       case ORTHORHOMBIC_LATTICE -> {
173         // alpha = beta = gamma = 90
174         return check(alpha, 90.0) && check(beta, 90.0) && check(gamma, 90.0);
175       }
176       case TETRAGONAL_LATTICE -> {
177         // a = b, alpha = beta = gamma = 90
178         return check(a, b) && check(alpha, 90.0) && check(beta, 90.0) && check(gamma, 90.0);
179       }
180       case RHOMBOHEDRAL_LATTICE -> {
181         // a = b = c, alpha = beta = gamma.
182         return check(a, b) && check(b, c) && check(alpha, beta) && check(beta, gamma);
183       }
184       case HEXAGONAL_LATTICE -> {
185         // a = b, alpha = beta = 90, gamma = 120
186         return check(a, b) && check(alpha, 90.0) && check(beta, 90.0) && check(gamma, 120.0);
187       }
188       case CUBIC_LATTICE -> {
189         // a = b = c; alpha = beta = gamma = 90
190         return check(a, b) && check(b, c) && check(alpha, 90.0) && check(beta, 90.0) && check(gamma,
191             90.0);
192       }
193     }
194   }
195 
196   /**
197    * Change the lattice parameters to satisfy the restrictions of the lattice system.
198    *
199    * @param a     the proposed a-axis length.
200    * @param b     the proposed b-axis length.
201    * @param c     the proposed c-axis length.
202    * @param alpha the proposed alpha angle.
203    * @param beta  the proposed beta angle.
204    * @param gamma the proposed gamma angle.
205    * @return Adjusted parameters if the restrictions are satisfied, original parameters otherwise.
206    */
207   public double[] fixParameters(double a, double b, double c, double alpha, double beta,
208                                 double gamma) {
209     double[] parameters = {a, b, c, alpha, beta, gamma};
210     double ab = (parameters[0] + parameters[1]) / 2;
211     double abc = (parameters[0] + parameters[1] + parameters[2]) / 3;
212     switch (this) {
213       default -> {
214         // TRICLINIC -- No restrictions.
215         return parameters;
216       }
217       case MONOCLINIC_LATTICE -> {
218         // alpha = gamma = 90
219         parameters[3] = 90.0;
220         parameters[5] = 90.0;
221         return parameters;
222       }
223       case ORTHORHOMBIC_LATTICE -> {
224         // alpha = beta = gamma = 90
225         parameters[3] = 90.0;
226         parameters[4] = 90.0;
227         parameters[5] = 90.0;
228         return parameters;
229       }
230       case TETRAGONAL_LATTICE -> {
231         // a = b, alpha = beta = gamma = 90
232         parameters[0] = ab;
233         parameters[1] = ab;
234         parameters[3] = 90.0;
235         parameters[4] = 90.0;
236         parameters[5] = 90.0;
237         return parameters;
238       }
239       case RHOMBOHEDRAL_LATTICE -> {
240         // a = b = c, alpha = beta = gamma.
241         double angles = (parameters[3] + parameters[4] + parameters[5]) / 3;
242         parameters[0] = abc;
243         parameters[1] = abc;
244         parameters[2] = abc;
245         parameters[3] = angles;
246         parameters[4] = angles;
247         parameters[5] = angles;
248         return parameters;
249       }
250       case HEXAGONAL_LATTICE -> {
251         // a = b, alpha = beta = 90, gamma = 120
252         parameters[0] = ab;
253         parameters[1] = ab;
254         parameters[3] = 90.0;
255         parameters[4] = 90.0;
256         parameters[5] = 120.0;
257         return parameters;
258       }
259       case CUBIC_LATTICE -> {
260         // a = b = c; alpha = beta = gamma = 90
261         parameters[0] = abc;
262         parameters[1] = abc;
263         parameters[2] = abc;
264         parameters[3] = 90.0;
265         parameters[4] = 90.0;
266         parameters[5] = 90.0;
267         return parameters;
268       }
269     }
270   }
271 
272   /**
273    * Returns the default b-axis for the lattice system.
274    *
275    * @param aaxis the a-axis length is the best guess for b-axis.
276    * @return default b-axis value
277    */
278   public double getDefaultBAxis(double aaxis) {
279     return aaxis;
280   }
281 
282   /**
283    * Returns the default c-axis for the lattice system.
284    *
285    * @return default c-axis value
286    */
287   public double getDefaultCAxis(double aaxis, double baxis) {
288     return (aaxis + baxis) / 2;
289   }
290 
291   /**
292    * Returns the default alpha for the lattice system.
293    *
294    * @return default alpha value
295    */
296   public double getDefaultAlpha() {
297     return 90.0;
298   }
299 
300   /**
301    * Returns the default beta for the lattice system.
302    *
303    * @return default beta value
304    */
305   public double getDefaultBeta() {
306     return 90.0;
307   }
308 
309   /**
310    * Returns the default gamma for the lattice system.
311    *
312    * @return default gamma value
313    */
314   public double getDefaultGamma() {
315     double gamma = 90.0;
316     if (this == HEXAGONAL_LATTICE) {
317       gamma = 120.0;
318     }
319     return gamma;
320   }
321 }