ffx.algorithms.SimulatedAnnealing.java Source code

Java tutorial

Introduction

Here is the source code for ffx.algorithms.SimulatedAnnealing.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.algorithms;

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

import org.apache.commons.configuration.CompositeConfiguration;

import ffx.algorithms.Integrator.Integrators;
import ffx.algorithms.Thermostat.Thermostats;
import ffx.numerics.Potential;
import ffx.potential.MolecularAssembly;

/**
 * Run NVT molecular dynamics at a series of temperatures.
 *
 * @author Michael J. Schnieders
 * @since 1.0
 *
 */
public class SimulatedAnnealing implements Runnable, Terminatable {

    private static final Logger logger = Logger.getLogger(SimulatedAnnealing.class.getName());
    private final MolecularDynamics molecularDynamics;
    private double highTemperature;
    private double lowTemperature;
    private int annealingSteps;
    private int mdSteps;
    private double timeStep;
    private boolean done, terminate;
    private boolean targetTemperaturesPresent = false;
    private double[] targetTemperatures;
    private double printInterval = 0.01;

    /**
     * <p>
     * Constructor for SimulatedAnnealing.</p>
     *
     * @param assembly a {@link ffx.potential.MolecularAssembly} object.
     * @param potentialEnergy a {@link ffx.numerics.Potential} object.
     * @param properties a
     * {@link org.apache.commons.configuration.CompositeConfiguration} object.
     * @param listener a {@link ffx.algorithms.AlgorithmListener} object.
     */
    public SimulatedAnnealing(MolecularAssembly assembly, Potential potentialEnergy,
            CompositeConfiguration properties, AlgorithmListener listener) {

        this(assembly, potentialEnergy, properties, listener, Thermostats.BERENDSEN, Integrators.BEEMAN);
    }

    /**
     * <p>
     * Constructor for SimulatedAnnealing.</p>
     *
     * @param assembly a {@link ffx.potential.MolecularAssembly} object.
     * @param potentialEnergy a {@link ffx.numerics.Potential} object.
     * @param properties a
     * {@link org.apache.commons.configuration.CompositeConfiguration} object.
     * @param listener a {@link ffx.algorithms.AlgorithmListener} object.
     * @param requestedThermostat a
     * {@link ffx.algorithms.Thermostat.Thermostats}
     * @param requestedIntegrator a
     * {@link ffx.algorithms.Integrator.Integrators}
     */
    public SimulatedAnnealing(MolecularAssembly assembly, Potential potentialEnergy,
            CompositeConfiguration properties, AlgorithmListener listener, Thermostats requestedThermostat,
            Integrators requestedIntegrator) {

        molecularDynamics = new MolecularDynamics(assembly, potentialEnergy, properties, listener,
                requestedThermostat, requestedIntegrator);
        done = true;
    }

    /**
     * <p>
     * anneal</p>
     *
     * @param highTemperature a double.
     * @param lowTemperature a double.
     * @param annealingSteps a int.
     * @param mdSteps a int.
     */
    public void anneal(double highTemperature, double lowTemperature, int annealingSteps, int mdSteps) {
        anneal(highTemperature, lowTemperature, annealingSteps, mdSteps, 1.0);
    }

    /**
     * <p>
     * anneal</p>
     *
     * @param highTemperature a double.
     * @param lowTemperature a double.
     * @param annealingSteps a int.
     * @param mdSteps a int.
     * @param timeStep a double
     */
    public void anneal(double highTemperature, double lowTemperature, int annealingSteps, int mdSteps,
            double timeStep) {

        /**
         * Return if already running; Could happen if two threads call dynamic
         * on the same SimulatedAnnealing instance.
         */
        if (!done) {
            logger.warning(" Programming error - a thread invoked anneal when it was already running.");
            return;
        }
        done = false;
        logger.info(" Simulated annealing starting up");

        if (annealingSteps <= 0) {
            annealingSteps = 1;
        }
        this.annealingSteps = annealingSteps;
        if (highTemperature < 0) {
            highTemperature = 400.0;
        }
        this.highTemperature = highTemperature;
        if (annealingSteps == 1) {
            lowTemperature = highTemperature;
        } else if (lowTemperature < 0.0 || lowTemperature > highTemperature) {
            lowTemperature = 100;
        }
        this.lowTemperature = lowTemperature;

        if (mdSteps <= 0) {
            mdSteps = 100;
        }
        this.mdSteps = mdSteps;

        if (timeStep <= 0) {
            timeStep = 1.0;
        }
        this.timeStep = timeStep;

        logger.info(String.format(" Initial temperature:    %8.3f (Kelvin)", highTemperature));
        logger.info(String.format(" Final temperature:      %8.3f (Kelvin)", lowTemperature));
        logger.info(String.format(" Annealing steps:        %8d", annealingSteps));
        logger.info(String.format(" MD steps/temperature:   %8d", mdSteps));
        logger.info(String.format(" MD time step:           %8.3f (fs)", timeStep));

        Thread annealingThread = new Thread(this);
        annealingThread.start();
        synchronized (this) {
            try {
                while (annealingThread.isAlive()) {
                    wait(100);
                }
            } catch (Exception e) {
                String message = "Simualted annealing interrupted.";
                logger.log(Level.WARNING, message, e);
            }
        }

    }

    public void annealToTargetValues(double[] targetTemperatures, int mdSteps, double timeStep) {

        targetTemperaturesPresent = true;
        this.targetTemperatures = targetTemperatures;

        if (mdSteps <= 0) {
            mdSteps = 100;
        }
        this.mdSteps = mdSteps;

        if (timeStep <= 0) {
            timeStep = 1.0;
        }
        this.timeStep = timeStep;

        Thread annealingThread = new Thread(this);
        annealingThread.start();
        synchronized (this) {
            try {
                while (annealingThread.isAlive()) {
                    wait(100);
                }
            } catch (Exception e) {
                String message = "Simualted annealing interrupted.";
                logger.log(Level.WARNING, message, e);
            }
        }
    }

    /**
     * {@inheritDoc}
     *
     * This method should only be invoked within the SimulatedAnnealing
     * instance.
     */
    @Override
    public void run() {
        done = false;
        terminate = false;

        if (!targetTemperaturesPresent) {
            double dt = (highTemperature - lowTemperature) / (annealingSteps - 1);
            for (int i = 0; i < annealingSteps; i++) {
                double temperature = highTemperature - dt * i;
                molecularDynamics.dynamic(mdSteps, timeStep, printInterval, 10.0, temperature, true, null);
                if (terminate) {
                    logger.info(String.format("\n Terminating at temperature %8.3f.\n", temperature));
                    break;
                }
            }
        } else {
            for (int i = 0; i < targetTemperatures.length; i++) {
                double temperature = targetTemperatures[i];
                molecularDynamics.dynamic(mdSteps, timeStep, printInterval, 10.0, temperature, true, null);
                if (terminate) {
                    logger.info(String.format("\n Terminating at temperature %8.3f.\n", temperature));
                    break;
                }
            }
        }
        if (!terminate) {
            logger.info(String.format(" Completed %8d annealing steps\n", annealingSteps));
        }

        done = true;
        terminate = false;
    }

    //Set print interval to report thermodyanamics (psec)
    public void setPrintInterval(double printInterval) {
        this.printInterval = printInterval;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void terminate() {
        terminate = true;
        while (!done) {
            synchronized (this) {
                try {
                    wait(1);
                } catch (Exception e) {
                    logger.log(Level.WARNING, "Exception terminating annealing.\n", e);
                }
            }
        }
    }
}