/*
Copyright (C) 2009 Diego Darriba
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package es.uvigo.darwin.prottest.facade;
import static es.uvigo.darwin.prottest.global.ApplicationGlobals.APPLICATION_PROPERTIES;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import mpi.MPI;
import pal.tree.Tree;
import es.uvigo.darwin.prottest.exe.util.TemporaryFileManager;
import es.uvigo.darwin.prottest.facade.strategy.DistributionStrategy;
import es.uvigo.darwin.prottest.facade.strategy.DynamicDistributionStrategy;
import es.uvigo.darwin.prottest.facade.strategy.HybridDistributionStrategy;
import es.uvigo.darwin.prottest.facade.strategy.ImprovedDynamicDistributionStrategy;
import es.uvigo.darwin.prottest.facade.strategy.StaticDistributionStrategy;
import es.uvigo.darwin.prottest.global.options.ApplicationOptions;
import es.uvigo.darwin.prottest.model.Model;
import es.uvigo.darwin.prottest.util.ProtTestAlignment;
import es.uvigo.darwin.prottest.util.Utilities;
import es.uvigo.darwin.prottest.util.checkpoint.CheckPointManager;
import es.uvigo.darwin.prottest.util.checkpoint.status.ProtTestStatus;
import es.uvigo.darwin.prottest.util.collection.ModelCollection;
import es.uvigo.darwin.prottest.util.collection.SingleModelCollection;
import es.uvigo.darwin.prottest.util.comparator.AminoAcidModelNaturalComparator;
import es.uvigo.darwin.prottest.util.comparator.ModelDistributionHeuristic;
/**
* A parallel implementation of the ProtTest facade.
*/
public class ProtTestFacadeMPJ extends ProtTestFacadeImpl {
/** The parallel distribution strategy. */
private DistributionStrategy strategy;
/** Boolean variable to show if MPJ environment is running. Some
* distribution strategies can be used even if the execution is
* sequential. */
private boolean mpjRun;
/** The MPJ rank of the process. It is only useful if MPJ is running. */
private int mpjMe;
/** The MPJ size of the communicator. It is only useful if MPJ is running. */
private int mpjSize;
/** The thread pool size. */
private int poolSize = 1;
private CheckPointManager cpManager;
/* (non-Javadoc)
* @see es.uvigo.darwin.prottest.facade.ProtTestFacade#getNumberOfThreads()
*/
@Override
public int getNumberOfThreads() {
return poolSize;
}
/* (non-Javadoc)
* @see es.uvigo.darwin.prottest.facade.ProtTestFacade#setNumberOfThreads(int)
*/
@Override
public void setNumberOfThreads(int numThreads) {
// options.setNumberOfThreads(numThreads);
this.poolSize = numThreads;
}
/**
* Instantiates a new parallel ProtTest facade.
*
* @param mpjRun the running state of MPJ
* @param mpjMe the rank of the current process in MPJ
* @param mpjSize the size of the MPJ communicator
*/
public ProtTestFacadeMPJ(boolean mpjRun, int mpjMe, int mpjSize) {
this.mpjRun = mpjRun;
this.mpjMe = mpjMe;
this.mpjSize = mpjSize;
}
@Override
protected Tree calculateBionjJTT(ApplicationOptions options) {
Tree[] t = new Tree[1];
if (mpjMe == 0) {
t[0] = super.calculateBionjJTT(options);
}
MPI.COMM_WORLD.Bcast(t, 0, 1, MPI.OBJECT, 0);
return t[0];
}
public Model[] analyze(ApplicationOptions options) {
ModelCollection arrayListModel = null;
if (mpjMe == 0) {
//Adding support for checkpointing
ProtTestStatus initialStatus = new ProtTestStatus(null, options);
cpManager = new CheckPointManager();
if (cpManager.loadStatus(initialStatus)) {
arrayListModel = new SingleModelCollection(
((ProtTestStatus) cpManager.getLastCheckpoint()).getModels(),
options.getAlignment());
} else {
arrayListModel = new SingleModelCollection(options.getAlignment());
Properties modelProperties = new Properties();
if (options.isPlusF()) {
modelProperties.setProperty(Model.PROP_PLUS_F, "true");
}
arrayListModel.addModelCartesian(options.getMatrices(), options.getDistributions(), modelProperties,
options.getAlignment(), options.getTree(), options.ncat);
}
}
String strategyProp = APPLICATION_PROPERTIES.getProperty("parallel_strategy", "static");
if (strategyProp.equals("dynamic")) {
strategy = new DynamicDistributionStrategy(mpjMe, mpjSize, options, cpManager);
} else if (strategyProp.equals("dynamic_improved")) {
strategy = new ImprovedDynamicDistributionStrategy(mpjMe, mpjSize, options, cpManager);
} else if (strategyProp.equals("hybrid")) {
int numberOfThreads;
try {
numberOfThreads = Integer.parseInt(APPLICATION_PROPERTIES.getProperty("number_of_threads",
String.valueOf(Runtime.getRuntime().availableProcessors())));
} catch (NumberFormatException ex) {
numberOfThreads = Runtime.getRuntime().availableProcessors();
}
setNumberOfThreads(numberOfThreads);
strategy = new HybridDistributionStrategy(mpjMe, mpjSize, options, cpManager, getNumberOfThreads());
TemporaryFileManager.synchronize(options.getAlignment(), options.getTree(),
getNumberOfThreads());
} else {
strategy = new StaticDistributionStrategy(mpjMe, mpjSize, options);
}
strategy.addObserver(this);
Model[] allModels = null;
//For each model, for each distribution,... optimize the model and calculate some statistics:
if (mpjMe == 0) {
println("**********************************************************");
//this is only for doing output prettier
println("Observed number of invariant sites: " + ProtTestAlignment.calculateInvariableSites(options.getAlignment(), false));
StringWriter sw = new StringWriter();
ProtTestAlignment.printFrequencies(ProtTestAlignment.getFrequencies(options.getAlignment()), new PrintWriter(sw));
sw.flush();
println(sw.toString());
println("**********************************************************");
println("");
allModels = strategy.distribute(arrayListModel, new ModelDistributionHeuristic());
} else {
strategy.request();
}
long startTime = strategy.getStartTime();
long endTime = strategy.getEndTime();
if (mpjRun) {
long[] runtime = {endTime - startTime};
long[] runtimes = new long[mpjSize];
// gathering run times
MPI.COMM_WORLD.Gather(runtime, 0, 1, MPI.LONG,
runtimes, 0, 1, MPI.LONG, 0);
if (mpjMe == 0) {
List<Model> sortedModels = new SingleModelCollection(allModels, options.getAlignment());
Collections.sort(sortedModels, new AminoAcidModelNaturalComparator());
for (Model model : sortedModels) {
println("");
model.printReport();
println("");
}
println("************************************************************");
println("Date: " + (new Date()).toString());
for (int i = 0; i < mpjSize; i++) {
println("Runtime processor " + i + ": " + Utilities.arrangeRuntime(runtimes[i]));
}
println("Minimum runtime: " + Utilities.arrangeRuntime(Utilities.getMin(runtimes)));
println("Maximum runtime: " + Utilities.arrangeRuntime(Utilities.getMax(runtimes)));
println("Average runtime: " + Utilities.arrangeRuntime(Utilities.getAverage(runtimes)));
println("");
println("");
flush();
}
} else {
println("************************************************************");
String runtimeStr = Utilities.calculateRuntime(startTime, endTime);
println("Date : " + (new Date()).toString());
println("Runtime: " + runtimeStr);
println("");
println("");
}
return allModels;
}
}