ffx.potential.parsers.XYZFilter.java Source code

Java tutorial

Introduction

Here is the source code for ffx.potential.parsers.XYZFilter.java

Source

/**
 * Title: Force Field X.
 *
 * Description: Force Field X - Software for Molecular Biophysics.
 *
 * Copyright: Copyright (c) Michael J. Schnieders 2001-2017.
 *
 * 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.potential.parsers;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import static java.lang.String.format;

import javax.vecmath.Vector3d;

import org.apache.commons.configuration.CompositeConfiguration;

import ffx.crystal.Crystal;
import ffx.crystal.SymOp;
import ffx.potential.MolecularAssembly;
import ffx.potential.Utilities.FileType;
import ffx.potential.bonded.Atom;
import ffx.potential.bonded.Bond;
import ffx.potential.parameters.AtomType;
import ffx.potential.parameters.BondType;
import ffx.potential.parameters.ForceField;

/**
 * The XYZFilter class parses TINKER Cartesian coordinate (*.XYZ) files.
 *
 * @author Michael J. Schnieders
 * @since 1.0
 *
 */
public class XYZFilter extends SystemFilter {

    private static final Logger logger = Logger.getLogger(XYZFilter.class.getName());
    private BufferedReader bin = null;
    private int snapShot;

    /**
     * <p>
     * readOnto</p>
     *
     * @param newFile a {@link java.io.File} object.
     * @param oldSystem a {@link ffx.potential.MolecularAssembly} object.
     * @return a boolean.
     */
    public static boolean readOnto(File newFile, MolecularAssembly oldSystem) {
        if (newFile == null || !newFile.exists() || oldSystem == null) {
            return false;
        }
        try {
            FileReader fr = new FileReader(newFile);
            BufferedReader br = new BufferedReader(fr);
            String data = br.readLine();
            if (data == null) {
                return false;
            }
            String tokens[] = data.trim().split(" +");
            int num_atoms = Integer.parseInt(tokens[0]);
            if (num_atoms != oldSystem.getAtomList().size()) {
                return false;
            }
            double d[][] = new double[num_atoms][3];
            for (int i = 0; i < num_atoms; i++) {
                if (!br.ready()) {
                    return false;
                }
                data = br.readLine();
                if (data == null) {
                    logger.warning("Check atom " + (i + 1));
                    return false;
                }
                tokens = data.trim().split(" +");
                if (tokens == null || tokens.length < 6) {
                    logger.warning("Check atom " + (i + 1));
                    return false;
                }
                d[i][0] = Double.parseDouble(tokens[2]);
                d[i][1] = Double.parseDouble(tokens[3]);
                d[i][2] = Double.parseDouble(tokens[4]);
            }
            ArrayList<Atom> atoms = oldSystem.getAtomList();
            for (Atom a : atoms) {
                int index = a.getXYZIndex() - 1;
                a.setXYZ(d[index]);
            }
            oldSystem.center();
            oldSystem.setFile(newFile);
            br.close();
            fr.close();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * <p>
     * Constructor for XYZFilter.</p>
     *
     * @param files a {@link java.util.List} object.
     * @param system a {@link ffx.potential.MolecularAssembly} object.
     * @param forceField a {@link ffx.potential.parameters.ForceField} object.
     * @param properties a
     * {@link org.apache.commons.configuration.CompositeConfiguration} object.
     */
    public XYZFilter(List<File> files, MolecularAssembly system, ForceField forceField,
            CompositeConfiguration properties) {
        super(files, system, forceField, properties);
        this.fileType = FileType.XYZ;
    }

    /**
     * <p>
     * Constructor for XYZFilter.</p>
     *
     * @param file a {@link java.io.File} object.
     * @param system a {@link ffx.potential.MolecularAssembly} object.
     * @param forceField a {@link ffx.potential.parameters.ForceField} object.
     * @param properties a
     * {@link org.apache.commons.configuration.CompositeConfiguration} object.
     */
    public XYZFilter(File file, MolecularAssembly system, ForceField forceField,
            CompositeConfiguration properties) {
        super(file, system, forceField, properties);
        this.fileType = FileType.XYZ;
    }

    /**
     * {@inheritDoc}
     *
     * Parse the XYZ File
     */
    @Override
    public boolean readFile() {
        File xyzFile = activeMolecularAssembly.getFile();

        if (forceField == null) {
            logger.warning(" No force field is associated with " + xyzFile.toString());
            return false;
        }
        try {
            FileReader fr = new FileReader(xyzFile);
            BufferedReader br = new BufferedReader(fr);
            String data = br.readLine();
            // Read blank lines at the top of the file
            while (data != null && data.trim().equals("")) {
                data = br.readLine();
            }
            if (data == null) {
                return false;
            }
            String tokens[] = data.trim().split(" +", 2);
            int numberOfAtoms = Integer.parseInt(tokens[0]);
            if (numberOfAtoms < 1) {
                return false;
            }
            if (tokens.length == 2) {
                getActiveMolecularSystem().setName(tokens[1]);
            }
            logger.info("\n Opening " + xyzFile.getName() + " with " + numberOfAtoms + " atoms\n");
            // The header line is reasonable - prepare to parse atom lines.
            Hashtable<Integer, Integer> labelHash = new Hashtable<Integer, Integer>();
            int label[] = new int[numberOfAtoms];
            int bonds[][] = new int[numberOfAtoms][8];
            double d[][] = new double[numberOfAtoms][3];
            boolean renumber = false;
            atomList = new ArrayList<Atom>();
            // Loop over the expected number of atoms.
            for (int i = 0; i < numberOfAtoms; i++) {
                if (!br.ready()) {
                    return false;
                }
                data = br.readLine();
                if (data == null) {
                    logger.warning("Check atom " + (i + 1) + " in " + activeMolecularAssembly.getFile().getName());
                    return false;
                }
                tokens = data.trim().split(" +");
                if (tokens == null || tokens.length < 6) {
                    logger.warning("Check atom " + (i + 1) + " in " + activeMolecularAssembly.getFile().getName());
                    return false;
                }
                // Valid number of tokens, so try to parse this line.
                label[i] = Integer.parseInt(tokens[0]);
                // Check for valid atom numbering, or flag for re-numbering.
                if (label[i] != i + 1) {
                    renumber = true;
                }
                String atomName = tokens[1];
                d[i][0] = Double.parseDouble(tokens[2]);
                d[i][1] = Double.parseDouble(tokens[3]);
                d[i][2] = Double.parseDouble(tokens[4]);
                int type = Integer.parseInt(tokens[5]);
                AtomType atomType = forceField.getAtomType(Integer.toString(type));
                if (atomType == null) {
                    StringBuilder message = new StringBuilder("Check atom type ");
                    message.append(type).append(" for Atom ").append(i + 1);
                    message.append(" in ").append(activeMolecularAssembly.getFile().getName());
                    logger.warning(message.toString());
                    return false;
                }
                Atom a = new Atom(i + 1, atomName, atomType, d[i]);
                atomList.add(a);
                // Bond Data
                int numberOfBonds = tokens.length - 6;
                for (int b = 0; b < 8; b++) {
                    if (b < numberOfBonds) {
                        int bond = Integer.parseInt(tokens[6 + b]);
                        bonds[i][b] = bond;
                    } else {
                        bonds[i][b] = 0;
                    }
                }
            }
            // Check if this is an archive.
            if (br.ready()) {
                // Read past blank lines between archive files
                data = br.readLine().trim();
                while (data != null && data.equals("")) {
                    data = br.readLine().trim();
                }
                if (data != null) {
                    tokens = data.split(" +", 2);
                    if (tokens != null && tokens.length > 0) {
                        try {
                            int archiveNumberOfAtoms = Integer.parseInt(tokens[0]);
                            if (archiveNumberOfAtoms == numberOfAtoms) {
                                setType(FileType.ARC);
                            }
                        } catch (Exception e) {
                            tokens = null;
                        }
                    }
                }
            }
            br.close();
            fr.close();
            // Try to renumber
            if (renumber) {
                for (int i = 0; i < numberOfAtoms; i++) {
                    if (labelHash.containsKey(label[i])) {
                        logger.warning("Two atoms have the same index: " + label[i]);
                        return false;
                    }
                    labelHash.put(label[i], i + 1);
                }
                for (int i = 0; i < numberOfAtoms; i++) {
                    int j = -1;
                    while (j < 3 && bonds[i][++j] > 0) {
                        bonds[i][j] = labelHash.get(bonds[i][j]);
                    }
                }
            }
            bondList = new ArrayList<Bond>();
            int c[] = new int[2];
            for (int i = 1; i <= numberOfAtoms; i++) {
                int a1 = i;
                int j = -1;
                while (j < 7 && bonds[i - 1][++j] > 0) {
                    int a2 = bonds[i - 1][j];
                    if (a1 < a2) {
                        if (a1 > numberOfAtoms || a1 < 1 || a2 > numberOfAtoms || a2 < 1) {
                            logger.warning("Check the Bond Bewteen " + a1 + " and " + a2 + " in "
                                    + activeMolecularAssembly.getFile().getName());
                            return false;
                        }
                        // Check for bidirectional connection
                        boolean bidirectional = false;
                        int k = -1;
                        while (k < 7 && bonds[a2 - 1][++k] > 0) {
                            int a3 = bonds[a2 - 1][k];
                            if (a3 == a1) {
                                bidirectional = true;
                                break;
                            }
                        }
                        if (!bidirectional) {
                            logger.warning("Check the Bond Bewteen " + a1 + " and " + a2 + " in "
                                    + activeMolecularAssembly.getFile().getName());
                            return false;
                        }
                        Atom atom1 = atomList.get(a1 - 1);
                        Atom atom2 = atomList.get(a2 - 1);
                        if (atom1 == null || atom2 == null) {
                            logger.warning("Check the Bond Bewteen " + a1 + " and " + a2 + " in "
                                    + activeMolecularAssembly.getFile().getName());
                            return false;
                        }
                        Bond bond = new Bond(atom1, atom2);
                        c[0] = atom1.getAtomType().atomClass;
                        c[1] = atom2.getAtomType().atomClass;
                        String key = BondType.sortKey(c);
                        BondType bondType = forceField.getBondType(key);
                        if (bondType == null) {
                            logger.severe("No BondType for key: " + key);
                        } else {
                            bond.setBondType(bondType);
                        }
                        bondList.add(bond);
                    }
                }
            }
            /*
             if (getType() == FileType.ARC) {
             return readtrajectory();
             } */
            return true;
        } catch (IOException e) {
            logger.severe(e.toString());
        }
        return false;
    }

    /*public boolean readNextNew() throws IOException {
    try {
        Atom[] atoms = activeMolecularAssembly.getAtomArray();
        int nAtoms = atoms.length;
        if (bin == null) {
            bin = new BufferedReader(new FileReader(currentFile));
            snapShot = 1;
        }
        double[][] coords = new double[nAtoms][3];
        boolean success = true;
            
        // Start with header line.
        String line = bin.readLine();
        for (int i = -1; i < nAtoms; i++) {
            try {
                if (line == null) {
                    logger.info(String.format(" End of archive reached for %s", activeMolecularAssembly));
                    bin.close();
                    return false;
                }
                line = line.trim();
                String[] toks = line.split("\\s+");
                if (i == -1) {
                    String filename = toks[1];
                    logger.info(String.format(" Reading snapshot %d of %s", snapShot++, filename));
                } else {
                    for (int j = 0; j < 3; j++) {
                        coords[i][j] = Double.parseDouble(toks[j + 2]);
                    }
                }
                line = bin.readLine();
            } catch (IOException | NumberFormatException exc) {
                success = false;
                logger.warning(String.format(" Exception reading coords for atom %d: %s", i, exc.toString()));
            }
        }
        
        if (success) {
            for (int i = 0; i < nAtoms; i++) {
                atoms[i].setXYZ(coords[i]);
            }
            return true;
        } else {
            logger.warning(String.format(" Failed to move atoms for snapshot %d", (snapShot - 1)));
            return false;
        }
            
    } catch (Exception ex) {
        logger.info(String.format(" Exception %s while reading archive %s", ex.toString(), activeMolecularAssembly));
        //return false;
        throw ex;
    }
    }*/

    @Override
    public boolean readNext() {
        return readNext(false);
    }

    /**
     * Reads the next snap-shot of an archive into the activeMolecularAssembly.
     * After calling this function, a BufferedReader will remain open until the
     * <code>close</code> method is called.
     *
     * @return true if successful.
     */
    @Override
    public boolean readNext(boolean resetPosition) {
        try {
            String data;
            Atom atoms[] = activeMolecularAssembly.getAtomArray();
            int nSystem = atoms.length;

            if (bin == null || resetPosition/* || !bin.ready()*/) {
                bin = new BufferedReader(new FileReader(currentFile));
                // Read past the first N + 1 non-blank lines
                for (int i = 0; i < nSystem + 1; i++) {
                    data = bin.readLine();
                    while (data != null && data.trim().equals("")) {
                        data = bin.readLine();
                    }
                }
                snapShot = 1;
            }

            snapShot++;
            logger.info(String.format(" Reading snapshot %d of %s.", snapShot, activeMolecularAssembly));

            data = bin.readLine();
            // Read past blank lines
            while (data != null && data.trim().equals("")) {
                data = bin.readLine();
            }
            try {
                int nArchive = Integer.parseInt(data.trim().split(" +")[0]);
                if (nArchive != nSystem) {
                    String message = String.format("Number of atoms mismatch (Archive: %d, System: %d).", nArchive,
                            nSystem);
                    if (dieOnMissingAtom) {
                        logger.severe(message);
                    }
                    logger.warning(message);
                    return false;
                }
            } catch (Exception e) {
                logger.warning(e.toString());
                return false;
            }
            for (int i = 0; i < nSystem; i++) {
                data = bin.readLine();
                // Read past blank lines
                while (data != null && data.trim().equals("")) {
                    data = bin.readLine();
                }
                String[] tokens = data.trim().split(" +");
                if (tokens == null || tokens.length < 6) {
                    String message = String.format("Check atom %d in %s.", (i + 1), currentFile.getName());
                    logger.warning(message);
                    return false;
                }
                double x = Double.parseDouble(tokens[2]);
                double y = Double.parseDouble(tokens[3]);
                double z = Double.parseDouble(tokens[4]);
                int xyzIndex = atoms[i].getXYZIndex();
                if (xyzIndex != i + 1) {
                    String message = String.format("Archive atom index %d being read onto system atom index %d.",
                            i + 1, xyzIndex);
                    logger.warning(message);
                }
                atoms[i].moveTo(x, y, z);
            }
            return true;
        } catch (FileNotFoundException e) {
            String message = String.format("Exception opening file %s.", currentFile);
            logger.log(Level.WARNING, message, e);
        } catch (IOException e) {
            String message = String.format("Exception reading from file %s.", currentFile);
            logger.log(Level.WARNING, message, e);
        }
        return false;
    }

    @Override
    public void closeReader() {
        try {
            bin.close();
        } catch (IOException ex) {
            logger.warning(String.format(" Exception in closing XYZ filter: %s", ex.toString()));
        }
    }

    /**
     * <p>
     * close</p>
     */
    public void close() {
        if (bin != null) {
            try {
                bin.close();
            } catch (Exception e) {
                String message = String.format("Exception closing file %s.", activeMolecularAssembly.getFile());
                logger.log(Level.WARNING, message, e);
            }
        }
    }

    /**
     * <p>
     * readtrajectory</p>
     *
     * @return a boolean.
     */
    public boolean readtrajectory() {
        // If the first entry was read successfully, reopen the
        // archive file and read the rest of the coordinates
        try {
            logger.info(" Trying to parse " + activeMolecularAssembly.getFile() + " as an archive.");
            bin = new BufferedReader(new FileReader(activeMolecularAssembly.getFile()));
            String data = null;
            int numatoms = atomList.size();
            int cycle = 1;
            double coords[][] = new double[numatoms][3];
            // Read past the first N + 1 non-blank lines
            for (int i = 0; i < numatoms + 1; i++) {
                data = bin.readLine();
                while (data != null && data.trim().equals("")) {
                    data = bin.readLine();
                }
            }
            while (bin.ready()) {
                data = bin.readLine();
                // Read past blank lines
                while (data != null && data.trim().equals("")) {
                    data = bin.readLine();
                }
                try {
                    int num = Integer.parseInt(data.trim().split(" +")[0]);
                    if (num != numatoms) {
                        logger.warning(num + " atoms for archive entry " + cycle + " is not equal to " + numatoms
                                + "." + "Only the first " + (cycle - 1) + " entries were read.");
                        return true;
                    }
                } catch (Exception e) {
                    logger.severe(e.toString());
                    return false;
                }
                for (int i = 0; i < numatoms; i++) {
                    data = bin.readLine();
                    // Read past blank lines
                    while (data != null && data.trim().equals("")) {
                        data = bin.readLine();
                    }
                    String[] tokens = data.trim().split(" +");
                    if (tokens == null || tokens.length < 6) {
                        logger.warning("Check atom " + (i + 1) + ", archive entry " + (cycle + 1) + " in "
                                + activeMolecularAssembly.getFile().getName());
                        return false;
                    }
                    coords[i][0] = Double.parseDouble(tokens[2]);
                    coords[i][1] = Double.parseDouble(tokens[3]);
                    coords[i][2] = Double.parseDouble(tokens[4]);
                }
                for (Atom a : atomList) {
                    int i = a.xyzIndex - 1;
                    Vector3d v3d = new Vector3d(coords[i][0], coords[i][1], coords[i][2]);
                    a.addTrajectoryCoords(v3d, cycle);
                }
                cycle++;
            }
            activeMolecularAssembly.setCycles(cycle);
            setFileRead(true);
            return true;
        } catch (FileNotFoundException e) {
            logger.warning(e.toString());
        } catch (IOException e) {
            logger.warning(e.toString());
        }
        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean writeFile(File saveFile, boolean append) {
        if (saveFile == null) {
            return false;
        }
        try {
            File newFile = saveFile;
            if (!append) {
                newFile = version(saveFile);
            }
            activeMolecularAssembly.setFile(newFile);
            activeMolecularAssembly.setName(newFile.getName());
            FileWriter fw = null;
            if (append && !newFile.exists()) {
                fw = new FileWriter(newFile);
            } else {
                fw = new FileWriter(newFile, append);
            }
            BufferedWriter bw = new BufferedWriter(fw);

            // XYZ File First Line
            int numberOfAtoms = activeMolecularAssembly.getAtomList().size();
            String output = format("%7d  %s\n", numberOfAtoms, activeMolecularAssembly.toString());
            bw.write(output);
            Atom a2;
            StringBuilder line;
            StringBuilder lines[] = new StringBuilder[numberOfAtoms];
            // XYZ File Atom Lines
            ArrayList<Atom> atoms = activeMolecularAssembly.getAtomList();
            Vector3d offset = activeMolecularAssembly.getOffset();
            for (Atom a : atoms) {
                if (vdwH) {
                    line = new StringBuilder(String.format("%7d %3s%14.8f%14.8f%14.8f%6d", a.getXYZIndex(),
                            a.getAtomType().name, a.getRedX() - offset.x, a.getRedY() - offset.y,
                            a.getRedZ() - offset.z, a.getType()));
                } else {
                    line = new StringBuilder(
                            String.format("%7d %3s%14.8f%14.8f%14.8f%6d", a.getXYZIndex(), a.getAtomType().name,
                                    a.getX() - offset.x, a.getY() - offset.y, a.getZ() - offset.z, a.getType()));
                }
                for (Bond b : a.getBonds()) {
                    a2 = b.get1_2(a);
                    line.append(format("%8d", a2.xyzIndex));
                }
                lines[a.getXYZIndex() - 1] = line.append("\n");
            }
            try {
                for (int i = 0; i < numberOfAtoms; i++) {
                    bw.write(lines[i].toString());
                }
            } catch (Exception e) {
                logger.severe("Their was an unexpected error writing to " + getActiveMolecularSystem().toString()
                        + "\n" + e + "\nForce Field X will continue...");
                return false;
            }
            bw.close();
            fw.close();
        } catch (IOException e) {
            logger.severe("Their was an unexpected error writing to " + getActiveMolecularSystem().toString() + "\n"
                    + e + "\nForce Field X will continue...");
            return false;
        }
        return true;
    }

    /**
     * <p>
     * writeFileAsP1</p>
     *
     * @param saveFile a {@link java.io.File} object.
     * @param append a boolean.
     * @param crystal a {@link ffx.crystal.Crystal} object.
     * @return a boolean.
     */
    public boolean writeFileAsP1(File saveFile, boolean append, Crystal crystal) {
        if (saveFile == null) {
            return false;
        }
        try {
            File newFile = saveFile;
            if (!append) {
                newFile = version(saveFile);
            }
            activeMolecularAssembly.setFile(newFile);
            activeMolecularAssembly.setName(newFile.getName());
            FileWriter fw = new FileWriter(newFile, append);
            BufferedWriter bw = new BufferedWriter(fw);
            int nSymm = crystal.spaceGroup.symOps.size();
            // XYZ File First Line
            int numberOfAtoms = activeMolecularAssembly.getAtomList().size() * nSymm;
            String output = format("%7d %s\n", numberOfAtoms, activeMolecularAssembly.toString());
            bw.write(output);
            Atom a2;
            StringBuilder line;
            StringBuilder lines[] = new StringBuilder[numberOfAtoms];
            // XYZ File Atom Lines
            Atom atoms[] = activeMolecularAssembly.getAtomArray();
            double xyz[] = new double[3];
            for (int iSym = 0; iSym < nSymm; iSym++) {
                SymOp symOp = crystal.spaceGroup.getSymOp(iSym);
                int indexOffset = iSym * atoms.length;
                for (Atom a : atoms) {
                    int index = a.getXYZIndex() + indexOffset;
                    String id = a.getAtomType().name;
                    if (vdwH) {
                        a.getRedXYZ(xyz);
                    } else {
                        xyz[0] = a.getX();
                        xyz[1] = a.getY();
                        xyz[2] = a.getZ();
                    }
                    crystal.applySymOp(xyz, xyz, symOp);
                    int type = a.getType();
                    line = new StringBuilder(
                            format("%7d %3s%14.8f%14.8f%14.8f%6d", index, id, xyz[0], xyz[1], xyz[2], type));
                    for (Bond b : a.getBonds()) {
                        a2 = b.get1_2(a);
                        line.append(format("%8d", a2.xyzIndex + indexOffset));
                    }
                    lines[index - 1] = line.append("\n");
                }
            }
            try {
                for (int i = 0; i < numberOfAtoms; i++) {
                    bw.write(lines[i].toString());
                }
            } catch (Exception e) {
                logger.severe("There was an unexpected error writing to " + getActiveMolecularSystem().toString()
                        + "\n" + e + "\nForce Field X will not continue...");
                return false;
            }
            bw.close();
            fw.close();
        } catch (IOException e) {
            logger.severe("Their was an unexpected error writing to " + getActiveMolecularSystem().toString() + "\n"
                    + e + "\nForce Field X will continue...");
            return false;
        }
        return true;
    }
}