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.numerics.spline; 39 40 import javax.annotation.Nullable; 41 42 /** 43 * TriCubicSpline class. 44 * 45 * @author Timothy D. Fenn 46 * @see <a href="http://www.cs.cmu.edu/~fp/courses/graphics/asst5/catmullRom.pdf" 47 * target="_blank">Catmull-Rom splines</a> 48 * @since 1.0 49 */ 50 public class TriCubicSpline { 51 52 /** 53 * Tau for the smoothing matrix. 54 */ 55 private static final double tau = 0.25; 56 /** 57 * Smoothing matrix: Catmull-Rom spline with tau=0.25 58 */ 59 private static final double[][] catmullRomMat = 60 new double[][]{ 61 {0.0, 1.0, 0.0, 0.0}, 62 {-tau, 0.0, tau, 0.0}, 63 {2.0 * tau, tau - 3.0, 3.0 - 2.0 * tau, -tau}, 64 {-tau, 2.0 - tau, tau - 2.0, tau} 65 }; 66 67 private final double[] p; 68 private final double[] q; 69 private final double[] r; 70 private final double[] u; 71 private final double[] v; 72 private final double[] w; 73 private final double[] dp; 74 private final double[] dq; 75 private final double[] dr; 76 private final double[] du; 77 private final double[] dv; 78 private final double[] dw; 79 80 /** 81 * Initialize Spline function. 82 */ 83 public TriCubicSpline() { 84 dw = new double[4]; 85 dv = new double[4]; 86 du = new double[4]; 87 dr = new double[4]; 88 dq = new double[4]; 89 dp = new double[4]; 90 w = new double[4]; 91 v = new double[4]; 92 u = new double[4]; 93 r = new double[4]; 94 q = new double[4]; 95 p = new double[4]; 96 } 97 98 /** 99 * Determine the spline value at a given point. 100 * 101 * @param dx delta between point and previous grid point in X 102 * @param dy delta between point and previous grid point in Y 103 * @param dz delta between point and previous grid point in Z 104 * @param scalar 3d array in x,y,z order of 3D scalar data 105 * @param g gradient array (can be null) 106 * @return the interpolated scalar value at the requested point 107 */ 108 public double spline(double dx, double dy, double dz, double[][][] scalar, @Nullable double[] g) { 109 110 // p(s) = u . catmull-rom matrix . p^T applied in 3 dimensions (u, v, w) 111 u[0] = 1.0; 112 v[0] = 1.0; 113 w[0] = 1.0; 114 for (int i = 1; i < 4; i++) { 115 u[i] = u[i - 1] * dx; 116 v[i] = v[i - 1] * dy; 117 w[i] = w[i - 1] * dz; 118 } 119 120 // Derivatives 121 du[0] = dv[0] = dw[0] = 0.0; 122 du[1] = dv[1] = dw[1] = 1.0; 123 du[2] = 2.0 * dx; 124 du[3] = 3.0 * dx * dx; 125 dv[2] = 2.0 * dy; 126 dv[3] = 3.0 * dy * dy; 127 dw[2] = 2.0 * dz; 128 dw[3] = 3.0 * dz * dz; 129 130 // vec4mat4 - could put this in VectorMath class 131 for (int i = 0; i < 4; i++) { 132 p[i] = q[i] = r[i] = 0.0; 133 dp[i] = dq[i] = dr[i] = 0.0; 134 for (int j = 0; j < 4; j++) { 135 p[i] += u[j] * catmullRomMat[j][i]; 136 q[i] += v[j] * catmullRomMat[j][i]; 137 r[i] += w[j] * catmullRomMat[j][i]; 138 dp[i] += du[j] * catmullRomMat[j][i]; 139 dq[i] += dv[j] * catmullRomMat[j][i]; 140 dr[i] += dw[j] * catmullRomMat[j][i]; 141 } 142 } 143 144 // Tensor products 145 double sum = 0.0; 146 double gx = 0.0, gy = 0.0, gz = 0.0; 147 for (int i = 0; i < 4; i++) { 148 for (int j = 0; j < 4; j++) { 149 for (int k = 0; k < 4; k++) { 150 sum += p[i] * q[j] * r[k] * scalar[i][j][k]; 151 gx += dp[i] * q[j] * r[k] * scalar[i][j][k]; 152 gy += p[i] * dq[j] * r[k] * scalar[i][j][k]; 153 gz += p[i] * q[j] * dr[k] * scalar[i][j][k]; 154 } 155 } 156 } 157 158 if (g != null) { 159 g[0] = gx; 160 g[1] = gy; 161 g[2] = gz; 162 } 163 164 return sum; 165 } 166 }