Skip to content

Commit

Permalink
new interface TextFileFormatted #437
Browse files Browse the repository at this point in the history
  • Loading branch information
walterxie committed Jan 19, 2024
1 parent 0734420 commit 1adcf57
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 38 deletions.
10 changes: 10 additions & 0 deletions examples/output/jcc2Fasta.lphy
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
data {
L = 200;
taxa = taxa(names=1:10);
}
model {
Θ ~ LogNormal(meanlog=3.0, sdlog=1.0);
ψ ~ Coalescent(theta=Θ, taxa=taxa);
D ~ PhyloCTMC(tree=ψ, L=L, Q=jukesCantor());
fastaD = fasta(D);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package lphy.base.evolution.alignment;

import jebl.evolution.sequences.SequenceType;
import lphy.base.evolution.Taxa;
import lphy.core.logger.LoggerUtils;
import lphy.core.logger.TextFileFormatted;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class FastaAlignment extends SimpleAlignment implements TextFileFormatted {

public FastaAlignment(Map<String, Integer> idMap, int nchar, SequenceType sequenceType) {
super(idMap, nchar, sequenceType);
}

public FastaAlignment(Taxa taxa, int nchar, SequenceType sequenceType) {
super(taxa, nchar, sequenceType);
}

public FastaAlignment(int nchar, Alignment source) {
super(nchar, source);
}

@Override
public List<String> getTextForFile() {
List<String> lines = new ArrayList<>();

for (int i=0; i < ntaxa(); i++) {
try {
String taxonName = getTaxaNames()[i];
lines.add(taxonName);
String sequence = getSequence(i);
lines.add(sequence);
} catch (Exception ex) {
LoggerUtils.log.severe("Error at " + i + " taxa (" + getTaxaNames()[i] + ") in " +
this.getClass().getName());
}
}

return lines;
}

@Override
public String getFileType() {
return ".fasta";
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ public final class ReaderConst {

public static final String DELIMITER = "sep";
public static final String HEADER = "header";

public static final String ALIGNMENT = "alignment";

}
47 changes: 47 additions & 0 deletions lphy-base/src/main/java/lphy/base/function/io/WriteFasta.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package lphy.base.function.io;

import lphy.base.evolution.alignment.Alignment;
import lphy.base.evolution.alignment.FastaAlignment;
import lphy.core.model.DeterministicFunction;
import lphy.core.model.Value;
import lphy.core.model.annotation.GeneratorCategory;
import lphy.core.model.annotation.GeneratorInfo;
import lphy.core.model.annotation.ParameterInfo;

public class WriteFasta extends DeterministicFunction<FastaAlignment> {


public WriteFasta(@ParameterInfo(name = ReaderConst.ALIGNMENT,
description = "the lphy alignment that is written into the fasta file.")
Value<Alignment> alignmentValue ) {


if (alignmentValue == null) throw new IllegalArgumentException("The alignment can't be null!");
setParam(ReaderConst.ALIGNMENT, alignmentValue);
}


@GeneratorInfo(name="fasta", verbClause = "is read from", narrativeName = "fasta file",
category = GeneratorCategory.TAXA_ALIGNMENT, examples = {"covidDPG.lphy"},
description = "A function that parses an alignment from a fasta file.")
public Value<FastaAlignment> apply() {

Alignment alignment = ((Value<Alignment>) getParams().get(ReaderConst.ALIGNMENT)).value();

// this only creates taxa and nchar
FastaAlignment faData = new FastaAlignment(alignment.nchar(), alignment);

// fill in states
for (int i=0; i < alignment.ntaxa(); i++) {
for (int j = 0; j < alignment.nchar(); j++) {
faData.setState(i, j, alignment.getState(i, j));
}
}

return new Value<>(null, faData, this);

}



}
4 changes: 3 additions & 1 deletion lphy-base/src/main/java/lphy/base/spi/LPhyBaseImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import lphy.base.function.io.ReadDelim;
import lphy.base.function.io.ReadFasta;
import lphy.base.function.io.ReadNexus;
import lphy.base.function.io.WriteFasta;
import lphy.base.function.taxa.*;
import lphy.base.function.tree.ExtantTree;
import lphy.base.function.tree.MigrationCount;
Expand Down Expand Up @@ -96,7 +97,8 @@ public List<Class<? extends BasicFunction>> declareFunctions() {
// Matrix
BinaryRateMatrix.class, MigrationMatrix.class, MigrationCount.class,
// IO
Newick.class, ReadNexus.class, ReadFasta.class, ReadDelim.class, ExtractTrait.class, SpeciesTaxa.class,
Newick.class, ReadNexus.class, ReadFasta.class, ReadDelim.class, WriteFasta.class,
ExtractTrait.class, SpeciesTaxa.class,
// Math
SumBoolean.class, SumRows.class, SumCols.class, Sum2dArray.class, Sum.class,// Product.class,
// Set Op
Expand Down
2 changes: 1 addition & 1 deletion lphy/src/main/java/lphy/core/io/OutputSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public static void setOut(String outputFileName) {

// consider outputFileName could be the absolute path, or relative, or only file name.
// also check if the preferred output dir
private static File getOutputFile(String outputFileName) {
public static File getOutputFile(String outputFileName) {
File outDir = getOrCreateOutputDirectory();
Path child = Paths.get(outputFileName);

Expand Down
14 changes: 14 additions & 0 deletions lphy/src/main/java/lphy/core/logger/TextFileFormatted.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package lphy.core.logger;

import java.util.List;

/**
* Implement this to make the value to be loggable into a file.
*/
public interface TextFileFormatted {

List<String> getTextForFile();

String getFileType();

}
101 changes: 65 additions & 36 deletions lphy/src/main/java/lphy/core/logger/ValueFileLoggerListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -118,42 +120,69 @@ else if (index < 1) // index starts from 0
for (int i = 0; i < values.size(); i++) {

Value value = values.get(i);
List<ValueFormatter> formatters = valueFormatResolver.getFormatter(value);

// if it is array, then one ValueFormatter for one element
for (int j = 0; j < formatters.size(); j++) {
ValueFormatter formatter = formatters.get(j);

if (formatter == null) {
LoggerUtils.log.warning("Cannot find formatter for " + value.getId() +
", type is " + value.getType());

} else if (formatter.getMode() == ValueFormatter.Mode.VALUE_PER_FILE) {
// e.g. Alignment
ValueFormatHandler.ValuePerFile.createFile(index, formatter,
fileConfig.getFilePrefix(), fileConfig.getNumReplicates());

ValueFormatHandler.ValuePerFile
.exportValuePerFile(index, value, formatter);

} else if (formatter.getMode() == ValueFormatter.Mode.VALUE_PER_LINE) {
// process meta data given 1st value
if (index == 0)
ValueFormatHandler.ValuePerLine.processHeaderFooter(formatter,
metadataById, fileConfig.getFilePrefix());

// e.g. Trees
ValueFormatHandler.ValuePerLine.populateValues(index, value, formatter, linesById);

} else if (formatter.getMode() == ValueFormatter.Mode.VALUE_PER_CELL) {
// add col names and parameters values
ValueFormatHandler.ValuePerCell.addColumnNamesAndLines(index, firstColValuePerCell,
value, formatter, valuesByRepColNamesBuilder, valuesByRepBuilder);
firstColValuePerCell = false;

} else
throw new RuntimeException("Unrecognised formatter mode : " + formatter.getMode() + " !");
} // end for j
Class type = value.getType();

// TextFileFormatted is the interface for lphy extension developers
// to define the type that can be written to a file
if (TextFileFormatted.class.isAssignableFrom(type)) {

TextFileFormatted fileFormatted = (TextFileFormatted) value.value();

String fileExtension = fileFormatted.getFileType();
String canonicalId = value.getCanonicalId();

String fileName = FileConfig.getOutFileName(canonicalId, index,
fileConfig.getNumReplicates(), fileConfig.getFilePrefix(), fileExtension);
File outputFile = OutputSystem.getOutputFile(fileName);

List<String> lines = fileFormatted.getTextForFile();
try {
Files.write(outputFile.toPath(), lines, StandardCharsets.UTF_8);
} catch (IOException e) {
LoggerUtils.log.severe("Cannot write " + canonicalId + " to file : " +
outputFile.getAbsolutePath() + " !");
}

} else { // default, ValueFormatter not accessible to lphy extension developer

List<ValueFormatter> formatters = valueFormatResolver.getFormatter(value);

// if it is array, then one ValueFormatter for one element
for (int j = 0; j < formatters.size(); j++) {
ValueFormatter formatter = formatters.get(j);

if (formatter == null) {
LoggerUtils.log.warning("Cannot find formatter for " + value.getId() +
", type is " + value.getType());

} else if (formatter.getMode() == ValueFormatter.Mode.VALUE_PER_FILE) {
// e.g. Alignment
ValueFormatHandler.ValuePerFile.createFile(index, formatter,
fileConfig.getFilePrefix(), fileConfig.getNumReplicates());

ValueFormatHandler.ValuePerFile
.exportValuePerFile(index, value, formatter);

} else if (formatter.getMode() == ValueFormatter.Mode.VALUE_PER_LINE) {
// process meta data given 1st value
if (index == 0)
ValueFormatHandler.ValuePerLine.processHeaderFooter(formatter,
metadataById, fileConfig.getFilePrefix());

// e.g. Trees
ValueFormatHandler.ValuePerLine.populateValues(index, value, formatter, linesById);

} else if (formatter.getMode() == ValueFormatter.Mode.VALUE_PER_CELL) {
// add col names and parameters values
ValueFormatHandler.ValuePerCell.addColumnNamesAndLines(index, firstColValuePerCell,
value, formatter, valuesByRepColNamesBuilder, valuesByRepBuilder);
firstColValuePerCell = false;

} else
throw new RuntimeException("Unrecognised formatter mode : " + formatter.getMode() + " !");
} // end for j

} // end if else
} // end for i
// ValuePerCell each line finish here
valuesByRepBuilder.append("\n");
Expand Down
2 changes: 2 additions & 0 deletions lphy/src/main/java/lphy/core/logger/ValueFormatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import lphy.core.model.Value;

/**
* Note: this cannot be extended by lphy extension developers,
* please use {@link TextFileFormatted}.
* The formatter to parse the {@link Value#value()} into String.
* It aims to process single element only.
* The array like data structure needs to decompose into elements.
Expand Down

0 comments on commit 1adcf57

Please sign in to comment.