View Javadoc
1   // ******************************************************************************
2   //
3   // Title:       Force Field X.
4   // Description: Force Field X - Software for Molecular Biophysics.
5   // Copyright:   Copyright (c) Michael J. Schnieders 2001-2025.
6   //
7   // This file is part of Force Field X.
8   //
9   // Force Field X is free software; you can redistribute it and/or modify it
10  // under the terms of the GNU General Public License version 3 as published by
11  // the Free Software Foundation.
12  //
13  // Force Field X is distributed in the hope that it will be useful, but WITHOUT
14  // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16  // details.
17  //
18  // You should have received a copy of the GNU General Public License along with
19  // Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
20  // Place, Suite 330, Boston, MA 02111-1307 USA
21  //
22  // Linking this library statically or dynamically with other modules is making a
23  // combined work based on this library. Thus, the terms and conditions of the
24  // GNU General Public License cover the whole combination.
25  //
26  // As a special exception, the copyright holders of this library give you
27  // permission to link this library with independent modules to produce an
28  // executable, regardless of the license terms of these independent modules, and
29  // to copy and distribute the resulting executable under terms of your choice,
30  // provided that you also meet, for each linked independent module, the terms
31  // and conditions of the license of that module. An independent module is a
32  // module which is not derived from or based on this library. If you modify this
33  // library, you may extend this exception to your version of the library, but
34  // you are not obligated to do so. If you do not wish to do so, delete this
35  // exception statement from your version.
36  //
37  // ******************************************************************************
38  package ffx.numerics.multipole;
39  
40  import jdk.incubator.vector.DoubleVector;
41  
42  import static jdk.incubator.vector.DoubleVector.SPECIES_PREFERRED;
43  import static jdk.incubator.vector.DoubleVector.fromArray;
44  
45  /**
46   * The PolarizableMultipole class defines a polarizable multipole.
47   *
48   * @author Michael J. Schnieders
49   * @since 1.0
50   */
51  public class PolarizableMultipoleSIMD {
52  
53    private static final double oneThird = 1.0 / 3.0;
54    private static final double twoThirds = 2.0 / 3.0;
55  
56    /**
57     * Partial charge.
58     */
59    protected DoubleVector q;
60    /**
61     * Dipole x-component.
62     */
63    protected DoubleVector dx;
64    /**
65     * Dipole y-component.
66     */
67    protected DoubleVector dy;
68    /**
69     * Dipole z-component.
70     */
71    protected DoubleVector dz;
72    /**
73     * Quadrupole xx-component multiplied by 1/3.
74     */
75    protected DoubleVector qxx;
76    /**
77     * Quadrupole yy-component multiplied by 1/3.
78     */
79    protected DoubleVector qyy;
80    /**
81     * Quadrupole zz-component multiplied by 1/3.
82     */
83    protected DoubleVector qzz;
84    /**
85     * Quadrupole xy-component multiplied by 2/3.
86     */
87    protected DoubleVector qxy;
88    /**
89     * Quadrupole xz-component multiplied by 2/3.
90     */
91    protected DoubleVector qxz;
92    /**
93     * Quadrupole xz-component multiplied by 2/3.
94     */
95    protected DoubleVector qyz;
96  
97    /**
98     * Induced dipole x-component.
99     */
100   protected DoubleVector ux;
101   /**
102    * Induced dipole y-component.
103    */
104   protected DoubleVector uy;
105   /**
106    * Induced dipole z-component.
107    */
108   protected DoubleVector uz;
109   /**
110    * Induced dipole chain rule x-component.
111    */
112   protected DoubleVector px;
113   /**
114    * Induced dipole chain rule y-component.
115    */
116   protected DoubleVector py;
117   /**
118    * Induced dipole chain rule z-component.
119    */
120   protected DoubleVector pz;
121   /**
122    * Averaged induced dipole + induced dipole chain-rule x-component: sx = 0.5 * (ux + px).
123    */
124   protected DoubleVector sx;
125   /**
126    * Averaged induced dipole + induced dipole chain-rule y-component: sy = 0.5 * (uy + py).
127    */
128   protected DoubleVector sy;
129   /**
130    * Averaged induced dipole + induced dipole chain-rule z-component: sz = 0.5 * (uz + pz).
131    */
132   protected DoubleVector sz;
133 
134   /**
135    * PolarizableMultipole constructor with zero moments.
136    */
137   public PolarizableMultipoleSIMD() {
138   }
139 
140   /**
141    * PolarizableMultipole constructor.
142    *
143    * @param Q   Multipoles Q[q, dx, dy, dz, qxx, qyy, qzz, qxy, qxz, qyz]
144    * @param u   Induced dipoles u[ux, uy, uz]
145    * @param uCR Induced dipole chain-rules uCR[ux, uy, uz]
146    */
147   public PolarizableMultipoleSIMD(double[][] Q, double[][] u, double[][] uCR) {
148     setPermanentMultipole(Q);
149     setInducedDipole(u, uCR);
150   }
151 
152   /**
153    * Set the permanent multipole.
154    * <p>
155    * Note that the quadrupole trace components are multiplied by 1/3 and the
156    * off-diagonal components are multiplied by 2/3.
157    *
158    * @param Q   Multipoles Q[q, dx, dy, dz, qxx, qyy, qzz, qxy, qxz, qyz]
159    * @param u   Induced dipoles u[ux, uy, uz]
160    * @param uCR Induced dipole chain-rules uCR[ux, uy, uz]
161    */
162   public void set(double[][] Q, double[][] u, double[][] uCR) {
163     setPermanentMultipole(Q);
164     setInducedDipole(u, uCR);
165   }
166 
167   /**
168    * Set the permanent multipole.
169    * <p>
170    * Note that the quadrupole trace components are multiplied by 1/3 and the
171    * off-diagonal components are multiplied by 2/3.
172    *
173    * @param Q Multipole Q[q, dx, dy, dz, qxx, qyy, qzz, qxy, qxz, qyz]
174    */
175   public final void setPermanentMultipole(double[][] Q) {
176     q = fromArray(SPECIES_PREFERRED, Q[0], 0);
177     dx = fromArray(SPECIES_PREFERRED, Q[1], 0);
178     dy = fromArray(SPECIES_PREFERRED, Q[2], 0);
179     dz = fromArray(SPECIES_PREFERRED, Q[3], 0);
180     qxx = fromArray(SPECIES_PREFERRED, Q[4], 0).mul(oneThird);
181     qyy = fromArray(SPECIES_PREFERRED, Q[5], 0).mul(oneThird);
182     qzz = fromArray(SPECIES_PREFERRED, Q[6], 0).mul(oneThird);
183     qxy = fromArray(SPECIES_PREFERRED, Q[7], 0).mul(twoThirds);
184     qxz = fromArray(SPECIES_PREFERRED, Q[8], 0).mul(twoThirds);
185     qyz = fromArray(SPECIES_PREFERRED, Q[9], 0).mul(twoThirds);
186   }
187 
188   /**
189    * Set the induced dipole.
190    *
191    * @param u   Induced dipole u[ux, uy, uz]
192    * @param uCR Induced dipole chain-rule uCR[ux, uy, uz]
193    */
194   public final void setInducedDipole(double[][] u, double[][] uCR) {
195     ux = fromArray(SPECIES_PREFERRED, u[0], 0);
196     uy = fromArray(SPECIES_PREFERRED, u[1], 0);
197     uz = fromArray(SPECIES_PREFERRED, u[2], 0);
198     px = fromArray(SPECIES_PREFERRED, uCR[0], 0);
199     py = fromArray(SPECIES_PREFERRED, uCR[1], 0);
200     pz = fromArray(SPECIES_PREFERRED, uCR[2], 0);
201     sx = ux.add(px).mul(0.5);
202     sy = uy.add(py).mul(0.5);
203     sz = uz.add(pz).mul(0.5);
204   }
205 
206   /**
207    * Compute the scaled and averaged induced dipole.
208    *
209    * @param scaleInduction Induction mask scale factor.
210    * @param scaleEnergy    Energy mask scale factor.
211    */
212   public final void applyMasks(DoubleVector scaleInduction, DoubleVector scaleEnergy) {
213     // [Ux, Uy, Uz] resulted from induction masking rules, and we now apply the energy mask.
214     // [Px, Py, Pz] resulted from energy masking rules, and we now apply the induction mask.
215     sx = ux.mul(scaleEnergy).add(px.mul(scaleInduction)).mul(0.5);
216     sy = uy.mul(scaleEnergy).add(py.mul(scaleInduction)).mul(0.5);
217     sz = uz.mul(scaleEnergy).add(pz.mul(scaleInduction)).mul(0.5);
218   }
219 
220 }