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.math; 39 40 import javax.annotation.Nullable; 41 42 import static java.lang.String.format; 43 import static org.apache.commons.math3.util.FastMath.abs; 44 import static org.apache.commons.math3.util.FastMath.acos; 45 import static org.apache.commons.math3.util.FastMath.max; 46 import static org.apache.commons.math3.util.FastMath.min; 47 import static org.apache.commons.math3.util.FastMath.sqrt; 48 49 import java.util.logging.Logger; 50 51 /** 52 * The DoubleMath class is a simple math library that operates on 3-coordinate double arrays. 53 * 54 * <p>All methods are static and thread-safe. 55 * 56 * <p>Use instances of Double3 for convenience. 57 * 58 * @author Michael J. Schnieders 59 * @since 1.0 60 */ 61 public final class DoubleMath { 62 63 private static final Logger logger = Logger.getLogger(DoubleMath.class.getName()); 64 65 private DoubleMath() { 66 // Prevent instantiation. 67 } 68 69 /** 70 * Compute a * b + c and return the result in a new array. 71 * 72 * @param a First vector. 73 * @param b Scalar. 74 * @param c Second vector. 75 * @return Returns a * b + c. 76 */ 77 public static double[] fma(double[] a, double b, double[] c) { 78 return fma(a, b, c, new double[3]); 79 } 80 81 /** 82 * Compute a * b + c. 83 * 84 * @param a First vector. 85 * @param b Scalar. 86 * @param c Second vector. 87 * @param ret Result vector. 88 * @return Returns a * b + c. 89 */ 90 public static double[] fma(double[] a, double b, double[] c, double[] ret) { 91 ret[0] = Math.fma(a[0], b, c[0]); 92 ret[1] = Math.fma(a[1], b, c[1]); 93 ret[2] = Math.fma(a[2], b, c[2]); 94 return ret; 95 } 96 97 /** 98 * Finds the cross-product between two vectors 99 * 100 * @param a First vector 101 * @param b Second vector 102 * @return Returns the cross-product. 103 */ 104 public static double[] X(double[] a, double[] b) { 105 return X(a, b, new double[3]); 106 } 107 108 /** 109 * Finds the cross-product between two vectors 110 * 111 * @param a First vector 112 * @param b Second vector 113 * @param ret The cross-product of a x b. 114 * @return Returns the cross-product ret. 115 */ 116 public static double[] X(double[] a, double[] b, double[] ret) { 117 ret[0] = a[1] * b[2] - a[2] * b[1]; 118 ret[1] = a[2] * b[0] - a[0] * b[2]; 119 ret[2] = a[0] * b[1] - a[1] * b[0]; 120 return ret; 121 } 122 123 /** 124 * sum 125 * 126 * @param a an array of double. 127 * @param b an array of double. 128 * @return Returns the sum array. 129 */ 130 public static double[] add(double[] a, double[] b) { 131 return add(a, b, new double[3]); 132 } 133 134 /** 135 * sum 136 * 137 * @param a an array of double. 138 * @param b an array of double. 139 * @param ret an array of double. 140 * @return Returns the array ret. 141 */ 142 public static double[] add(double[] a, double[] b, double[] ret) { 143 ret[0] = a[0] + b[0]; 144 ret[1] = a[1] + b[1]; 145 ret[2] = a[2] + b[2]; 146 return ret; 147 } 148 149 /** 150 * angle 151 * 152 * @param i an array of double. 153 * @param j an array of double. 154 * @return Returns the angle. 155 */ 156 public static double angle(double[] i, double[] j) { 157 var x = dot(normalize(i), normalize(j)); 158 if (abs(x) > 1) { 159 if (x > 0) { 160 x = 1; 161 } else { 162 x = -1; 163 } 164 } 165 return acos(x); 166 } 167 168 /** 169 * Finds the angle formed by three atoms. 170 * 171 * @param i Atom position vector. 172 * @param j Atom position vector (central atom). 173 * @param k Atom position vector. 174 * @return Return the angle in the range [ -pi, pi ]. 175 */ 176 public static double bondAngle(double[] i, double[] j, double[] k) { 177 return angle(sub(i, j), sub(k, j)); 178 } 179 180 /** 181 * Finds the dihedral angle formed between 4 atoms, a, b, c, d, via position 182 * vectors AB, BC, and CD. 183 * 184 * @param ab Position vector AB. 185 * @param bc Position vector BC. 186 * @param cd Position vector CD. 187 * @return The dihedral angle in the range [ -pi, pi ]. 188 */ 189 public static double dihedralAngle(double[] ab, double[] bc, double[] cd) { 190 var t = X(ab, bc); 191 var u = X(bc, cd); 192 var rt = dot(t, t); 193 var ru = dot(u, u); 194 var rtu = sqrt(rt * ru); 195 if (rtu != 0.0) { 196 var rcb = length(bc); 197 var cosine = dot(t, u) / rtu; 198 var tu = X(t, u); 199 var sine = dot(bc, tu) / (rcb * rtu); 200 cosine = min(1.0, max(-1.0, cosine)); 201 var angle = acos(cosine); 202 if (sine < 0.0) { 203 angle = -angle; 204 } 205 return angle; 206 } 207 return 0; 208 } 209 210 /** 211 * Finds the dihedral angle formed between 4 atoms. 212 * 213 * @param a Atom position vector. 214 * @param b Atom position vector. 215 * @param c Atom position vector. 216 * @param d Atom position vector. 217 * @return The dihedral angle in the range [ -pi, pi ]. 218 */ 219 public static double dihedralAngle(double[] a, double[] b, double[] c, double[] d) { 220 return dihedralAngle(sub(b, a), sub(c, b), sub(d, c)); 221 } 222 223 /** 224 * Finds the distance between two vectors. 225 * 226 * @param a First vector. 227 * @param b Second vector. 228 * @return Returns the distance between vectors a and b. 229 */ 230 public static double dist(double[] a, double[] b) { 231 return sqrt(dist2(a, b)); 232 } 233 234 /** 235 * Finds the squared distance between two vectors 236 * 237 * @param a First vector. 238 * @param b Second vector. 239 * @return Returns the squared distance between vectors a and b. 240 */ 241 public static double dist2(double[] a, double[] b) { 242 var dx = a[0] - b[0]; 243 var dy = a[1] - b[1]; 244 var dz = a[2] - b[2]; 245 return Math.fma(dx, dx, Math.fma(dy, dy, dz * dz)); 246 } 247 248 /** 249 * Finds the dot product between two vectors. 250 * 251 * @param a First vector. 252 * @param b Second vector. 253 * @return Returns the dot product of a and b. 254 */ 255 public static double dot(double[] a, double[] b) { 256 return Math.fma(a[0], b[0], Math.fma(a[1], b[1], a[2] * b[2])); 257 } 258 259 /** 260 * Finds the length of a vector. 261 * 262 * @param d A vector to find the length of. 263 * @return Length of vector d. 264 */ 265 public static double length(double[] d) { 266 return sqrt(length2(d)); 267 } 268 269 /** 270 * Finds the length^2 of a vector. 271 * 272 * @param d A vector to find the length of. 273 * @return Returns the length^2 of vector d. 274 */ 275 public static double length2(double[] d) { 276 return Math.fma(d[0], d[0], Math.fma(d[1], d[1], d[2] * d[2])); 277 } 278 279 /** 280 * logVector 281 * 282 * @param v an array of double. 283 */ 284 public static void log(double[] v) { 285 logger.info(toString(v)); 286 } 287 288 /** 289 * logVector. 290 * 291 * @param v an array of double values. 292 * @param label a {@link String} object. 293 */ 294 public static void log(double[] v, String label) { 295 logger.info(toString(v, label)); 296 } 297 298 /** 299 * Normalizes a vector. 300 * 301 * @param n A vector to be normalized. 302 * @return Returns the normalized vector. 303 */ 304 public static double[] normalize(double[] n) { 305 return scale(n, 1.0 / length(n), new double[3]); 306 } 307 308 /** 309 * Normalizes a vector. 310 * 311 * @param n A vector to be normalized. 312 * @param ret The normalized vector. 313 * @return Returns the normalized vector. 314 */ 315 public static double[] normalize(double[] n, double[] ret) { 316 return scale(n, 1.0 / length(n), ret); 317 } 318 319 /** 320 * Scales a vector. 321 * 322 * @param n A vector to be scaled. 323 * @param a A scalar value. 324 * @return Returns the scaled vector. 325 */ 326 public static double[] scale(double[] n, double a) { 327 return scale(n, a, new double[3]); 328 } 329 330 /** 331 * Scales a vector. 332 * 333 * @param n A vector to be scaled. 334 * @param a A scalar value. 335 * @param ret The scaled vector. 336 * @return Returns the array ret. 337 */ 338 public static double[] scale(double[] n, double a, double[] ret) { 339 ret[0] = n[0] * a; 340 ret[1] = n[1] * a; 341 ret[2] = n[2] * a; 342 return ret; 343 } 344 345 /** 346 * Squares values of a vector. 347 * 348 * @param n A vector to be squared. 349 * @return Returns the squared vector. 350 */ 351 public static double[] square(double[] n) {return square(n, new double[3]);} 352 353 /** 354 * Squares values of a vector. 355 * 356 * @param n A vector to be squared. 357 * @param ret The squared vector. 358 * @return Returns the array ret. 359 */ 360 public static double[] square(double[] n, double[] ret) { 361 ret[0] = n[0] * n[0]; 362 ret[1] = n[1] * n[1]; 363 ret[2] = n[2] * n[2]; 364 return ret; 365 } 366 367 /** 368 * Square root values of a vector. 369 * 370 * @param n A vector to determine square root. 371 * @return Returns the rooted vector. 372 */ 373 public static double[] squareRoot(double[] n) {return squareRoot(n, new double[3]);} 374 375 /** 376 * Square root values of a vector. 377 * 378 * @param n A vector to determine square root. 379 * @param ret The rooted vector. 380 * @return Returns the array ret. 381 */ 382 public static double[] squareRoot(double[] n, double[] ret) { 383 ret[0] = sqrt(n[0]); 384 ret[1] = sqrt(n[1]); 385 ret[2] = sqrt(n[2]); 386 return ret; 387 } 388 389 /** 390 * Finds the difference between two vectors. 391 * 392 * @param a First vector 393 * @param b Second vector 394 * @return Returns the difference. 395 */ 396 public static double[] sub(double[] a, double[] b) { 397 return sub(a, b, new double[3]); 398 } 399 400 /** 401 * Finds the difference between two vectors. 402 * 403 * @param a First vector 404 * @param b Second vector 405 * @param ret Return Values 406 * @return Returns the difference ret. 407 */ 408 public static double[] sub(double[] a, double[] b, double[] ret) { 409 ret[0] = a[0] - b[0]; 410 ret[1] = a[1] - b[1]; 411 ret[2] = a[2] - b[2]; 412 return ret; 413 } 414 415 /** 416 * logVector. 417 * 418 * @param v an array of double. 419 * @return Returns a String description of the vector. 420 */ 421 public static String toString(double[] v) { 422 StringBuilder sb = new StringBuilder(" [ "); 423 for (double d : v) { 424 sb.append(format("%16.8f ", d)); 425 } 426 sb.append("]"); 427 return sb.toString(); 428 } 429 430 /** 431 * vectorToString. 432 * 433 * @param v an array of double values. 434 * @param label a {@link String} object. 435 * @return Returns a String description of the vector. 436 */ 437 public static String toString(@Nullable double[] v, @Nullable String label) { 438 if (v == null) { 439 return null; 440 } 441 if (label == null) { 442 label = "v"; 443 } 444 StringBuilder sb = new StringBuilder(format(" %16s = [", label)); 445 for (double value : v) { 446 sb.append(format(" %16.8f", value)); 447 } 448 sb.append(" ]"); 449 return sb.toString(); 450 } 451 }