// ------------------------------------------- // Constructor // ------------------------------------------- public MultiFit( double[] image, ArrayList<Peak> params, double tolerance, int imageSizeX, int imageSizeY, boolean zFitting) { assert (tolerance < 1.0e-1); assert (image != null && image.length == (imageSizeX * imageSizeY)); this.tolerance = tolerance; this.imgData = image; this.imgSizeX = imageSizeX; this.imgSizeY = imageSizeY; this.fgData = new double[image.length]; this.bgData = new double[image.length]; this.bgCounts = new int[image.length]; this.fits = new ArrayList<FitPeak>(params.size()); for (Peak p : params) { FitPeak newFit = new FitPeak(p, 10); if (newFit.peak.hasStatus(PeakStatus.RUNNING)) { newFit.error = 0.0; newFit.errorOld = 0.0; } else { newFit.error = newFit.peak.getIError(); newFit.errorOld = newFit.error; } if (zFitting) { calcWidthsFromZ(newFit); } else { newFit.peak.setXWidth(1.0 / (2.0 * Math.pow(newFit.peak.getXWidth(), 2))); newFit.peak.setYWidth(1.0 / (2.0 * Math.pow(newFit.peak.getYWidth(), 2))); } newFit.xc = (int) newFit.peak.getXCenter(); newFit.yc = (int) newFit.peak.getYCenter(); // possible bug casting fromm double to int in original version newFit.wx = calcWidth(newFit.peak.getXWidth(), -10); newFit.wy = calcWidth(newFit.peak.getYWidth(), -10); // todo these are annoying constants newFit.setClampHeight(1000.0); newFit.setClampBackground(100.0); newFit.setClampXCenter(1.0); newFit.setClampYCenter(1.0); newFit.setClampXWidth(0.3); newFit.setClampYWidth(0.3); newFit.setClampZCenter(0.1); this.fits.add(newFit); } calcFit(); calcError(); }
public void update2D() { double[] delta = new double[Peak.NFITPARAMS]; double[] jt = new double[5]; double[] jacobian = new double[5]; double[][] hessian = new double[5][5]; for (FitPeak fit : this.fits) { if (fit.peak.hasStatus(PeakStatus.RUNNING)) { for (int i = 0; i < 5; i++) { jacobian[i] = 0.0; hessian[i][0] = 0.0; hessian[i][1] = 0.0; hessian[i][2] = 0.0; hessian[i][3] = 0.0; hessian[i][4] = 0.0; } final int offset = fit.offset; final int wx = fit.wx; final int wy = fit.wy; final double height = fit.peak.getHeight(); final double width = fit.peak.getXWidth(); for (int i = -wy; i <= +wy; i++) { final double yt = fit.yt[i + wy]; final double eyt = fit.eyt[i + wy]; for (int j = -wx; j <= +wx; j++) { final double xt = fit.xt[j + wx]; final double ext = fit.ext[j + wx]; final int idx = (i * this.imgSizeX) + (j + offset); final double xi = this.imgData[idx]; final double fi = this.fgData[idx] + (this.bgData[idx] / ((double) this.bgCounts[idx])); final double et = ext * eyt; jt[0] = et; jt[1] = 2.0 * height * width * xt * et; jt[2] = 2.0 * height * width * yt * et; jt[3] = (-height * xt * xt * et) - (height * yt * yt * et); jt[4] = 1.0; // calculate jacobian final double t1 = 2.0 * (1.0 - xi / fi); jacobian[0] += t1 * jt[0]; jacobian[1] += t1 * jt[1]; jacobian[2] += t1 * jt[2]; jacobian[3] += t1 * jt[3]; jacobian[4] += t1 * jt[4]; // calculate hessian final double t2 = 2.0 * xi / (fi * fi); // calculate hessian without second derivative terms. // (symmetric upper triangular) hessian[0][0] += t2 * jt[0] * jt[0]; hessian[0][1] += t2 * jt[0] * jt[1]; hessian[0][2] += t2 * jt[0] * jt[2]; hessian[0][3] += t2 * jt[0] * jt[3]; hessian[0][4] += t2 * jt[0] * jt[4]; hessian[1][1] += t2 * jt[1] * jt[1]; hessian[1][2] += t2 * jt[1] * jt[2]; hessian[1][3] += t2 * jt[1] * jt[3]; hessian[1][4] += t2 * jt[1] * jt[4]; hessian[2][2] += t2 * jt[2] * jt[2]; hessian[2][3] += t2 * jt[2] * jt[3]; hessian[2][4] += t2 * jt[2] * jt[4]; hessian[3][3] += t2 * jt[3] * jt[3]; hessian[3][4] += t2 * jt[3] * jt[4]; hessian[4][4] += t2 * jt[4] * jt[4]; } } // subtract the old peak out of the foreground and background arrays subtractPeak(fit); // use lapack to solve Ax=B to calculate update vector; boolean error = false; final RealMatrix hessianMatrix = MatrixUtils.createRealMatrix(hessian); RealVector jacobianVector = MatrixUtils.createRealVector(jacobian); try { MatrixUtils.solveUpperTriangularSystem(hessianMatrix, jacobianVector); } catch (Exception ex) { fit.peak.setStatus(PeakStatus.ERROR); error = true; } if (!error) { // TODO: Rearranged the jacobian vector entries delta[Peak.HEIGHT] = jacobianVector.getEntry(0); // height delta[Peak.XCENTER] = jacobianVector.getEntry(1); // x center delta[Peak.YCENTER] = jacobianVector.getEntry(2); // y center delta[Peak.XWIDTH] = jacobianVector.getEntry(3); // width delta[Peak.YWIDTH] = jacobianVector.getEntry(3); // width delta[Peak.BACKGROUND] = jacobianVector.getEntry(4); // background // update fits data fitDataUpdate(fit, delta); // add the peak to the foreground and background arrays // recalculate peak fit area as the peak width may have changed if (!fit.peak.hasStatus(PeakStatus.ERROR)) { fit.wx = calcWidth(fit.peak.getXWidth(), fit.wx); fit.wy = fit.wx; addPeak(fit); } } } } }
public void updateZ() { double[] delta = new double[Peak.NFITPARAMS]; double[] jt = new double[5]; double[] jacobian = new double[5]; double[][] hessian = new double[5][5]; for (FitPeak fit : this.fits) { if (fit.peak.hasStatus(PeakStatus.RUNNING)) { for (int i = 0; i < 5; i++) { jacobian[i] = 0; hessian[i][0] = 0.0; hessian[i][1] = 0.0; hessian[i][2] = 0.0; hessian[i][3] = 0.0; hessian[i][4] = 0.0; } final int offset = fit.offset; final int wx = fit.wx; final int wy = fit.wy; final double height = fit.peak.getHeight(); final double xwidth = fit.peak.getXWidth(); final double ywidth = fit.peak.getYWidth(); // calculate dwx vs z final double zCenter = fit.peak.getZCenter(); double z0 = (zCenter - this.wxZParams[1]) / this.wxZParams[2]; double z1 = z0 * z0; double z2 = z1 * z0; double zt = (2.0 * z0) + (3.0 * this.wxZParams[3] * z1) + (4.0 * this.wxZParams[4] * z2); final double gx = -2.0 * zt / (this.wxZParams[0] * fit.wxTerm); // calculate dwy vs z z0 = (zCenter - this.wyZParams[1]) / this.wyZParams[2]; z1 = z0 * z0; z2 = z1 * z0; zt = (2.0 * z0) + (3.0 * this.wyZParams[3] * z1) + (4.0 * this.wyZParams[4] * z2); final double gy = -2.0 * zt / (this.wyZParams[0] * fit.wyTerm); for (int i = -wy; i < +wy; i++) { final double yt = fit.yt[i + wy]; final double eyt = fit.eyt[i + wy]; for (int j = -wx; j < +wx; j++) { final double xt = fit.xt[j + wx]; final double ext = fit.ext[j + wx]; final int idx = (i * this.imgSizeX) + (j + offset); final double xi = this.imgData[idx]; final double fi = this.fgData[idx] / (this.bgData[idx] / ((double) this.bgCounts[idx])); // first derivatives final double et = ext * eyt; jt[0] = et; jt[1] = 2.0 * height * xwidth * xt * et; jt[2] = 2.0 * height * ywidth * yt * et; jt[3] = (-height * xt * xt * gx * et) - (height * yt * yt * gy * et); jt[4] = 1.0; // calculate jacobian final double t1 = 2.0 * (1.0 - xi / fi); jacobian[0] += t1 * jt[0]; jacobian[1] += t1 * jt[1]; jacobian[2] += t1 * jt[2]; jacobian[3] += t1 * jt[3]; jacobian[4] += t1 * jt[4]; // calculate hessian final double t2 = 2.0 * xi / (fi * fi); // calculate hessian without second derivative terms. hessian[0][0] += t2 * jt[0] * jt[0]; hessian[0][1] += t2 * jt[0] * jt[1]; hessian[0][2] += t2 * jt[0] * jt[2]; hessian[0][3] += t2 * jt[0] * jt[3]; hessian[0][4] += t2 * jt[0] * jt[4]; hessian[1][1] += t2 * jt[1] * jt[1]; hessian[1][2] += t2 * jt[1] * jt[2]; hessian[1][3] += t2 * jt[1] * jt[3]; hessian[1][4] += t2 * jt[1] * jt[4]; hessian[2][2] += t2 * jt[2] * jt[2]; hessian[2][3] += t2 * jt[2] * jt[3]; hessian[2][4] += t2 * jt[2] * jt[4]; hessian[3][3] += t2 * jt[3] * jt[3]; hessian[3][4] += t2 * jt[3] * jt[4]; hessian[4][4] += t2 * jt[4] * jt[4]; } } // subtract the old peak out of the foreground and background arrays subtractPeak(fit); // use lapack to solve Ax=B to calculate update vector; boolean error = false; final RealMatrix hessianMatrix = MatrixUtils.createRealMatrix(hessian); RealVector jacobianVector = MatrixUtils.createRealVector(jacobian); try { MatrixUtils.solveUpperTriangularSystem(hessianMatrix, jacobianVector); } catch (Exception ex) { System.out.println("Fitting ERROR:"); System.out.println(ex.getMessage()); fit.peak.setStatus(PeakStatus.ERROR); error = true; } if (!error) { // update parameters delta[Peak.HEIGHT] = jacobianVector.getEntry(0); delta[Peak.XCENTER] = jacobianVector.getEntry(1); delta[Peak.YCENTER] = jacobianVector.getEntry(2); delta[Peak.ZCENTER] = jacobianVector.getEntry(3); delta[Peak.BACKGROUND] = jacobianVector.getEntry(4); fitDataUpdate(fit, delta); if (!fit.peak.hasStatus(PeakStatus.ERROR)) { // calculate new x, y, width and update fit area calcWidthsFromZ(fit); fit.wx = calcWidth(fit.peak.getXWidth(), fit.wx); fit.wy = calcWidth(fit.peak.getYWidth(), fit.wy); addPeak(fit); } } } } }