diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/artifacts/TCellSim_jar.xml b/.idea/artifacts/TCellSim_jar.xml
new file mode 100644
index 0000000..68721a0
--- /dev/null
+++ b/.idea/artifacts/TCellSim_jar.xml
@@ -0,0 +1,15 @@
+
+
+ $PROJECT_DIR$/out/artifacts/TCellSim_jar
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/artifacts/TCellSim_jar2.xml b/.idea/artifacts/TCellSim_jar2.xml
new file mode 100644
index 0000000..0c29e4c
--- /dev/null
+++ b/.idea/artifacts/TCellSim_jar2.xml
@@ -0,0 +1,15 @@
+
+
+ $PROJECT_DIR$/out/artifacts/TCellSim_jar2
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..c3728c7
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..712ab9d
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/apache_commons_csv.xml b/.idea/libraries/apache_commons_csv.xml
new file mode 100644
index 0000000..91cd631
--- /dev/null
+++ b/.idea/libraries/apache_commons_csv.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/jgrapht_core.xml b/.idea/libraries/jgrapht_core.xml
new file mode 100644
index 0000000..96adbc8
--- /dev/null
+++ b/.idea/libraries/jgrapht_core.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..82dbec8
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..797acea
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml
new file mode 100644
index 0000000..e96534f
--- /dev/null
+++ b/.idea/uiDesigner.xml
@@ -0,0 +1,124 @@
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..b4eb9b7
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,36 @@
+
+
+ 4.0.0
+
+ org.example
+ TCellSim
+ 1.0-SNAPSHOT
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 14
+ 14
+
+
+
+
+
+
+ org.jetbrains
+ annotations
+ RELEASE
+ compile
+
+
+
+
+ 11
+ 11
+
+
+
\ No newline at end of file
diff --git a/src/main/java/CellFileReader.java b/src/main/java/CellFileReader.java
new file mode 100644
index 0000000..5a3697a
--- /dev/null
+++ b/src/main/java/CellFileReader.java
@@ -0,0 +1,50 @@
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CellFileReader {
+
+ private List distinctCells = new ArrayList<>();
+
+ public CellFileReader(String filename) {
+
+ if(!filename.matches(".*\\.csv")){
+ filename = filename + ".csv";
+ }
+
+ CSVFormat cellFileFormat = CSVFormat.Builder.create()
+ .setHeader("Alpha", "Beta")
+ .setSkipHeaderRecord(true)
+ .build();
+
+ try(//don't need to close reader bc of try-with-resources auto-closing
+ BufferedReader reader = Files.newBufferedReader(Path.of(filename));
+ CSVParser parser = new CSVParser(reader, cellFileFormat);
+ ){
+ for(CSVRecord record: parser.getRecords()) {
+ Integer[] cell = new Integer[2];
+ cell[0] = Integer.valueOf(record.get("Alpha"));
+ cell[1] = Integer.valueOf(record.get("Beta"));
+ distinctCells.add(cell);
+ }
+ } catch(IOException ex){
+ System.out.println("cell file " + filename + " not found.");
+ System.err.println(ex);
+ }
+ }
+
+ public List getCells(){
+ return distinctCells;
+ }
+
+ public Integer getCellCount() {
+ return distinctCells.size();
+ }
+}
diff --git a/src/main/java/CellFileWriter.java b/src/main/java/CellFileWriter.java
new file mode 100644
index 0000000..dddc2d4
--- /dev/null
+++ b/src/main/java/CellFileWriter.java
@@ -0,0 +1,38 @@
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.List;
+
+public class CellFileWriter {
+
+ private String[] headers = {"Alpha", "Beta"};
+ List cells;
+ String filename;
+
+ public CellFileWriter(String filename, CellSample cells) {
+ if(!filename.matches(".*\\.csv")){
+ filename = filename + ".csv";
+ }
+ this.filename = filename;
+ this.cells = cells.getCells();
+ }
+
+ public void writeCellsToFile() {
+ CSVFormat cellFileFormat = CSVFormat.Builder.create()
+ .setHeader(headers)
+ .build();
+ try(BufferedWriter writer = Files.newBufferedWriter(Path.of(filename), StandardOpenOption.CREATE_NEW);
+ CSVPrinter printer = new CSVPrinter(writer, cellFileFormat);
+ ){
+ printer.printRecords(cells);
+ } catch(IOException ex){
+ System.out.println("Could not make new file named "+filename);
+ System.err.println(ex);
+ }
+ }
+}
diff --git a/src/main/java/CellSample.java b/src/main/java/CellSample.java
new file mode 100644
index 0000000..411936d
--- /dev/null
+++ b/src/main/java/CellSample.java
@@ -0,0 +1,19 @@
+import java.util.List;
+
+public class CellSample {
+
+ private List cells;
+
+ public CellSample(List cells){
+ this.cells = cells;
+ }
+
+ public List getCells(){
+ return cells;
+ }
+
+ public Integer population(){
+ return cells.size();
+ }
+
+}
diff --git a/src/main/java/MatchingFileWriter.java b/src/main/java/MatchingFileWriter.java
new file mode 100644
index 0000000..d1de122
--- /dev/null
+++ b/src/main/java/MatchingFileWriter.java
@@ -0,0 +1,52 @@
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.List;
+
+
+public class MatchingFileWriter {
+
+ private String filename;
+ private List comments;
+ private List headers;
+ private List> results;
+
+ public MatchingFileWriter(String filename, List comments, List headers, List> results){
+ if(!filename.matches(".*\\.csv")){
+ filename = filename + ".csv";
+ }
+ this.filename = filename;
+ this.comments = comments;
+ this.headers = headers;
+ this.results = results;
+ }
+
+ public void writeResultsToFile(){
+ String[] headerStrings = new String[headers.size()];
+ for(int i = 0; i < headers.size(); i++){
+ headerStrings[i] = headers.get(i);
+ }
+ CSVFormat resultsFileFormat = CSVFormat.Builder.create()
+ .setCommentMarker('#')
+ //.setHeader(headerStrings)
+ .build();
+ try(BufferedWriter writer = Files.newBufferedWriter(Path.of(filename), StandardOpenOption.CREATE_NEW);
+ CSVPrinter printer = new CSVPrinter(writer, resultsFileFormat);
+ ){
+ for(String comment: comments){
+ printer.printComment(comment);
+ }
+ results.add(0, headers);
+ printer.printRecords(results);
+
+ } catch(IOException ex){
+ System.out.println("Could not make new file named "+filename);
+ System.err.println(ex);
+ }
+ }
+}
diff --git a/src/main/java/Plate.java b/src/main/java/Plate.java
index c3f7a91..27877c7 100644
--- a/src/main/java/Plate.java
+++ b/src/main/java/Plate.java
@@ -8,14 +8,23 @@ public class Plate {
private Random rand = new Random();
private int size;
private double error;
+ private Integer[] concentrations;
+ private double stdDev;
- public Plate (int size, double error) {
+ public Plate (int size, double error, Integer[] concentrations, double stdDev) {
this.size = size;
this.error = error;
+ this.concentrations = concentrations;
+ this.stdDev = stdDev;
wells = new ArrayList<>();
}
- public void fillWells(List cells, int[] concentrations, double stdDev) {
+ public Plate(List> wells){
+ this.wells = wells;
+ this.size = wells.size();
+ }
+
+ public void fillWells(List cells) {
int numSections = concentrations.length;
int section = 0;
double m;
@@ -26,8 +35,8 @@ public class Plate {
List well = new ArrayList<>();
for (int j = 0; j < concentrations[section]; j++) {
do {
- m = Math.abs(rand.nextGaussian()) * stdDev;
- } while (m >= cells.size());
+ m = (rand.nextGaussian() * stdDev) + (cells.size() / 2);
+ } while (m >= cells.size() || m < 0);
n = (int) Math.floor(m);
Integer[] cellToAdd = cells.get(n).clone();
drop = Math.abs(rand.nextDouble()) < error;
@@ -46,6 +55,31 @@ public class Plate {
}
}
+ public void writePlateToFile(String filename) {
+
+
+ }
+
+ public Integer[] getConcentrations(){
+ return concentrations;
+ }
+
+ public int getSize(){
+ return size;
+ }
+
+ public double getStdDev() {
+ return stdDev;
+ }
+
+ public double getError() {
+ return error;
+ }
+
+ public List> getWells() {
+ return wells;
+ }
+
public Map assayWellsAlpha() {
return this.assayWellsAlpha(0, size);
}
diff --git a/src/main/java/PlateFileReader.java b/src/main/java/PlateFileReader.java
new file mode 100644
index 0000000..cbafcf2
--- /dev/null
+++ b/src/main/java/PlateFileReader.java
@@ -0,0 +1,61 @@
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.sql.Array;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+public class PlateFileReader {
+
+ private List> wells = new ArrayList<>();
+
+ public PlateFileReader(String filename){
+
+ if(!filename.matches(".*\\.csv")){
+ filename = filename + ".csv";
+ }
+
+ CSVFormat plateFileFormat = CSVFormat.Builder.create()
+ .setCommentMarker('#')
+ .build();
+
+ try(//don't need to close reader bc of try-with-resources auto-closing
+ BufferedReader reader = Files.newBufferedReader(Path.of(filename));
+ CSVParser parser = new CSVParser(reader, plateFileFormat);
+ ){
+ for(CSVRecord record: parser.getRecords()) {
+ List well = new ArrayList<>();
+ for(String s: record) {
+ if(!"".equals(s)) {
+ String[] intString = s.replaceAll("\\[", "")
+ .replaceAll("]", "")
+ .replaceAll(" ", "")
+ .split(",");
+ //System.out.println(intString);
+ Integer[] arr = new Integer[intString.length];
+ for (int i = 0; i < intString.length; i++) {
+ arr[i] = Integer.valueOf(intString[i]);
+ }
+ well.add(arr);
+ }
+ }
+ wells.add(well);
+ }
+ } catch(IOException ex){
+ System.out.println("plate file " + filename + " not found.");
+ System.err.println(ex);
+ }
+
+ }
+
+ public List> getWells() {
+ return wells;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/PlateFileWriter.java b/src/main/java/PlateFileWriter.java
new file mode 100644
index 0000000..ad68fd4
--- /dev/null
+++ b/src/main/java/PlateFileWriter.java
@@ -0,0 +1,93 @@
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVPrinter;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.*;
+import java.util.regex.Pattern;
+
+public class PlateFileWriter {
+ private int size;
+ private List> wells;
+ private double stdDev;
+ private Double error;
+ private String filename;
+ private String[] headers;
+ private List concentrations;
+
+ public PlateFileWriter(String filename, Plate plate) {
+ if(!filename.matches(".*\\.csv")){
+ filename = filename + ".csv";
+ }
+ this.filename = filename;
+ this.size = plate.getSize();
+ this.stdDev = plate.getStdDev();
+ this.error = plate.getError();
+ this.wells = plate.getWells();
+ this.concentrations = Arrays.asList(plate.getConcentrations());
+ concentrations.sort(Comparator.reverseOrder());
+ }
+
+ public void writePlateFile(){
+ //works as is, but too many columns in csv, need to make them all rows.
+
+ //will now redo it so that every column is a well, with well names as headers
+ //need to give plate error, sample pop size, stdDev, num sections, concentration per section as comments
+ Comparator> listLengthDescending = Comparator.comparingInt(List::size);
+ wells.sort(listLengthDescending.reversed());
+ int maxLength = wells.get(0).size();
+ List> wellsAsStrings = new ArrayList<>();
+ for (List w: wells){
+ List tmp = new ArrayList<>();
+ for(Integer[] c: w) {
+ tmp.add(Arrays.toString(c));
+ }
+ wellsAsStrings.add(tmp);
+ }
+ for(List w: wellsAsStrings){
+ while(w.size() < maxLength){
+ w.add("");
+ }
+ }
+
+ //this took forever
+ List> rows = new ArrayList<>();
+ List tmp = new ArrayList<>();
+ for(int i = 0; i < wellsAsStrings.size(); i++){//List w: wells){
+ tmp.add("well " + (i+1));
+ }
+ rows.add(tmp);
+ for(int row = 0; row < maxLength; row++){
+ tmp = new ArrayList<>();
+ for(List c: wellsAsStrings){
+ tmp.add(c.get(row));
+ }
+ rows.add(tmp);
+ }
+ StringBuilder concen = new StringBuilder();
+ for(Integer i: concentrations){
+ concen.append(i.toString());
+ concen.append(" ");
+ }
+ String concenString = concen.toString();
+
+ CSVFormat plateFileFormat = CSVFormat.Builder.create().setCommentMarker('#').build();
+
+ try(BufferedWriter writer = Files.newBufferedWriter(Path.of(filename), StandardOpenOption.CREATE_NEW);
+ CSVPrinter printer = new CSVPrinter(writer, plateFileFormat);
+ ){
+ printer.printComment("Each row represents one well on the plate.");
+ printer.printComment("Plate size: " + size);
+ printer.printComment("Error rate: " + error);
+ printer.printComment("Concentrations: " + concenString);
+ printer.printComment("Std. dev.: " + stdDev);
+ printer.printRecords(wellsAsStrings);
+ } catch(IOException ex){
+ System.out.println("Could not make new file named "+filename);
+ System.err.println(ex);
+ }
+ }
+}
diff --git a/src/main/java/Simulation.java b/src/main/java/Simulator.java
similarity index 62%
rename from src/main/java/Simulation.java
rename to src/main/java/Simulator.java
index 6aeff78..bb2c5c8 100644
--- a/src/main/java/Simulation.java
+++ b/src/main/java/Simulator.java
@@ -13,21 +13,196 @@ import java.time.Instant;
import java.util.*;
import java.util.stream.IntStream;
-public class Simulation {
- private static Integer numDistinctCells = 15_000_000;
- private static double stdDeviation = 1000; //square root of numDistCells would approximate poisson dist, supposedly
+public class Simulator {
+ private static Integer numDistinctCells = 2_000_000;
+ private static double stdDeviation = 200; //square root of numDistCells would approximate poisson dist
private static int numWells = 96;
private static int numConcentrations = 1;
private static double errorRate = 0.1;
- private static int[] concentrations = {500};
+ private static Integer[] concentrations = {500};
private static int lowThreshold = 2; //min number of shared wells to attempt pairing
private static int highThreshold = numWells - 3; //max number of shared wells to attempt pairing
private static boolean use2DArrayForGraph = true; //Doing this is much faster for larger graphs
private static boolean useJGraphTGraphMatrixGenerator = true; //fastest option
- public static void main(String[] args) {
- Instant start = Instant.now();
+ public static CellSample generateCellSample(Integer numDistinctCells) {
+ List numbers = new ArrayList<>();
+ IntStream.range(1, (2 * numDistinctCells) + 1).forEach(i -> numbers.add(i));
+ Collections.shuffle(numbers);
+
+ //Each cell represented by two numbers from the random permutation
+ //These represent unique alpha and beta peptides
+ List distinctCells = new ArrayList<>();
+ for(int i = 0; i < numbers.size() - 1; i = i + 2) {
+ Integer tmp1 = numbers.get(i);
+ Integer tmp2 = numbers.get(i+1);
+ Integer[] tmp = {tmp1, tmp2};
+ distinctCells.add(tmp);
+ }
+ return new CellSample(distinctCells);
+ }
+
+ public static void matchCells(String filename, List distinctCells, Plate samplePlate, Integer lowThreshold, Integer highThreshold){
+ System.out.println("Cells: " + distinctCells.size());
+
+ System.out.println("Making cell maps");
+ //HashMap keyed to Alphas, values Betas
+ Map distCellsMapAlphaKey = new HashMap<>();
+ for (Integer[] cell : distinctCells) {
+ distCellsMapAlphaKey.put(cell[0], cell[1]);
+ }
+ //HashMap keyed to Betas, values Alphas
+ Map distCellsMapBetaKey = new HashMap<>();
+ for (Integer[] cell : distinctCells) {
+ distCellsMapBetaKey.put(cell[1], cell[0]);
+ }
+ System.out.println("Cell maps made");
+
+ System.out.println("Making well maps");
+ Map allAlphas = samplePlate.assayWellsAlpha();
+ Map allBetas = samplePlate.assayWellsBeta();
+ int alphaCount = allAlphas.size();
+ System.out.println("all alphas count: " + alphaCount);
+ int betaCount = allBetas.size();
+ System.out.println("all betas count: " + betaCount);
+
+ System.out.println("Well maps made");
+
+ System.out.println("Making vertex maps");
+ //Using Integers instead of Strings to label vertices so I can do clever stuff with indices if I need to
+ // when I refactor to use a 2d array to make the graph
+ //For the autogenerator, all vertices must have distinct numbers associated with them
+ Integer vertexStartValue = 0;
+ //keys are sequential integer vertices, values are alphas
+ Map plateVtoAMap = getVertexToPeptideMap(allAlphas, vertexStartValue);
+ //New start value for vertex to beta map should be one more than final vertex value in alpha map
+ vertexStartValue += plateVtoAMap.size();
+ //keys are sequential integers vertices, values are betas
+ Map plateVtoBMap = getVertexToPeptideMap(allBetas, vertexStartValue);
+ //keys are alphas, values are sequential integer vertices from previous map
+ Map plateAtoVMap = invertVertexMap(plateVtoAMap);
+ System.out.println(plateAtoVMap.size());
+ //keys are betas, values are sequential integer vertices from previous map
+ Map plateBtoVMap = invertVertexMap(plateVtoBMap);
+ System.out.println(plateAtoVMap.size());
+ System.out.println("Vertex maps made");
+
+ System.out.println("Creating Graph");
+ //Count how many wells each alpha appears in
+ Map alphaWellCounts = new HashMap<>();
+ //count how many wells each beta appears in
+ Map betaWellCounts = new HashMap<>();
+ //add edges, where weights are number of wells the peptides share in common.
+ //If this is too slow, can make a 2d array and use the SimpleWeightedGraphMatrixGenerator class
+ Map wellNAlphas = null;
+ Map wellNBetas = null;
+ SimpleWeightedGraph graph =
+ new SimpleWeightedGraph<>(DefaultWeightedEdge.class);
+ double[][] weights = new double[plateVtoAMap.size()][plateVtoBMap.size()];
+ for (int n = 0; n < numWells; n++) {
+ wellNAlphas = samplePlate.assayWellsAlpha(n);
+ for (Integer a : wellNAlphas.keySet()) {
+ alphaWellCounts.merge(a, 1, (oldValue, newValue) -> oldValue + newValue);
+ }
+ wellNBetas = samplePlate.assayWellsBeta(n);
+ for (Integer b : wellNBetas.keySet()) {
+ betaWellCounts.merge(b, 1, (oldValue, newValue) -> oldValue + newValue);
+ }
+ for (Integer i : wellNAlphas.keySet()) {
+ for (Integer j : wellNBetas.keySet()) {
+ weights[plateAtoVMap.get(i)][plateBtoVMap.get(j) - vertexStartValue] += 1.0;
+ }
+ }
+ }
+ SimpleWeightedBipartiteGraphMatrixGenerator graphGenerator = new SimpleWeightedBipartiteGraphMatrixGenerator();
+ List alphaVertices = new ArrayList<>();
+ alphaVertices.addAll(plateVtoAMap.keySet()); //This will work because LinkedHashMap preserves order of entry
+ graphGenerator.first(alphaVertices);
+ List betaVertices = new ArrayList<>();
+ betaVertices.addAll(plateVtoBMap.keySet());
+ graphGenerator.second(betaVertices); //This will work because LinkedHashMap preserves order of entry
+ graphGenerator.weights(weights);
+ graphGenerator.generateGraph(graph);
+ System.out.println("Graph created");
+
+ System.out.println("Finding maximum weighted matching");
+ MaximumWeightBipartiteMatching maxWeightMatching =
+ new MaximumWeightBipartiteMatching(graph, plateVtoAMap.keySet(), plateVtoBMap.keySet());
+ MatchingAlgorithm.Matching graphMatching = maxWeightMatching.getMatching();
+ System.out.println("Matching completed");
+
+ //Header for CSV file
+ List header = new ArrayList<>();
+ header.add("Alpha");
+ header.add("Alpha well count");
+ header.add("Beta");
+ header.add("Beta well count");
+ header.add("Overlap well count");
+ header.add("Matched correctly?");
+ header.add("P-value");
+
+
+ //Results for csv file
+ List> allResults = new ArrayList<>();
+ int size = samplePlate.getSize();
+ Iterator weightIter = graphMatching.iterator();
+ DefaultWeightedEdge e = null;
+ int trueCount = 0;
+ int falseCount = 0;
+ boolean check = false;
+ while(weightIter.hasNext()) {
+ e = weightIter.next();
+ if(graph.getEdgeWeight(e) < lowThreshold || graph.getEdgeWeight(e) > highThreshold) {
+ continue;
+ }
+ Integer source = graph.getEdgeSource(e);
+ Integer target = graph.getEdgeTarget(e);
+ check = plateVtoBMap.get(target).equals(distCellsMapAlphaKey.get(plateVtoAMap.get(source)));
+ if(check) {
+ trueCount++;
+ }
+ else {
+ falseCount++;
+ }
+ List result = new ArrayList<>();
+ result.add(plateVtoAMap.get(source).toString());
+ //alpha well count
+ result.add(alphaWellCounts.get(plateVtoAMap.get(source)).toString());
+ result.add(plateVtoBMap.get(target).toString());
+ //beta well count
+ result.add(betaWellCounts.get(plateVtoBMap.get(target)).toString());
+ //overlap count
+ result.add(Double.toString(graph.getEdgeWeight(e)));
+ result.add(Boolean.toString(check));
+ result.add(Double.toString(Equations.pValue(size, alphaWellCounts.get(plateVtoAMap.get(source)),
+ betaWellCounts.get(plateVtoBMap.get(target)), graph.getEdgeWeight(e))));
+ allResults.add(result);
+ }
+
+ //Metadate comments for CSV file
+ int min = alphaCount > betaCount ? betaCount : alphaCount;
+ double attemptRate = (double) (trueCount + falseCount) / min;
+ double pairingErrorRate = (double) falseCount / (trueCount + falseCount);
+
+ List comments = new ArrayList<>();
+ comments.add("Total alphas found: " + alphaCount);
+ comments.add("Total betas found: " + betaCount);
+ comments.add("Pairing attempt rate: " + attemptRate);
+ comments.add("Correct pairings: " + trueCount);
+ comments.add("Incorrect pairings: " + falseCount);
+ comments.add("Pairing error rate: " + pairingErrorRate);
+
+ //result writer
+ MatchingFileWriter writer = new MatchingFileWriter(filename, comments, header, allResults);
+ writer.writeResultsToFile();
+ }
+
+
+
+
+ public static void Simulate() {
+ Instant start = Instant.now();
//Four things to try to improve this
//1. Run it on hardware with more memory
//2. implement p-values and just check exhaustively for strictly-bounded weights
@@ -76,8 +251,8 @@ public class Simulation {
distCellsMapBetaKey.put(cell[1], cell[0]);
}
- Plate samplePlate = new Plate(numWells, errorRate);
- samplePlate.fillWells(distinctCells, concentrations, stdDeviation);
+ Plate samplePlate = new Plate(numWells, errorRate, concentrations, stdDeviation);
+ samplePlate.fillWells(distinctCells);
//OUTPUT
System.out.println("Wells filled");
diff --git a/src/main/java/UserInterface.java b/src/main/java/UserInterface.java
new file mode 100644
index 0000000..7feebc8
--- /dev/null
+++ b/src/main/java/UserInterface.java
@@ -0,0 +1,192 @@
+import java.util.List;
+import java.util.Scanner;
+import java.util.ArrayList;
+import java.util.InputMismatchException;
+
+//
+public class UserInterface {
+
+ final static Scanner sc = new Scanner(System.in);
+ static int input;
+ static boolean quit = false;
+
+ public static void main(String args[]) {
+ while(!quit) {
+ System.out.println("\nALPHA/BETA T-CELL RECEPTOR MATCHING SIMULATOR");
+ System.out.println("Please select and option:");
+ System.out.println("1) Generate a population of distinct cells");
+ System.out.println("2) Generate a sample plate of T-cells");
+ System.out.println("3) Simulate T-Cell matching");
+ System.out.println("4) Acknowledgements");
+ System.out.println("0) Exit");
+ try {
+ input = sc.nextInt();
+ switch(input){
+ case 1 -> makeCells();
+ case 2 -> makePlate();
+ case 3 -> matchCells();
+ //case 4 -> //method call goes here
+ case 0 -> quit = true;
+ default -> throw new InputMismatchException("Invalid input.");
+ }
+ }catch(InputMismatchException ex){
+ System.out.println(ex);
+ sc.next();
+ }
+ }
+ sc.close();
+ }
+
+ private static void makeCells() {
+ String filename = null;
+ Integer numCells = 0;
+ try {
+ System.out.println("\nSimulated T-Cells consist of matched pairs of alpha and beta peptides, " +
+ "represented by unique integer values.");
+ System.out.println("(Note: peptide values are unique within a simulated population, " +
+ "but repeated between simulated populations.)");
+ System.out.println("\nThe cells will be written to a file.");
+ System.out.print("Please enter a file name: ");
+ filename = sc.next();
+ System.out.print("Please enter the number of T-cells to generate: ");
+ numCells = sc.nextInt();
+ if(numCells <= 0){
+ throw new InputMismatchException("Number of cells must be a positive integer.");
+ }
+ } catch (InputMismatchException ex) {
+ System.out.println(ex);
+ sc.next();
+ }
+ CellSample sample = Simulator.generateCellSample(numCells);
+ CellFileWriter writer = new CellFileWriter(filename, sample);
+ writer.writeCellsToFile();
+ }
+
+ //method to output a CSV of
+ private static void makePlate() {
+ String cellFile = null;
+ String filename = null;
+ Double stdDev = 0.0;
+ Integer numWells = 0;
+ Integer numSections = 0;
+ Integer[] concentrations = {1};
+ Double dropOutRate = 0.0;
+ boolean poisson = false;
+ try {
+ System.out.println("\nMaking a sample plate requires a population of distinct cells");
+ System.out.println("Please enter name of an existing cell sample file: ");
+ cellFile = sc.next();
+ System.out.println("\nThe sample plate will be written to file");
+ System.out.print("Please enter a name for the output file: ");
+ filename = sc.next();
+ System.out.println("Select T-cell frequency distribution function");
+ System.out.println("1) Poisson");
+ System.out.println("2) Gaussian");
+ System.out.println("(Note: wider distributions are more memory intensive to match)");
+ System.out.print("Enter selection value: ");
+ input = sc.nextInt();
+ switch(input) {
+ case 1:
+ poisson = true;
+ break;
+ case 2:
+ System.out.println("How many distinct T-cells within one standard deviation of peak frequency?");
+ System.out.println("(Note: wider distributions are more memory intensive to match)");
+ stdDev = sc.nextDouble();
+ if(stdDev <= 0.0){
+ throw new InputMismatchException("Value must be positive.");
+ }
+ break;
+ default:
+ System.out.println("Invalid input. Defaulting to Poisson.");
+ poisson = true;
+ }
+ System.out.print("Number of wells on plate: ");
+ numWells = sc.nextInt();
+ if(numWells < 1){
+ throw new InputMismatchException("No wells on plate");
+ }
+ System.out.println("The plate can be evenly sectioned to allow multiple concentrations of T-cells/well");
+ System.out.println("How many sections would you like to make (minimum 1)?");
+ numSections = sc.nextInt();
+ if(numSections < 1) {
+ throw new InputMismatchException("Too few sections.");
+ }
+ else if (numSections > numWells) {
+ throw new InputMismatchException("Cannot have more sections than wells.");
+ }
+ int i = 1;
+ concentrations = new Integer[numSections];
+ while(numSections > 0) {
+ System.out.print("Enter number of T-cells per well in section " + i +": ");
+ concentrations[i - 1] = sc.nextInt();
+ i++;
+ numSections--;
+ }
+ System.out.println("Errors in amplification can induce a well dropout rate for peptides");
+ System.out.print("Enter well dropout rate (0.0 to 1.0): ");
+ dropOutRate = sc.nextDouble();
+ if(dropOutRate < 0.0 || dropOutRate > 1.0) {
+ throw new InputMismatchException("The well dropout rate must be in the range [0.0, 1.0]");
+ }
+ }catch(InputMismatchException ex){
+ System.out.println(ex);
+ sc.next();
+ }
+ CellFileReader cellReader = new CellFileReader(cellFile);
+ if(poisson) {
+ stdDev = Math.sqrt(cellReader.getCellCount()); //gaussian with square root of elements approximates poisson
+ }
+ Plate samplePlate = new Plate(numWells, dropOutRate, concentrations, stdDev);
+ samplePlate.fillWells(cellReader.getCells());
+ PlateFileWriter writer = new PlateFileWriter(filename, samplePlate);
+ writer.writePlateFile();
+ }
+
+ private static void matchCells() {
+ String filename = null;
+ String cellFile = null;
+ String plateFile = null;
+ Integer lowThreshold = 0;
+ Integer highThreshold = Integer.MAX_VALUE;
+ try {
+ System.out.println("\nSimulated experiment requires a cell sample file and a sample plate file.");
+ System.out.print("Please enter name of an existing cell sample file: ");
+ cellFile = sc.next();
+ System.out.print("Please enter name of an existing sample plate file: ");
+ plateFile = sc.next();
+ System.out.println("The matching results will be written to a file.");
+ System.out.print("Please enter a name for the output file: ");
+ filename = sc.next();
+ System.out.println("What is the minimum number of alpha/beta overlap wells to attempt matching?");
+ lowThreshold = sc.nextInt();
+ if(lowThreshold < 1){
+ throw new InputMismatchException("Minimum value for low threshold is 1");
+ }
+ System.out.println("What is the maximum number of alpha/beta overlap wells to attempt matching?");
+ highThreshold = sc.nextInt();
+ } catch (InputMismatchException ex) {
+ System.out.println(ex);
+ sc.next();
+ }
+ CellFileReader cellReader = new CellFileReader(cellFile);
+ PlateFileReader plateReader = new PlateFileReader(plateFile);
+ Plate plate = new Plate(plateReader.getWells());
+ if (cellReader.getCells().size() == 0){
+ System.out.println("No cell sample found.");
+ System.out.println("Returning to main menu.");
+ }
+ else if(plate.getWells().size() == 0){
+ System.out.println("No sample plate found.");
+ System.out.println("Returning to main menu.");
+
+ }
+ else{
+ if(highThreshold > plate.getSize()){
+ highThreshold = plate.getSize();
+ }
+ List cells = cellReader.getCells();
+ Simulator.matchCells(filename, cells, plate, lowThreshold, highThreshold);
+ }
+ }
+}