ffx.xray.RealSpaceData.java Source code

Java tutorial

Introduction

Here is the source code for ffx.xray.RealSpaceData.java

Source

/**
 * Title: Force Field X.
 *
 * Description: Force Field X - Software for Molecular Biophysics.
 *
 * Copyright: Copyright (c) Michael J. Schnieders 2001-2015.
 *
 * This file is part of Force Field X.
 *
 * Force Field X is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 3 as published by
 * the Free Software Foundation.
 *
 * Force Field X is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * Force Field X; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Linking this library statically or dynamically with other modules is making a
 * combined work based on this library. Thus, the terms and conditions of the
 * GNU General Public License cover the whole combination.
 *
 * As a special exception, the copyright holders of this library give you
 * permission to link this library with independent modules to produce an
 * executable, regardless of the license terms of these independent modules, and
 * to copy and distribute the resulting executable under terms of your choice,
 * provided that you also meet, for each linked independent module, the terms
 * and conditions of the license of that module. An independent module is a
 * module which is not derived from or based on this library. If you modify this
 * library, you may extend this exception to your version of the library, but
 * you are not obligated to do so. If you do not wish to do so, delete this
 * exception statement from your version.
 */
package ffx.xray;

import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.configuration.CompositeConfiguration;

import ffx.crystal.Crystal;
import ffx.numerics.TriCubicSpline;
import ffx.potential.MolecularAssembly;
import ffx.potential.bonded.Atom;
import ffx.potential.bonded.Molecule;
import ffx.potential.bonded.Residue;
import ffx.xray.RefinementMinimize.RefinementMode;

/**
 * <p>
 * RealSpaceData class.</p>
 *
 * @author Timothy D. Fenn
 *
 */
public class RealSpaceData implements DataContainer {

    private static final Logger logger = Logger.getLogger(RealSpaceData.class.getName());
    protected final MolecularAssembly assembly[];
    protected final RealSpaceFile dataname[];
    protected final String modelname;
    protected final int n;
    protected final Crystal crystal[];
    protected final RealSpaceRefinementData refinementdata[];
    protected final RefinementModel refinementmodel;
    protected double lambda = 1.0;
    // settings
    public double xweight;

    /**
     * construct a real space data assembly, assumes a real space map with a
     * weight of 1.0 using the same name as the molecular assembly
     *
     * @param assembly
     * {@link ffx.potential.MolecularAssembly molecular assembly} object, used
     * as the atomic model for comparison against the data
     * @param properties system properties file
     * @param diffractiondata {@link ffx.xray.DiffractionData diffraction data}
     */
    public RealSpaceData(MolecularAssembly assembly, CompositeConfiguration properties,
            DiffractionData diffractiondata) {
        this(new MolecularAssembly[] { assembly }, properties, diffractiondata);
    }

    /**
     * construct a real space data assembly, assumes a real space map with a
     * weight of 1.0 using the same name as the molecular assembly
     *
     * @param assembly
     * {@link ffx.potential.MolecularAssembly molecular assembly} object, used
     * as the atomic model for comparison against the data
     * @param properties system properties file
     * @param diffractiondata {@link ffx.xray.DiffractionData diffraction data}
     */
    public RealSpaceData(MolecularAssembly assembly[], CompositeConfiguration properties,
            DiffractionData diffractiondata) {
        this.assembly = assembly;
        this.modelname = assembly[0].getFile().getName();
        this.dataname = null;
        this.n = 1;
        crystal = new Crystal[n];
        crystal[0] = diffractiondata.crystal[0];
        refinementdata = new RealSpaceRefinementData[n];
        refinementdata[0] = new RealSpaceRefinementData();
        refinementdata[0].periodic = true;

        xweight = properties.getDouble("xweight", 1.0);

        if (logger.isLoggable(Level.INFO)) {
            StringBuilder sb = new StringBuilder();
            sb.append(" Refinement Settings\n");
            sb.append("  Real space refinement weight (xweight): " + xweight + "\n");
            logger.info(sb.toString());
        }

        if (!diffractiondata.scaled[0]) {
            diffractiondata.scaleBulkFit();
            diffractiondata.printStats();
            // energy();
        }

        // get Fo-Fc difference density
        diffractiondata.crs_fc[0].computeAtomicGradients(diffractiondata.refinementData[0].fofc1,
                diffractiondata.refinementData[0].freer, diffractiondata.refinementData[0].rfreeflag,
                RefinementMode.COORDINATES);

        refinementdata[0].ori[0] = 0;
        refinementdata[0].ori[1] = 0;
        refinementdata[0].ori[2] = 0;
        int extx = (int) diffractiondata.crs_fc[0].getXDim();
        int exty = (int) diffractiondata.crs_fc[0].getYDim();
        int extz = (int) diffractiondata.crs_fc[0].getZDim();
        refinementdata[0].ext[0] = extx;
        refinementdata[0].ext[1] = exty;
        refinementdata[0].ext[2] = extz;
        refinementdata[0].ni[0] = extx;
        refinementdata[0].ni[1] = exty;
        refinementdata[0].ni[2] = extz;
        refinementdata[0].data = new double[extx * exty * extz];
        for (int k = 0; k < extz; k++) {
            for (int j = 0; j < exty; j++) {
                for (int i = 0; i < extx; i++) {
                    int index1 = (i + extx * (j + exty * k));
                    int index2 = 2 * (i + extx * (j + exty * k));
                    refinementdata[0].data[index1] = diffractiondata.crs_fc[0].densityGrid[index2];
                }
            }
        }

        // now set up the refinement model
        refinementmodel = new RefinementModel(assembly);
    }

    /**
     * construct a real space data assembly, assumes a real space map with a
     * weight of 1.0 using the same name as the molecular assembly
     *
     * @param assembly
     * {@link ffx.potential.MolecularAssembly molecular assembly} object, used
     * as the atomic model for comparison against the data
     * @param properties system properties file
     */
    public RealSpaceData(MolecularAssembly assembly, CompositeConfiguration properties) {
        this(new MolecularAssembly[] { assembly }, properties, new RealSpaceFile(assembly));
    }

    /**
     * construct a real space data assembly
     *
     * @param assembly
     * {@link ffx.potential.MolecularAssembly molecular assembly} object, used
     * as the atomic model for comparison against the data
     * @param properties system properties file
     * @param datafile one or more {@link RealSpaceFile} to be refined against
     */
    public RealSpaceData(MolecularAssembly assembly, CompositeConfiguration properties, RealSpaceFile... datafile) {
        this(new MolecularAssembly[] { assembly }, properties, datafile);
    }

    /**
     * construct a real space data assembly
     *
     * @param assembly
     * {@link ffx.potential.MolecularAssembly molecular assembly} object array
     * (typically containing alternate conformer assemblies), used as the atomic
     * model for comparison against the data
     * @param properties system properties file
     * @param datafile one or more {@link RealSpaceFile} to be refined against
     */
    public RealSpaceData(MolecularAssembly assembly[], CompositeConfiguration properties,
            RealSpaceFile... datafile) {

        this.assembly = assembly;
        this.modelname = assembly[0].getFile().getName();
        this.dataname = datafile;
        this.n = datafile.length;
        crystal = new Crystal[n];
        refinementdata = new RealSpaceRefinementData[n];

        xweight = properties.getDouble("xweight", 1.0);

        for (int i = 0; i < n; i++) {
            crystal[i] = datafile[i].realspacefilter.getCrystal(datafile[i].filename, properties);

            if (crystal[i] == null) {
                logger.severe("CCP4 map file does not contain full crystal information!");
            }
        }

        for (int i = 0; i < n; i++) {
            refinementdata[i] = new RealSpaceRefinementData();
            datafile[i].realspacefilter.readFile(datafile[i].filename, refinementdata[i], properties);

            if (refinementdata[i].ori[0] == 0 && refinementdata[i].ori[1] == 0 && refinementdata[i].ori[2] == 0
                    && refinementdata[i].ext[0] == refinementdata[i].ni[0]
                    && refinementdata[i].ext[1] == refinementdata[i].ni[1]
                    && refinementdata[i].ext[2] == refinementdata[i].ni[2]) {
                refinementdata[i].periodic = true;
            }
        }

        if (logger.isLoggable(Level.INFO)) {
            StringBuilder sb = new StringBuilder();
            sb.append(" Refinement Settings\n");
            sb.append("  Real space refinement weight (xweight): " + xweight + "\n");
            logger.info(sb.toString());
        }

        // now set up the refinement model
        refinementmodel = new RefinementModel(assembly);
    }

    /**
     * compute real space target value, also fills in atomic derivatives
     *
     * @return target value sum over all data sets
     * @param dLambda a boolean.
     */
    public double computeRealSpaceTarget(boolean dLambda) {
        double xyz[] = new double[3];
        double uvw[] = new double[3];
        double grad[] = new double[3];
        double scalar[][][] = new double[4][4][4];

        double sum;
        for (int i = 0; i < n; i++) {
            sum = 0.0;
            TriCubicSpline spline = new TriCubicSpline();
            for (Atom a : refinementmodel.atomArray) {
                if (dLambda && !a.applyLambda()) {
                    continue;
                }

                if (!a.isActive()) {
                    continue;
                }

                final double lambdai = dLambda ? 1.0 : a.applyLambda() ? lambda : 1.0;
                a.getXYZ(xyz);
                a.setXYZGradient(0.0, 0.0, 0.0);
                crystal[i].toFractionalCoordinates(xyz, uvw);

                // Logic to find atom in 3d scalar field box
                final double frx = refinementdata[i].ni[0] * uvw[0];
                final int ifrx = ((int) Math.floor(frx)) - refinementdata[i].ori[0];
                final double dfrx = frx - Math.floor(frx);

                final double fry = refinementdata[i].ni[1] * uvw[1];
                final int ifry = ((int) Math.floor(fry)) - refinementdata[i].ori[1];
                final double dfry = fry - Math.floor(fry);

                final double frz = refinementdata[i].ni[2] * uvw[2];
                final int ifrz = ((int) Math.floor(frz)) - refinementdata[i].ori[2];
                final double dfrz = frz - Math.floor(frz);

                if (!refinementdata[i].periodic) {
                    if (ifrx - 1 < 0 || ifrx + 2 > refinementdata[i].ext[0] || ifry - 1 < 0
                            || ifry + 2 > refinementdata[i].ext[1] || ifrz - 1 < 0
                            || ifrz + 2 > refinementdata[i].ext[2]) {
                        logger.warning("atom: " + a.toString() + " is outside the scalar field box! Ignoring...");
                        continue;
                    }
                }

                // fill in scalar 4x4 array for interpolation
                int uii, vii, wii;
                for (int ui = ifrx - 1; ui < ifrx + 3; ui++) {
                    uii = ui - (ifrx - 1);
                    int pui = Crystal.mod(ui, refinementdata[i].ext[0]);
                    for (int vi = ifry - 1; vi < ifry + 3; vi++) {
                        vii = vi - (ifry - 1);
                        int pvi = Crystal.mod(vi, refinementdata[i].ext[1]);
                        for (int wi = ifrz - 1; wi < ifrz + 3; wi++) {
                            wii = wi - (ifrz - 1);
                            int pwi = Crystal.mod(wi, refinementdata[i].ext[2]);

                            if (refinementdata[i].periodic) {
                                scalar[uii][vii][wii] = refinementdata[i].getDataIndex(pui, pvi, pwi);
                            } else {
                                scalar[uii][vii][wii] = refinementdata[i].getDataIndex(ui, vi, wi);
                            }
                        }
                    }
                }

                // scale and interpolate
                double scale;
                if (dataname == null) {
                    scale = -1.0 * lambdai * a.getAtomType().atomicWeight;
                } else {
                    scale = -1.0 * lambdai * dataname[i].weight * a.getAtomType().atomicWeight;
                }
                double val = spline.spline(dfrx, dfry, dfrz, scalar, grad);
                sum += scale * val;

                grad[0] = grad[0] * refinementdata[i].ni[0];
                grad[1] = grad[1] * refinementdata[i].ni[1];
                grad[2] = grad[2] * refinementdata[i].ni[2];
                // transpose of toFractional
                xyz[0] = grad[0] * crystal[i].A00 + grad[1] * crystal[i].A01 + grad[2] * crystal[i].A02;
                xyz[1] = grad[0] * crystal[i].A10 + grad[1] * crystal[i].A11 + grad[2] * crystal[i].A12;
                xyz[2] = grad[0] * crystal[i].A20 + grad[1] * crystal[i].A21 + grad[2] * crystal[i].A22;
                a.addToXYZGradient(scale * xyz[0], scale * xyz[1], scale * xyz[2]);
            }
            refinementdata[i].densityscore = sum;
        }
        sum = 0.0;
        for (int i = 0; i < n; i++) {
            sum += refinementdata[i].densityscore;
        }
        return sum;
    }

    /**
     * Set the current value of the state variable.
     *
     * @param lambda a double.
     */
    protected void setLambda(double lambda) {
        this.lambda = lambda;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Atom[] getAtomArray() {
        return refinementmodel.atomArray;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ArrayList<ArrayList<Residue>> getAltResidues() {
        return refinementmodel.altResidues;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public ArrayList<ArrayList<Molecule>> getAltMolecules() {
        return refinementmodel.altMolecules;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public MolecularAssembly[] getMolecularAssembly() {
        return assembly;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public RefinementModel getRefinementModel() {
        return refinementmodel;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public double getWeight() {
        return xweight;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void setWeight(double weight) {
        this.xweight = weight;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String printOptimizationHeader() {
        return "Density score";
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String printOptimizationUpdate() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            sb.append(String.format("%6.2f ", refinementdata[i].densityscore));
        }
        return sb.toString();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String printEnergyUpdate() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            sb.append(
                    String.format("     dataset %d (weight: %5.1f): chemical energy: %8.2f density score: %8.2f\n",
                            i + 1, dataname[i].weight, assembly[0].getPotentialEnergy().getTotalEnergy(),
                            dataname[i].weight * refinementdata[i].densityscore));
        }
        return sb.toString();
    }
}