302 lines
14 KiB
Java
302 lines
14 KiB
Java
import java.util.List;
|
|
import java.util.Scanner;
|
|
import java.util.InputMismatchException;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
//
|
|
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 an 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 CDR3 alpha/beta T cell matching");
|
|
System.out.println("4) Simulate CDR3/CDR1 T cell matching");
|
|
System.out.println("5) Acknowledgements");
|
|
System.out.println("0) Exit");
|
|
try {
|
|
input = sc.nextInt();
|
|
switch(input){
|
|
case 1 -> makeCells();
|
|
case 2 -> makePlate();
|
|
case 3 -> matchCells();
|
|
case 4 -> matchCellsExpanded();
|
|
case 5 -> acknowledge();
|
|
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;
|
|
Integer cdr1Freq = 1;
|
|
try {
|
|
System.out.println("\nSimulated T-Cells consist of integer values representing:\n" +
|
|
"* a pair of alpha and beta CDR3 peptides (unique within simulated population)\n" +
|
|
"* a pair of alpha and beta CDR1 peptides (not necessarily unique).");
|
|
System.out.println("\nThe cells will be written to a file.");
|
|
System.out.print("Please enter a file name: ");
|
|
filename = sc.next();
|
|
System.out.println("CDR3 sequences are more diverse than CDR1 sequences.");
|
|
System.out.println("Please enter the factor by which distinct CDR3s outnumber CDR1s: ");
|
|
cdr1Freq = sc.nextInt();
|
|
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, cdr1Freq);
|
|
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.getFilename(), 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.getFilename(), 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() - 1;
|
|
}
|
|
List<Integer[]> cells = cellReader.getCells();
|
|
MatchingResult results = Simulator.matchCDR3s(cells, plate, lowThreshold, highThreshold);
|
|
//result writer
|
|
MatchingFileWriter writer = new MatchingFileWriter(filename, results);
|
|
writer.writeResultsToFile();
|
|
}
|
|
}
|
|
|
|
public static void matchCellsExpanded(){
|
|
/*
|
|
The idea here is that we'll get the CDR3 alpha/beta matches first. Then we'll try to match CDR3s to CDR1s by
|
|
looking at the top two matches for each CDR3. If CDR3s in the same cell simply swap CDR1s, we assume a correct
|
|
match
|
|
*/
|
|
String filename = null;
|
|
String preliminaryResultsFilename = null;
|
|
String cellFile = null;
|
|
String plateFile = null;
|
|
Integer lowThresholdCDR3 = 0;
|
|
Integer highThresholdCDR3 = Integer.MAX_VALUE;
|
|
Integer lowThresholdCDR1 = 0;
|
|
Integer highThresholdCDR1 = Integer.MAX_VALUE;
|
|
boolean outputCDR3Matches = false;
|
|
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 CDR3 alpha/beta overlap wells to attempt matching?");
|
|
lowThresholdCDR3 = sc.nextInt();
|
|
if(lowThresholdCDR3 < 1){
|
|
throw new InputMismatchException("Minimum value for low threshold is 1");
|
|
}
|
|
System.out.println("What is the maximum number of CDR3 alpha/beta overlap wells to attempt matching?");
|
|
highThresholdCDR3 = sc.nextInt();
|
|
System.out.println("What is the minimum number of CDR3/CDR1 overlap wells to attempt matching?");
|
|
lowThresholdCDR1 = sc.nextInt();
|
|
if(lowThresholdCDR1 < 1){
|
|
throw new InputMismatchException("Minimum value for low threshold is 1");
|
|
}
|
|
System.out.println("What is the maximum number of CDR3/CDR1 overlap wells to attempt matching?");
|
|
highThresholdCDR1 = sc.nextInt();
|
|
System.out.println("Matching CDR3s to CDR1s requires first matching CDR3 alpha/betas.");
|
|
System.out.println("Output a file for CDR3 alpha/beta match results as well?");
|
|
System.out.print("Please enter y/n: ");
|
|
String ans = sc.next();
|
|
Pattern pattern = Pattern.compile("(?:yes|y)", Pattern.CASE_INSENSITIVE);
|
|
Matcher matcher = pattern.matcher(ans);
|
|
if(matcher.matches()){
|
|
outputCDR3Matches = true;
|
|
System.out.println("Please enter filename for CDR3 alpha/beta match results");
|
|
preliminaryResultsFilename = sc.next();
|
|
System.out.println("CDR3 alpha/beta matches will be output to file");
|
|
}
|
|
else{
|
|
System.out.println("CDR3 alpha/beta matches will not be output to file");
|
|
}
|
|
} catch (InputMismatchException ex) {
|
|
System.out.println(ex);
|
|
sc.next();
|
|
}
|
|
CellFileReader cellReader = new CellFileReader(cellFile);
|
|
PlateFileReader plateReader = new PlateFileReader(plateFile);
|
|
Plate plate = new Plate(plateReader.getFilename(), 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(highThresholdCDR3 >= plate.getSize()){
|
|
highThresholdCDR3 = plate.getSize() - 1;
|
|
}
|
|
if(highThresholdCDR1 >= plate.getSize()){
|
|
highThresholdCDR1 = plate.getSize() - 1;
|
|
}
|
|
List<Integer[]> cells = cellReader.getCells();
|
|
MatchingResult preliminaryResults = Simulator.matchCDR3s(cells, plate, lowThresholdCDR3, highThresholdCDR3);
|
|
MatchingResult[] results = Simulator.matchCDR1s(cells, plate, lowThresholdCDR1,
|
|
highThresholdCDR1, preliminaryResults);
|
|
MatchingFileWriter writer = new MatchingFileWriter(filename + "_FirstPass", results[0]);
|
|
writer.writeResultsToFile();
|
|
writer = new MatchingFileWriter(filename + "_SecondPass", results[1]);
|
|
writer.writeResultsToFile();
|
|
if(outputCDR3Matches){
|
|
writer = new MatchingFileWriter(preliminaryResultsFilename, preliminaryResults);
|
|
writer.writeResultsToFile();
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void acknowledge(){
|
|
System.out.println("Simulation based on:");
|
|
System.out.println("Howie, B., Sherwood, A. M., et. al.");
|
|
System.out.println("High-throughput pairing of T cell receptor alpha and beta sequences.");
|
|
System.out.println("Sci. Transl. Med. 7, 301ra131 (2015)");
|
|
System.out.println("");
|
|
System.out.println("Simulation by Eugene Fischer, 2021");
|
|
}
|
|
}
|