/*
Copyright (C) 2011 Diego Darriba, David Posada
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 3 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.jmodeltest.exe;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import es.uvigo.darwin.jmodeltest.ApplicationOptions;
import es.uvigo.darwin.jmodeltest.ModelTest;
import es.uvigo.darwin.jmodeltest.model.Model;
import es.uvigo.darwin.jmodeltest.observer.ProgressInfo;
import es.uvigo.darwin.jmodeltest.selection.AIC;
import es.uvigo.darwin.jmodeltest.selection.AICc;
import es.uvigo.darwin.jmodeltest.selection.BIC;
import es.uvigo.darwin.jmodeltest.selection.InformationCriterion;
public class RunPhymlThread extends RunPhyml {
private ExecutorService threadPool;
private int currentStage;
private int numModelsInStage;
public RunPhymlThread(Observer progress, ApplicationOptions options,
Model[] models) {
super(progress, options, models);
this.threadPool = Executors.newFixedThreadPool(options
.getNumberOfThreads());
}
/*******************************
* doPhyml ****************************** * run the phyml calculations on a
* separate thread * * *
***********************************************************************/
protected Object doPhyml() {
boolean errorsFound = false;
if (options.isClusteringSearch()) {
List<Model> evaluatedModels = new ArrayList<Model>();
evaluatedModels.add(gtrModel);
Model globalBestModel = gtrModel;
if (gtrModel == null) {
globalBestModel = models[models.length-1];
}
double globalBestScore = Double.MAX_VALUE;
for (int groups=6; groups>0; groups--) {
double bestScore = Double.MAX_VALUE;
String partition = globalBestModel==null?"012345":globalBestModel.getPartition();
Model[] currentModels = GuidedSearchManager.getModelsSubset(models, partition, groups);
currentStage = 7-groups;
numModelsInStage = currentModels.length;
if (currentModels.length > 0) {
// Optimize the current models
Model bestModel = currentModels[0];
errorsFound |= !parallelExecute(currentModels, false);
for (Model model : currentModels) {
double currentScore = Double.MAX_VALUE - 1.0;
switch (options.getHeuristicInformationCriterion()) {
case InformationCriterion.IC_AIC:
currentScore = AIC.computeAic(model, options);
break;
case InformationCriterion.IC_BIC:
currentScore = BIC.computeBic(model, options);
break;
case InformationCriterion.IC_AICc:
currentScore = AICc.computeAicc(model, options);
break;
}
if (currentScore < bestScore) {
bestModel = model;
bestScore = currentScore;
}
}
// Check LnL
if (globalBestModel.getLnL()>0 && bestScore > globalBestScore) {
// End of algorithm
break;
} else {
globalBestModel = bestModel;
globalBestScore = bestScore;
}
}
}
ModelTest.purgeModels();
} else {
errorsFound = !parallelExecute(models, false);
}
if (errorsFound) {
notifyObservers(ProgressInfo.OPTIMIZATION_COMPLETED_INTERRUPTED, models.length,
null, null);
return "Interrupted";
} else {
notifyObservers(ProgressInfo.OPTIMIZATION_COMPLETED_OK, models.length,
null, null);
}
return "All Done";
} // doPhyml
protected boolean parallelExecute(Model models[], boolean ignoreGaps) {
Collection<Callable<Object>> c = new ArrayList<Callable<Object>>();
int current = 0;
for (Model model : models) {
if (model != null) {
PhymlSingleModel psm = new PhymlSingleModel(model, current, false,
ignoreGaps, options);
psm.addObserver(this);
c.add(Executors.callable(psm));
current++;
}
}
Collection<Future<Object>> futures = null;
try {
futures = threadPool.invokeAll(c);
} catch (InterruptedException e) {
notifyObservers(ProgressInfo.INTERRUPTED, 0, null, null);
}
if (futures != null) {
for (Future<Object> f : futures) {
try {
f.get();
} catch (InterruptedException ex) {
notifyObservers(ProgressInfo.INTERRUPTED, 0, null, null);
ex.printStackTrace();
return false;
} catch (ExecutionException ex) {
// Internal exception while computing model.
// Let's continue with errors
ex.printStackTrace();
return false;
}
}
}
return true;
}
public void interruptThread() {
super.interruptThread();
ProcessManager.getInstance().killAll();
threadPool.shutdownNow();// shutdown();
}
@Override
public void update(Observable o, Object arg) {
if (arg != null) {
ProgressInfo info = (ProgressInfo) arg;
if (info.getType() == ProgressInfo.ERROR ||
info.getType() == ProgressInfo.ERROR_BINARY_NOEXECUTE ||
info.getType() == ProgressInfo.ERROR_BINARY_NOEXISTS) {
interruptThread();
} else if (options.isClusteringSearch()) {
info.setHeuristicStage(currentStage);
info.setNumModelsInStage(numModelsInStage);
}
}
super.update(o, arg);
}
}