Skip to content

Upgraded Solver Handler and fixed bugs in CLI Container #1447

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions vcell-cli/src/main/java/org/vcell/cli/CLIStandalone.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.apache.logging.log4j.Logger;

import cbit.vcell.mongodb.VCMongoMessage;
import org.vcell.cli.run.RunUtils;
import org.vcell.util.VCellUtilityHub;
import org.vcell.util.document.KeyValue;
import org.vcell.util.document.User;
Expand All @@ -36,6 +37,7 @@ public class CLIStandalone {
private final static Logger logger = LogManager.getLogger(CLIStandalone.class);
public static void main(String[] args) {
int exitCode = -1;
RunUtils.drawBreakLine("-", 100);
try{
logger.info("Starting Vcell...");
if (logger.isDebugEnabled()) logger.debug("!!!DEBUG Mode Active!!!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@

public interface CLIRecordable {

public void writeDetailedErrorList(Exception e, String message) throws IOException;
void writeDetailedErrorList(Exception e, String message) throws IOException;

public void writeFullSuccessList(String message) throws IOException;
void writeFullSuccessList(String message) throws IOException;

public void writeErrorList(Exception e, String message) throws IOException;
void writeErrorList(Exception e, String message) throws IOException;

public void writeDetailedResultList(String message) throws IOException;
void writeDetailedResultList(String message) throws IOException;

// we make a list with the omex files that contain (some) spatial simulations (FVSolverStandalone solver)
public void writeSpatialList(String message) throws IOException;
// void writeSpatialList(String message) throws IOException;

public void writeImportErrorList(Exception e, String message) throws IOException;
void writeImportErrorList(Exception e, String message) throws IOException;
}
12 changes: 6 additions & 6 deletions vcell-cli/src/main/java/org/vcell/cli/messaging/CLIRecorder.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
public class CLIRecorder extends Recorder implements CLIRecordable {
protected final static boolean DEFAULT_SHOULD_PRINT_LOG_FILES = false, DEFAULT_SHOULD_FLUSH_LOG_FILES = false;
protected boolean shouldPrintLogFiles, shouldFlushLogFiles;
protected TextFileRecord detailedErrorLog, fullSuccessLog, errorLog, detailedResultsLog, spatialLog, importErrorLog;
protected TextFileRecord detailedErrorLog, fullSuccessLog, errorLog, detailedResultsLog, /*spatialLog,*/ importErrorLog;
protected File outputDirectory;

// Note: this constructor is not public
Expand Down Expand Up @@ -86,7 +86,7 @@ public CLIRecorder(File outputDirectory, boolean forceLogFiles, boolean shouldFl
this.fullSuccessLog = logManager.requestNewRecord(Paths.get(this.outputDirectory.getAbsolutePath(), "fullSuccessLog.txt").toString());
this.errorLog = logManager.requestNewRecord(Paths.get(this.outputDirectory.getAbsolutePath(), "errorLog.txt").toString());
this.detailedResultsLog = logManager.requestNewRecord(Paths.get(this.outputDirectory.getAbsolutePath(), "detailedResultLog.txt").toString());
this.spatialLog = logManager.requestNewRecord(Paths.get(this.outputDirectory.getAbsolutePath(), "hasSpatialLog.txt").toString());
//this.spatialLog = logManager.requestNewRecord(Paths.get(this.outputDirectory.getAbsolutePath(), "hasSpatialLog.txt").toString());
this.importErrorLog = logManager.requestNewRecord(Paths.get(this.outputDirectory.getAbsolutePath(), "importErrorLog.txt").toString());

this.createHeader();
Expand Down Expand Up @@ -162,10 +162,10 @@ public void writeDetailedResultList(String message) throws IOException {
*
* @param message string to write to file
*/
public void writeSpatialList(String message) throws IOException {
// we make a list with the omex files that contain (some) spatial simulations (FVSolverStandalone solver)
this.writeToFileLog(this.spatialLog, message);
}
// public void writeSpatialList(String message) throws IOException {
// // we make a list with the omex files that contain (some) spatial simulations (FVSolverStandalone solver)
// this.writeToFileLog(this.spatialLog, message);
// }

/**
* Write to `importErrorLog.txt`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public void writeErrorList(Exception e, String message) {
public void writeDetailedResultList(String message) {
Tracer.log("writeDetailedResultList(): "+message);
}
@Override
//@Override
public void writeSpatialList(String message) {
Tracer.log("writeSpatialList(): "+message);
}
Expand Down
106 changes: 106 additions & 0 deletions vcell-cli/src/main/java/org/vcell/cli/run/CLISolverListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.vcell.cli.run;

import cbit.vcell.parser.DivideByZeroException;
import cbit.vcell.solver.SolverException;
import cbit.vcell.solver.server.SolverEvent;
import cbit.vcell.solver.server.SolverListener;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.vcell.util.Triplet;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeoutException;

public class CLISolverListener implements SolverListener {
private static final Logger lg = LogManager.getLogger(CLISolverListener.class);

public final CompletableFuture<Triplet<Double, Integer, Exception>> solverResult;
private final StringBuilder solverLog;
private final String solverLabel;

/**
* Tracks a CLI execution of a solver, and offers a completable future for the result!
* @param solverLabel what to call the solver this class listens to
*/
public CLISolverListener(String solverLabel) {
this.solverResult = new CompletableFuture<>();
this.solverLog = new StringBuilder();
this.solverLabel = solverLabel;
}

/**
* Invoked when the solver aborts a calculation (abnormal termination).
*
* @param event indicates the solver and the event type
*/
@Override
public void solverAborted(SolverEvent event) {
Double progress = event.getProgress();
Exception fault = this.determineFault(event);
this.solverResult.complete(new Triplet<>(progress, SolverEvent.SOLVER_ABORTED, fault));
}

private Exception determineFault(SolverEvent event){
String sourceString = event.getSource().toString();
String errorString = event.getSimulationMessage().getDisplayMessage();
String formattedString = String.format("%s(%s): %s", this.solverLabel, sourceString, errorString);
if (errorString.toLowerCase().contains("timed out")) return new TimeoutException(formattedString);
else if (errorString.toLowerCase().contains("divide by zero")) return new DivideByZeroException(formattedString);
else return new SolverException(formattedString);
}

/**
* Invoked when the solver finishes a calculation (normal termination).
*
* @param event indicates the solver and the event type
*/
@Override
public void solverFinished(SolverEvent event) {
Double progress = event.getProgress();
String sourceString = event.getSource().toString();
String successString = event.getSimulationMessage().toString();
lg.info("{}({}) Success Message: {}", this.solverLabel, sourceString, successString);
this.solverResult.complete(new Triplet<>(progress, SolverEvent.SOLVER_FINISHED, null));
}

/**
* Invoked when the solver stores values in the result set.
*
* @param event indicates the solver and the event type
*/
@Override
public void solverPrinted(SolverEvent event) {
this.solverLog.append(event.getSimulationMessage()).append("\n");
}

/**
* Invoked when the solver stores values in the result set.
*
* @param event indicates the solver and the event type
*/
@Override
public void solverProgress(SolverEvent event) {
lg.info("{}({}) progress: {}\t(\"{}\")", this.solverLabel, event.getSource().toString(), event.getProgress(), event.getSimulationMessage());
}

/**
* Invoked when the solver begins a calculation.
*
* @param event indicates the solver and the event type
*/
@Override
public void solverStarting(SolverEvent event) {
lg.info("{}({}) Beginning Simulation (\"{}\")", this.solverLabel, event.getSource().toString(), event.getSimulationMessage());
}

/**
* Invoked when the solver stops a calculation, usually because
* of a user-initiated stop call.
*
* @param event indicates the solver and the event type
*/
@Override
public void solverStopped(SolverEvent event) {
lg.info("{}({}) Ending Simulation: (\"{}\")", this.solverLabel, event.getSource().toString(), event.getSimulationMessage());
}
}
24 changes: 13 additions & 11 deletions vcell-cli/src/main/java/org/vcell/cli/run/ExecutionJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public class ExecutionJob {

private OmexHandler omexHandler = null;
private List<String> sedmlLocations;
private Path sedmlPath2d3d;
private File inputFile;

private CLIRecordable cliRecorder;
Expand All @@ -59,7 +58,7 @@ public ExecutionJob(File inputFile, File rootOutputDir, CLIRecordable cliRecorde

this.bioModelBaseName = FileUtils.getBaseName(inputFile.getName()); // input file without the path
String outputBaseDir = rootOutputDir.getAbsolutePath();
this.outputDir = bEncapsulateOutput ? Paths.get(outputBaseDir, bioModelBaseName).toString() : outputBaseDir;
this.outputDir = bEncapsulateOutput ? Paths.get(outputBaseDir, this.bioModelBaseName).toString() : outputBaseDir;
this.bKeepTempFiles = bKeepTempFiles;
this.bExactMatchOnly = bExactMatchOnly;
this.bSmallMeshOverride = bSmallMeshOverride;
Expand All @@ -86,7 +85,6 @@ public void preprocessArchive() throws IOException {

// Unpack the Omex Archive
try { // It's unlikely, but if we get errors here they're fatal.
this.sedmlPath2d3d = Paths.get(this.outputDir, "temp");
this.omexHandler = new OmexHandler(this.inputFile.getAbsolutePath(), this.outputDir);
this.omexHandler.extractOmex();
this.sedmlLocations = this.omexHandler.getSedmlLocationsAbsolute();
Expand Down Expand Up @@ -136,17 +134,21 @@ public void executeArchive(boolean isBioSimSedml) throws BiosimulationsHdfWriter
} catch (IOException e){
logger.error("System IO encountered a fatal error");
throw new ExecutionException(e);
} finally {
RunUtils.drawBreakLine("-", 100);
}

}

private void executeSedmlDocument(String sedmlLocation, HDF5ExecutionResults cumulativeHdf5Results) throws IOException, PreProcessingException, ExecutionException {
BiosimulationLog.instance().updateSedmlDocStatusYml(sedmlLocation, BiosimulationLog.Status.QUEUED);
SedmlJob job = new SedmlJob(sedmlLocation, this.omexHandler, this.inputFile, this.outputDir, this.sedmlPath2d3d.toString(), this.cliRecorder, this.bKeepTempFiles, this.bExactMatchOnly, this.bSmallMeshOverride, this.logOmexMessage);
SedmlJob job = new SedmlJob(sedmlLocation, this.omexHandler.getOutputPathFromSedml(sedmlLocation), this.inputFile, this.outputDir, this.cliRecorder, this.bKeepTempFiles, this.bExactMatchOnly, this.bSmallMeshOverride, this.logOmexMessage);
SedmlStatistics stats = job.preProcessDoc();
boolean hasSucceeded = job.simulateSedml(cumulativeHdf5Results);
this.anySedmlDocumentHasSucceeded |= hasSucceeded;
this.anySedmlDocumentHasFailed &= hasSucceeded;
logger.log(hasSucceeded ? Level.INFO : Level.ERROR, "Processing of SedML ({}) {}", stats.getSedmlName(), hasSucceeded ? "succeeded." : "failed!");
RunUtils.drawBreakLine("-", 100);
}

/**
Expand All @@ -162,23 +164,23 @@ public void postProcessessArchive() throws IOException {
this.endTime_ms = System.currentTimeMillis();
long elapsedTime_ms = this.endTime_ms - this.startTime_ms;
double duration_s = elapsedTime_ms / 1000.0;
logger.info("Omex `" + inputFile.getName() + "` processing completed (" + duration_s + "s)");
logger.info("Omex `" + this.inputFile.getName() + "` processing completed (" + duration_s + "s)");
//
// failure if at least one of the documents in the omex archive fails
//
if (anySedmlDocumentHasFailed) {
if (this.anySedmlDocumentHasFailed) {
String error = " All sedml documents in this archive failed to execute";
if (anySedmlDocumentHasSucceeded) { // some succeeded, some failed
if (this.anySedmlDocumentHasSucceeded) { // some succeeded, some failed
error = " At least one document in this archive failed to execute";
}
BiosimulationLog.instance().updateOmexStatusYml(BiosimulationLog.Status.FAILED, duration_s);
logger.error(error);
logOmexMessage.append(error);
cliRecorder.writeErrorList(new Exception("exception not recorded"), bioModelBaseName);
this.logOmexMessage.append(error);
this.cliRecorder.writeErrorList(new Exception("exception not recorded"), this.bioModelBaseName);
} else {
BiosimulationLog.instance().updateOmexStatusYml(BiosimulationLog.Status.SUCCEEDED, duration_s);
cliRecorder.writeFullSuccessList(bioModelBaseName);
logOmexMessage.append(" Done");
this.cliRecorder.writeFullSuccessList(this.bioModelBaseName);
this.logOmexMessage.append(" Done");

}
BiosimulationLog.instance().setOutputMessage("null", "null", "omex", logOmexMessage.toString());
Expand Down
49 changes: 10 additions & 39 deletions vcell-cli/src/main/java/org/vcell/cli/run/OmexHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,29 +94,6 @@ private void replaceMetadataRdfFiles(Path zipFilePath) throws IOException {
}
}

public static void rename(String zipFileName, String entryOldName, String entryNewName) throws Exception {

/* Define ZIP File System Properties in HashMap */
Map<String, String> zip_properties = new HashMap<>();
/* We want to read an existing ZIP File, so we set this to False */
zip_properties.put("create", "false");

/* Specify the path to the ZIP File that you want to read as a File System */
URI zip_disk = URI.create("jar:file:/" + zipFileName);

/* Create ZIP file System */
try (FileSystem zipfs = FileSystems.newFileSystem(zip_disk, zip_properties)) {
/* Access file that needs to be renamed */
Path pathInZipfile = zipfs.getPath(entryOldName);
/* Specify new file name */
Path renamedZipEntry = zipfs.getPath(entryNewName);
logger.trace("About to rename an entry from ZIP File" + pathInZipfile.toUri());
/* Execute rename */
Files.move(pathInZipfile, renamedZipEntry, StandardCopyOption.ATOMIC_MOVE);
logger.trace("File successfully renamed");
}
}

public List<String> getSedmlLocationsRelative(){
Collection<ArchiveEntry> entries = this.archive.getEntries();

Expand All @@ -135,26 +112,16 @@ public List<String> getSedmlLocationsRelative(){
sedmlMap.get(isMaster ? MASTER : REGULAR).add(entry);
}

if (!sedmlMap.get(MASTER).isEmpty()) return sedmlMap.get(MASTER).stream().map(ArchiveEntry::getFilePath).toList();

// Test corner cases
if (sedmlMap.get(MASTER).isEmpty()){
if (sedmlMap.get(REGULAR).isEmpty()) {
throw new RuntimeException("There are no SED-MLs in the archive to execute");
}
if (masterCount > 0) {
logger.warn("No SED-MLs are marked as master, so will run them all");
}
return sedmlMap.get(REGULAR).stream().map(ArchiveEntry::getFilePath).toList();
}
if (sedmlMap.get(REGULAR).isEmpty()) throw new RuntimeException("There are no SED-MLs in the archive to execute");

return sedmlMap.get(MASTER).stream().map(ArchiveEntry::getFilePath).toList();
}
if (masterCount > 0) logger.warn("No SED-MLs are marked as master, so will run them all");

private boolean isSedmlFormat(ArchiveEntry entry) {
URI format = entry.getFormat();
return format.getPath().contains("sedml") || format.getPath().contains("sed-ml");
return sedmlMap.get(REGULAR).stream().map(ArchiveEntry::getFilePath).toList();
}


public ArrayList<String> getSedmlLocationsAbsolute(){
ArrayList<String> sedmlListAbsolute = new ArrayList<>();
List<String> sedmlListRelative = this.getSedmlLocationsRelative();
Expand All @@ -165,9 +132,13 @@ public ArrayList<String> getSedmlLocationsAbsolute(){
return sedmlListAbsolute;
}

private boolean isSedmlFormat(ArchiveEntry entry) {
URI format = entry.getFormat();
return format.getPath().contains("sedml") || format.getPath().contains("sed-ml");
}

public String getOutputPathFromSedml(String absoluteSedmlPath) {
String outputPath = "";
//String sedmlName = absoluteSedmlPath.substring(absoluteSedmlPath.lastIndexOf(File.separator) + 1);
List<String> sedmlListRelative = this.getSedmlLocationsRelative();
for (String sedmlFileRelative : sedmlListRelative) {
boolean check = absoluteSedmlPath.contains(Paths.get(sedmlFileRelative).normalize().toString());
Expand Down
Loading
Loading