/*************************************************************************
* *
* This file is part of the 20n/act project. *
* 20n/act enables DNA prediction for synthetic biology/bioengineering. *
* Copyright (C) 2017 20n Labs, Inc. *
* *
* Please direct all queries to act@20n.com. *
* *
* 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, see <http://www.gnu.org/licenses/>. *
* *
*************************************************************************/
package com.act.biointerpretation.l2expansion;
import chemaxon.reaction.ReactionException;
import com.act.biointerpretation.sars.NoSar;
import com.act.biointerpretation.sars.Sar;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public abstract class L2Expander implements Serializable {
private static final long serialVersionUID = 5846728290095735668L;
private static final Logger LOGGER = LogManager.getFormatterLogger(L2Expander.class);
// This SAR accepts every substrate.
@JsonIgnore
protected static final List<Sar> NO_SAR = Collections.unmodifiableList(Collections.singletonList(new NoSar()));
private PredictionGenerator generator;
public abstract Iterable<PredictionSeed> getPredictionSeeds();
public L2Expander(PredictionGenerator generator) {
this.generator = generator;
}
/**
* Get predictions for this expander without logging progress.
*
* @return A corpus of L2 predictions using the specified generator.
*/
public L2PredictionCorpus getPredictions() {
return getPredictions(Optional.empty());
}
/**
* Get predictions for this expander, logging progress to the specified output stream.
*
* @param maybeOutputStream A stream to which to write incremental results.
* @return A corpus of L2 predicitions using the specified generator.
*/
public L2PredictionCorpus getPredictions(Optional<OutputStream> maybeOutputStream) {
L2PredictionCorpus result = new L2PredictionCorpus();
Optional<OutputStreamWriter> maybeWriter = maybeOutputStream.map(OutputStreamWriter::new);
ObjectMapper objectMapper = new ObjectMapper();
int counter = 0;
for (PredictionSeed seed : getPredictionSeeds()) {
if (counter % 1000 == 0) {
LOGGER.info("Processed %d seeds", counter);
}
counter++;
// Apply reactor to substrate if possible
try {
List<L2Prediction> results = generator.getPredictions(seed);
if (maybeWriter.isPresent()) {
try {
/* Write results as string to ensure the object mapper doesn't close the stream we give it. See
* https://fasterxml.github.io/jackson-databind/javadoc/2.6/com/fasterxml/jackson/databind/ObjectMapper.html#writeValue-java.io.OutputStream-java.lang.Object-
* for a confusing explanation of why we worry about this. */
String resultJson = objectMapper.writeValueAsString(results);
maybeWriter.get().write(resultJson);
maybeWriter.get().write("\n");
maybeWriter.get().flush(); // Flush to ensure the user can actually see the progress output.
} catch (Exception e) {
LOGGER.error("Caught exception when writing progress, skipping: %s", e.getMessage());
}
}
result.addAll(results);
// If there is an error on a certain RO, metabolite pair, we should log the error, but the expansion may
// produce some valid results, so no error is thrown.
} catch (ReactionException e) {
LOGGER.error("ReactionException on getPredictions. %s", e.getMessage());
} catch (IOException e) {
LOGGER.error("IOException during prediction generation. %s", e.getMessage());
}
}
return result;
}
}