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 }