package org.cellocad.MIT.dnacompiler; /** * Created by Bryan Der on 3/26/14. */ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import lombok.Getter; import lombok.Setter; import org.apache.log4j.*; import org.cellocad.BU.netsynth.NetSynth; import org.cellocad.BU.netsynth.NetSynthSwitch; import org.cellocad.BU.netsynth.Utilities; import org.cellocad.MIT.dnacompiler.Gate.GateType; import org.cellocad.MIT.figures.*; import org.cellocad.MIT.tandem_promoter.InterpolateTandemPromoter; import org.cellocad.adaptors.eugeneadaptor.EugeneAdaptor; import org.cellocad.adaptors.sboladaptor.SBOLCircuitWriter; import org.cellocad.adaptors.ucfadaptor.UCFAdaptor; import org.cellocad.adaptors.ucfadaptor.UCFReader; import org.cellocad.adaptors.ucfadaptor.UCFValidator; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.map.JsonMappingException; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.node.ObjectNode; import org.json.JSONException; import org.json.simple.JSONObject; import org.json.simple.parser.ParseException; import java.io.File; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.*; //@Slf4j public class DNACompiler { public DNACompiler() { } public DNACompiler(String username) { _username = username; } /* * These enum values are used to report a job/result status to the front-end web application. * If the job does not succeed, it is helpful to know why. */ public enum ResultStatus{ success, wiring_diagram_invalid, not_enough_gates_in_library, no_assignments_found, roadblocking_inputs, ucf_invalid, arguments_invalid, breadth_first_not_allowed, abstract_only, } public enum CircuitType{ combinational, sequential } /** * * Cello main * * 1. Set runtime arguments/options. * 2. Get abstract circuit (wiring diagram). * 3. Load input, repressor, output, toxicity, histogram data. * 4. Assignment of repressors to gates. * 5. Generate plasmid DNA sequences. * 6. Generate figures. * */ public void run(String[] args) { //System.setProperty("logfile.name", "default.log"); //PropertyConfigurator.configure(_options.get_home() + "/src/main/resources/log4j.properties"); /** * read command-line arguments. Verilog file required, others are optional. */ // _options.setThreadDependentLoggername(threadDependentLoggername); _options.set_username(_username); _options.parse(args); /** * set paths to data files (Inputs, Outputs, NOR_Gates, AND_Gates, ToxicityTable) * set jobID prefix for output files */ setPaths(); Util.createDirectory(_options.get_output_directory()); String logfile = _options.get_output_directory() + _options.get_jobID() + "_dnacompiler_output.txt"; FileAppender appender = new FileAppender(); appender.setFile(logfile); appender.setLayout(new PatternLayout("%m%n")); appender.setName(threadDependentLoggername); appender.setThreshold(Level.DEBUG); appender.activateOptions(); // ConsoleAppender is set in log4j.properties ConsoleAppender console = new ConsoleAppender(); console.setLayout(new PatternLayout("%m%n")); console.setThreshold(Level.DEBUG); console.activateOptions(); logger = Logger.getLogger(threadDependentLoggername); logger.addAppender(appender); //logger.addAppender(console); /** * Instead of logger.info, use a logging system. * Need to set logfile.name before any logger is instantiated to avoid error messages. * Here we are using log4j. See /src/main/resources/log4j.properties for the configuration details. */ //the logger will write to the specified file // System.setProperty("logfile.name", logfile); // PropertyConfigurator.configure(_options.get_home() + "/src/main/resources/log4j.properties"); // log = Logger.getLogger(this.getClass().getPackage().getName()); logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Welcome to Cello //////////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); //print the options for record-keeping //logger.info(Arrays.toString(args).replaceAll(",", "") + "\n"); logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Options ///////////////////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); // logger.info(objToJSONString(_options)); if(_options.get_assignment_algorithm() == null) { logger.info("Assignment algorithm invalid"); _result_status = ResultStatus.arguments_invalid; return; } logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// UCF Validation ////////////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); //UCFAdaptor helps generate Gate/Part libraries from the UCF, and get other data from the UCF. ucfAdaptor.setThreadDependentLoggername(threadDependentLoggername); //UCFReader reads the JSON text file and creates the UCF object. ucfReader.setThreadDependentLoggername(threadDependentLoggername); //UCFValidator. returns 'false' if something is not valid in the UCF. (some collections are optional) ucfValidator.setThreadDependentLoggername(threadDependentLoggername); //UCF. JSON objects organized by 'collection'. UCF ucf = ucfReader.readAllCollections(_options.get_UCFfilepath()); if(ucf == null) { _result_status = ResultStatus.ucf_invalid; logger.info("invalid UCF"); return; } JSONObject ucf_validation_map = ucfValidator.validateAllUCFCollections(ucf, _options); logger.info(gson.toJson(ucf_validation_map)); boolean is_ucf_valid = (boolean) ucf_validation_map.get("is_valid"); if (!is_ucf_valid) { _result_status = ResultStatus.ucf_invalid; logger.info("invalid UCF"); return; } //optional collections // toxicity // cytometry // eugene rules // motif_library // genetic locations //options is passed in order to turn off the toxicity, histogram, plasmid options if that data //is missing from the UCF. /** * abstract_lc: Boolean circuit. Also called wiring diagram. * * unassigned_lcs: input gates and output gates assigned, logic gates not assigned. * multiple possible if permuting input order * * assigned_lcs: all logic gates assigned with genetic gates */ LogicCircuit abstract_lc = new LogicCircuit(); ArrayList<LogicCircuit> unassigned_lcs = new ArrayList<LogicCircuit>(); ArrayList<LogicCircuit> assigned_lcs = new ArrayList<LogicCircuit>(); logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Logic synthesis, Wiring diagram ///////"); logger.info("///////////////////////////////////////////////////////////\n"); /** * NetSynth: convert Verilog to Boolean wiring diagram */ try { abstract_lc = getAbstractCircuit(_options.get_fin_verilog(), ucf); } catch(Exception e) { throw new IllegalStateException("Error in abstract circuit. Exiting."); } /** * A logic circuit must have at least one input gate and one output gate */ if (abstract_lc.get_input_gates().size() == 0 || abstract_lc.get_output_gates().size() == 0) { _result_status = ResultStatus.wiring_diagram_invalid; logger.info("incorrect wiring diagram, no inputs/outputs"); return; } /** * circuit size */ for (GateType gtype : abstract_lc.get_gate_types().keySet()) { logger.info("Circuit has " + abstract_lc.get_gate_types().get(gtype).size() + " " + gtype + " gates."); } logger.info("N logic gates: " + abstract_lc.get_logic_gates().size() + ""); /** * * Set the logic for the input gates. * For combinational logic, this means permuting all input combinations. * For sequential logic, the input 'waveforms' will used as the truth table. * * For a 3-input circuit: * * in1 in2 in3 * 0 0 0 * 0 0 1 * 0 1 0 * 0 1 1 * 1 0 0 * 1 0 1 * 1 1 0 * 1 1 1 */ if(_options.get_circuit_type() == CircuitType.sequential) { HashMap<String, List<Integer>> initial_logics = new HashMap<>(); int nrows = SequentialHelper.loadInitialLogicsFromTruthtable(initial_logics, get_options().get_fin_sequential_waveform()); SequentialHelper.setInitialLogics(abstract_lc, initial_logics, nrows); SequentialHelper.printTruthTable(abstract_lc); logger.info("Cycle 1"); SequentialHelper.updateLogics(abstract_lc); SequentialHelper.printTruthTable(abstract_lc); logger.info("Cycle 2"); SequentialHelper.updateLogics(abstract_lc); SequentialHelper.printTruthTable(abstract_lc); logger.info("Cycle 3"); SequentialHelper.updateLogics(abstract_lc); SequentialHelper.printTruthTable(abstract_lc); //assert logic is valid if(! SequentialHelper.validLogic(abstract_lc)) { throw new IllegalStateException("SequentialHelper: Invalid logic. Exiting."); } } else { LogicCircuitUtil.setInputLogics(abstract_lc); /** * propagate logic through gates */ //initialize logic to all zeroes Integer nrows = abstract_lc.get_input_gates().get(0).get_logics().size(); for (Gate g : abstract_lc.get_Gates()) { if (g.get_logics().isEmpty()) { ArrayList<Integer> logics = new ArrayList<>(); for (int i = 0; i < nrows; ++i) { logics.add(0); } g.set_logics(logics); } } //compute Boolean logic for each gate in the circuit. Evaluate.simulateLogic(abstract_lc); } /** * abstract circuit is now fully specified * * generate figures for abstract circuit */ logger.info(abstract_lc.printGraph()); if (_options.is_figures()) { logger.info("=========== Graphviz wiring diagram =========="); Graphviz graphviz = new Graphviz(_options.get_home(), _options.get_output_directory(), _options.get_jobID()); graphviz.printGraphvizDotText(abstract_lc, _options.get_jobID() + "_wiring_agrn.dot"); ScriptCommands script_commands = new ScriptCommands(_options.get_home(), _options.get_output_directory(), _options.get_jobID()); script_commands.makeDot2Png(_options.get_jobID() + "_wiring_agrn.dot"); if (_options.is_dnaplotlib()) { //PlotLibAbstractTruthtableWriter.writeAbstractCircuitTruthtableForDNAPlotLib( abstract_lc ); } } /** * If you only want to see the Boolean wiring diagram, we are done. */ if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.abstract_only) { _result_status = ResultStatus.abstract_only; return; } // TODO organize DNACompiler in a more modular way. // TODO with a more clear API. // abstract circuit: Verilog in, LogicCircuit out // assigned circuits: abstract_lc in, UCF in, Args in, assigned_lcs out. // plasmids: assigned_lc in, ArrayList<Part> out // SBOL: plasmid in, SBOL out // figures: assigned_lcs in, Args in, /** * The UCF (user constraint file) specifies the gate library, data, and other options. * UCF.java: UCF object * UCFReader: reads .json text file and creates UCF object. * UCFAdaptor: returns java data types from the UCF object. */ logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Loading parts /////////////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); /** * Part objects mapped to the part name. */ PartLibrary part_library = ucfAdaptor.createPartLibrary(ucf); for (Part p : part_library.get_ALL_PARTS().values()) { logger.info("Part: " + p.get_type() + " " + p.get_name()); } logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Loading Gate Library //////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); /** * In order to initialize gate_library, the number of inputs/outputs must be known. * This is because data members in the gate library are 'final' and cannot be modified. */ Integer n_inputs = InputOutputGateReader.nInputs(_options.get_fin_input_promoters()); Integer n_outputs = InputOutputGateReader.nOutputs(_options.get_fin_output_genes()); //TODO this is a comment with blue /** * The gate library is a list of input, logic, and output gates. * input and output gates were specified using text files (user input), * but the logic gates were specified in the UCF. * input gates and logic gates were purposefully omitted from the UCF, * the idea being that the same gate library can be used to design circuits with different inputs/outputs. */ GateLibrary gate_library = ucfAdaptor.createGateLibrary(ucf, n_inputs, n_outputs, _options); for(Gate g: gate_library.get_GATES_BY_NAME().values()) { logger.info("loading gate from UCF gates collection: " + g.Name); } logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Loading input and output gates ////////"); logger.info("///////////////////////////////////////////////////////////\n"); /** * * read text files for input promoters and output genes, populate gate_library with data. * * Inputs: pTac, pTet, pBAD, etc. * includes promoter name, RPU OFF, RPU ON, and DNA sequence * * Outputs: YFP, etc. * includes output gene name, and the concatenated DNA sequence of the output cassette (typically ribozyme, rbs, cds, terminator concatenated) * * gate_library is passed in because it will be modified with the input/output data that's read in */ InputOutputGateReader.readInputsFromFile(_options.get_fin_input_promoters(), gate_library); InputOutputGateReader.readOutputsFromFile(_options.get_fin_output_genes(), gate_library); logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Loading Gate Parts ////////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); //associate Part objects with the _downstream_parts and _regulable_promoter data members of Gate.java ucfAdaptor.setGateParts(ucf, gate_library, part_library); //make sure all gates have gate parts defined if(!ucfValidator.allGatesHaveGateParts(gate_library)) { _result_status = ResultStatus.ucf_invalid; return; } logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Loading Response Functions ////////////"); logger.info("///////////////////////////////////////////////////////////\n"); ucfAdaptor.setResponseFunctions(ucf, gate_library); //make sure all gates have a response function defined. if(!ucfValidator.allGatesHaveResponseFunctions(gate_library)) { _result_status = ResultStatus.ucf_invalid; return; } //printing the response functions for (Gate g : gate_library.get_GATES_BY_NAME().values()) { logger.info(g.Name + " " + g.get_equation() + " " + g.get_params().toString()); } logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Loading Toxicity Data /////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); /** * populate the gate objects with the Part objects for 'downstream_parts' and 'regulable_promoter'. */ ucfAdaptor.setGateToxicity(ucf, gate_library, _options); if (_options.is_toxicity()) { Toxicity.initializeCircuitToxicity(abstract_lc); } logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Loading Cytometry Data ////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); ucfAdaptor.setGateCytometry(ucf, gate_library, _options); /** * populate the gate objects with the Part objects for 'downstream_parts' and 'regulable_promoter'. */ if(_options.is_tandem_promoter()) { logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Loading Tandem Promoter Data //////////"); logger.info("///////////////////////////////////////////////////////////\n"); ucfAdaptor.setTandemPromoters(ucf, gate_library, _options); } /** * print statements for inputs/outputs */ for (String i : gate_library.get_INPUT_NAMES()) { String input_info = "input: " + String.format("%-16s", i); input_info += " off_rpu=" + Util.sc(gate_library.get_INPUTS_OFF().get(i)); input_info += " on_rpu=" + Util.sc(gate_library.get_INPUTS_ON().get(i)); logger.info(input_info); } for (String i : gate_library.get_OUTPUT_NAMES()) { String output_info = "output: " + String.format("%-16s", i); logger.info(output_info); } /** * Allow NOR gates to also be used as NOT gates */ if (_options.is_NOTequalsNOR1() && gate_library.get_GATES_BY_TYPE().containsKey(GateType.NOR)) { LinkedHashMap<String, Gate> NOR_Gates = gate_library.get_GATES_BY_TYPE().get(GateType.NOR); gate_library.get_GATES_BY_TYPE().put(GateType.NOT, NOR_Gates); LinkedHashMap<String, ArrayList<Gate>> NOR_Gate_Groups = gate_library.get_GATES_BY_GROUP().get(GateType.NOR); gate_library.get_GATES_BY_GROUP().put(GateType.NOT, NOR_Gate_Groups); } for (Gate g : gate_library.get_GATES_BY_NAME().values()) { logger.info("Gate: " + g.System + " " + g.Type + " " + g.Name + " " + g.Group); } for (GateType gtype : gate_library.get_GATES_BY_GROUP().keySet()) { logger.info("GateLibrary groups: " + gtype + " " + gate_library.get_GATES_BY_GROUP().get(gtype).size()); } for (GateType gtype : gate_library.get_GATES_BY_GROUP().keySet()) { LinkedHashMap<String, ArrayList<Gate>> groups = gate_library.get_GATES_BY_GROUP().get(gtype); for (String group_name : groups.keySet()) { String group_string_builder = gtype + ": group name: " + group_name; ArrayList<Gate> gates = groups.get(group_name); for (Gate g : gates) { group_string_builder += " " + g.Name; } logger.info(group_string_builder); } } for(Gate g: _abstract_lc.get_logic_gates()) { logger.info(g.Type); } /** * are there enough gates of each type (input, output, logic to build the circuit */ if (abstract_lc.get_input_gates().size() > gate_library.get_INPUT_NAMES().length) { logger.info("Number of input gates out of range: " + abstract_lc.get_input_gates().size()); return; } if (abstract_lc.get_output_gates().size() > gate_library.get_OUTPUT_NAMES().length) { logger.info("Number of output gates out of range: " + abstract_lc.get_output_gates().size()); return; } if (!LogicCircuitUtil.libraryGatesCoverCircuitGates(abstract_lc, gate_library)) { //logger.info("Not enough gates in the library to cover the gates in the circuit."); //return; logger.info("Not enough gates in the library to cover the gates in the circuit."); return; } else { logger.info("The gates library can cover the circuit."); } /** * * Assign input promoters to input gates, and also assign output gates * * _options.get_permute_inputs == false: unassigned_lcs.size() == 1 * _options.get_permute_inputs == true: unassigned_lcs.size() == 2^(n_inputs) * */ //_options.get_permute_inputs = true; unassigned_lcs = LogicCircuitUtil.getInputAssignments(abstract_lc, gate_library, _options.is_permute_inputs()); for(LogicCircuit lc: unassigned_lcs) { LogicCircuitUtil.setInputOutputGroups(lc); } /** * * Promoter interference has been observed for certain promoters when downstream in the txn unit, * likely due to the inability of RNAP to pass through. Our term for this is roadblocking, * which disrupts the assumption that tandem promoter activities are additive. * * As a result, two roadblocking promoters cannot be inputs to a NOR gate or OUTPUT_OR gate, * because one of the promoters must be downstream in the txn unit, which leads to interference. * * * Roadblocking inducible promoters: pTac, pBAD * Roadblocking repressible promoters: pSrpR, pPhlF, pBM3R1, pQacR * */ ArrayList<String> eugene_part_rules = ucfAdaptor.getEugenePartRules(ucf); Roadblock roadblock = new Roadblock(); roadblock.setThreadDependentLoggername(threadDependentLoggername); roadblock.set_roadblockers(eugene_part_rules, gate_library); //gate_library.setHashMapsForGates(); /** * * If inducible promoters (pTac, pBAD) result in roadblocking in the input order given, promoter interference * will occur, but we design the circuit and provide a warning message. * * However, when a repressible promoter participates in roadblocking, this will be treated as an illegal assignment. * */ ArrayList<LogicCircuit> nonRB_unassigned_lcs = new ArrayList<LogicCircuit>(); for (LogicCircuit unassigned_lc : unassigned_lcs) { /*if (_options.is_assign_C_pBAD()) { // This is a hack for Lauren's latched designs for (Gate g : unassigned_lc.get_input_gates()) { if (g.Group.equals("C") && g.Name.equals("pBAD")) { if (!roadblock.illegalInputRoadblocking(unassigned_lc)) { nonRB_unassigned_lcs.add(unassigned_lc); } } } }*/ if (!roadblock.illegalInputRoadblocking(unassigned_lc)) { nonRB_unassigned_lcs.add(unassigned_lc); } } if (nonRB_unassigned_lcs.size() == 0) { logger.info("\n"); logger.info("-----------------------------------------------------------"); logger.info("--------------- Warning: input promoter roadblocking ----"); logger.info("-----------------------------------------------------------\n"); /* * Choose one input assignment... it's roadblocking, but we will continue with the design anyway. */ nonRB_unassigned_lcs.add(unassigned_lcs.get(0)); } /** * * Ready to assign genetic gates * * Random * BreadthFirstSearch (guarantees global max) * Hill climbing * Simulated annealing * */ //No assignment needed if no logic gates. 2-input OR has no logic gates, for example if (unassigned_lcs.get(0).get_logic_gates().size() == 0) { assigned_lcs = nonRB_unassigned_lcs; } else { logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Assignment algorithm //////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); logger.info("assignment algorithm: " + _options.get_assignment_algorithm()); Date datestart = new Date(); long starttime = datestart.getTime(); BuildCircuits circuit_builder = new BuildCircuits(); //base class logger.info("=========== Assignment algorithm ============="); //default: simulated annealing. similar to hill climbing, but with a cooling schedule if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.sim_annealing) { circuit_builder = new BuildCircuitsSimAnnealing(_options, gate_library, roadblock); } //hill climbing. Many swaps with accept/reject based on score increase/decrease. else if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.hill_climbing) { circuit_builder = new BuildCircuitsHillClimbing(_options, gate_library, roadblock); } //Breadth First Search algorithm. Performs an exhaustive search. else if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.breadth_first) { circuit_builder = new BuildCircuitsBreadthFirstSearch(_options, gate_library, roadblock); /** * Breadth-first is memory intensive and is not used in the publicly available tool on cellocad.org. */ _result_status = ResultStatus.breadth_first_not_allowed; return; } //similar to hill climbing, but explores all options for a single swap and chooses the best swap each time. else if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.steepest_ascent) { circuit_builder = new BuildCircuitsSteepestAscent(_options, gate_library, roadblock); } //completely randomizes the gate assignment. Does this many times. else if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.random) { circuit_builder = new BuildCircuitsRandom(_options, gate_library, roadblock); } //exhaustive... does not scale. else if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.permute) { circuit_builder = new BuildCircuitsPermuteNOR(_options, gate_library, roadblock); } //if you want to reload a prior assignment. Based on x_logic_circuit.txt parsing. else if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.reload) { circuit_builder = new BuildCircuitsReload(_options, gate_library, roadblock); } //do not use. else if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.preset) { circuit_builder = new BuildCircuitsPreset(_options, gate_library, roadblock); } else { } circuit_builder.setThreadDependentLoggername(threadDependentLoggername); //when circuits have one or more feedback loops, it's a sequential circuit rather than combinational. //currently hacky, needs to be refined. /*if (_options.get_assignment_algorithm() == BuildCircuits.AssignmentAlgorithm.sequential) { _options.set_histogram(false); circuit_builder = new SequentialHelper(_options, gate_library, roadblock); }*/ logger.info(unassigned_lcs.size()); for (LogicCircuit unassigned_lc : nonRB_unassigned_lcs) { circuit_builder.set_unassigned_lc(unassigned_lc); /** * Run assignment algorithm */ circuit_builder.buildCircuits(); // TODO hard-coded for Jonghyeon boolean only_tp = false; if (only_tp) { for (LogicCircuit lc : circuit_builder.get_logic_circuits()) { boolean has_all_tp_data = LogicCircuitUtil.dataFoundForAllTandemPromoters(gate_library, lc); if (has_all_tp_data) { assigned_lcs.add(lc); } } } // else { assigned_lcs.addAll(circuit_builder.get_logic_circuits()); } } /** * * Assignment complete. * */ logger.info("=========== Assigned circuits ================"); logger.info("assigned lcs: " + assigned_lcs.size() + ""); Date datestop = new Date(); long endtime = datestop.getTime(); long elapsedtime = endtime - starttime; logger.info("Total elapsed time for assignment algorithm: " + elapsedtime + " milliseconds"); if (assigned_lcs.size() == 0) { _result_status = ResultStatus.no_assignments_found; logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("//////// No assignments found. Exiting Cello. /////////"); logger.info("///////////////////////////////////////////////////////////\n"); return; } } /** * * Multiple circuits will exist: * if permuting input order, * if the search algorithm saves multiple circuits instead of just the best circuit. * * To get the best circuit, sort the LogicCircuit objects by score * */ sortLogicCircuitsByScore(assigned_lcs); logger.info("best assignment score: " + String.format("%-5.4f", assigned_lcs.get(0).get_scores().get_score())); /** * Predict distributions (optional). * Generate plasmids. * Generate figures. */ logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Processing best circuits //////////////"); logger.info("///////////////////////////////////////////////////////////\n"); //sim annealing / hill climbing can add duplicate assignments //this doesn't matter if only 1 assignment will be the Cello output //but could cause problems if more than 1 assignment is desired ArrayList<LogicCircuit> unique_lcs = assigned_lcs; LinkedHashMap<String, LogicCircuit> unique_lcs_map = new LinkedHashMap<>(); if(_options.is_output_all_assignments()) { for(LogicCircuit lc: assigned_lcs) { String score = Util.sc(lc.get_scores().get_score()); unique_lcs_map.put(score, lc); } unique_lcs = new ArrayList<>(unique_lcs_map.values()); } logger.info("all lcs " + assigned_lcs.size()); logger.info("unique lcs " + unique_lcs.size()); sortLogicCircuitsByScore(unique_lcs); /*if (_options.is_unique_rbs_assignments()) { ArrayList<LogicCircuit> unique_assignment_lcs = BuildCircuitsUtil.removeIdenticalTUs(unique_lcs, gate_library, part_library); unique_lcs = unique_assignment_lcs; } else if (_options.is_unique_repressor_assignments()) { ArrayList<LogicCircuit> unique_repressor_lcs = BuildCircuitsUtil.getUniqueRepressorAssignments(unique_lcs, gate_library, part_library); unique_lcs = unique_repressor_lcs; }*/ if(_options.get_nA() > unique_lcs.size()) { _options.set_nA(unique_lcs.size()); } if(_options.is_output_all_assignments()) { if(_options.is_histogram()) { for(Gate g: gate_library.get_GATES_BY_NAME().values()) { HistogramUtil.interpolateTransferFunctionTitrations(g.Name, gate_library); } String file_name_default = _options.get_home() + _options.get_datapath() + "default_histogram.txt"; InputOutputGateReader.makeHistogramsforInputRPUs(gate_library, file_name_default); for(LogicCircuit lc: unique_lcs) { LogicCircuitUtil.setInputRPU(lc, gate_library); for (Gate g : lc.get_Gates()) { g.get_histogram_bins().init(); } for (Gate g : lc.get_logic_gates()) { g.set_xfer_hist(gate_library.get_GATES_BY_NAME().get(g.Name).get_xfer_hist()); } Evaluate.evaluateCircuitHistogramOverlap(lc, gate_library, _options); } for(LogicCircuit lc: unique_lcs) { Double overlap_score = lc.get_scores().get_conv_overlap(); lc.get_scores().set_onoff_ratio(overlap_score); } sortLogicCircuitsByScore(unique_lcs); } int counter = 0; for(LogicCircuit lc: unique_lcs) { lc.set_assignment_name( _options.get_jobID() + "_A" + String.format("%03d", counter) ); counter++; Util.fileWriter(_options.get_output_directory() + lc.get_assignment_name() + "_logic_circuit.txt", lc.toString(), false); logger.info("=========== Circuit bionetlist ==============="); PlasmidUtil.setGateParts(lc, gate_library, part_library); Netlist.setBioNetlist(lc, false); Util.fileWriter(_options.get_output_directory() + lc.get_assignment_name() + "_bionetlist.txt", lc.get_netlist(), false); } return; } sortLogicCircuitsByScore(unique_lcs); _logic_circuits = new ArrayList<>(); for(int a=0; a<_options.get_nA(); ++a) { LogicCircuit lc = new LogicCircuit(unique_lcs.get(a)); lc.set_index(a); lc.set_assignment_name( _options.get_jobID() + "_A" + String.format("%03d", a) ); _logic_circuits.add(lc); Double unit_conversion = ucfAdaptor.getUnitConversion(ucf); for(Gate g: lc.get_output_gates()) { g.set_unit_conversion(unit_conversion); } Evaluate.evaluateCircuit(lc, gate_library, _options); for (Gate g : lc.get_Gates()) { Evaluate.evaluateGate(g, _options); } if (_options.is_toxicity()) { Toxicity.evaluateCircuitToxicity(lc, gate_library); } logger.info("=========== Circuit assignment details ======="); logger.info(lc.toString() + "\n"); Util.fileWriter(_options.get_output_directory() + lc.get_assignment_name() + "_logic_circuit.txt", lc.toString(), false); // TODO logger.info("=========== Circuit bionetlist ==============="); PlasmidUtil.setGateParts(lc, gate_library, part_library); Netlist.setBioNetlist(lc, false); logger.info(lc.get_netlist()); Util.fileWriter(_options.get_output_directory() + lc.get_assignment_name() + "_bionetlist.txt", lc.get_netlist(), false); if(_options.is_histogram()) { logger.info("=========== Simulate cytometry distributions"); String file_name_default = _options.get_home() + _options.get_datapath() + "default_histogram.txt"; InputOutputGateReader.makeHistogramsforInputRPUs(gate_library, file_name_default); LogicCircuitUtil.setInputRPU(lc, gate_library); for(Gate g: lc.get_Gates()) { g.get_histogram_bins().init(); } for(Gate g: lc.get_logic_gates()) { HistogramUtil.interpolateTransferFunctionTitrations(g.Name, gate_library); g.set_xfer_hist(gate_library.get_GATES_BY_NAME().get(g.Name).get_xfer_hist()); logger.info("histogram interpolation for " + g.Name + " " + g.get_xfer_hist().get_xfer_interp().size() + " " + g.get_xfer_hist().get_xfer_interp().get(0).length ); } Evaluate.evaluateCircuitHistogramOverlap(lc, gate_library, _options); logger.info("distribution score: " + lc.get_scores().get_conv_overlap()); } //if(_options.get_histogram() && lc.get_scores().get_conv_overlap() < _options.get_histogram()_threshold) { // continue; //} /*SBOLCircuitWriterIWBDA sbol_circuit_writer = new SBOLCircuitWriterIWBDA(); sbol_circuit_writer.setCircuitName(lc.get_assignment_name()); //String sbol_document = sbol_circuit_writer.writeSBOLCircuit(lc.get_assignment_name() + "_SBOL.xml", lc, lc.get_assignment_name(), _options); String sbol_document = sbol_circuit_writer.writeSBOLCircuit(lc.get_assignment_name() + "_circuit.sbol", lc, lc.get_assignment_name(), _options);*/ if (_options.is_figures()) { logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("//////////////////////// Figures //////////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); generateFigures(lc, gate_library); } if(_options.is_plasmid()) { logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Plasmid DNA sequences /////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); PlasmidUtil.findPartComponentsInOutputGates(lc, gate_library, part_library); generatePlasmids(lc, gate_library, part_library, ucf); } ScriptCommands script_commands = new ScriptCommands(_options.get_home(), _options.get_output_directory(), _options.get_jobID()); script_commands.removeEPSFiles(_options.get_output_directory()); //script_commands.removeGateFiles(_options.get_output_directory()); /** * This warning was printed earlier, but it is more noticeable at the end of the text file */ if (roadblock.illegalInputRoadblocking(lc)) { _result_status = ResultStatus.roadblocking_inputs; logger.info("\n"); logger.info("-----------------------------------------------------------"); logger.info("--------------- Warning: input promoter roadblocking ----"); logger.info("-----------------------------------------------------------\n"); } } if(_result_status != ResultStatus.roadblocking_inputs) { _result_status = ResultStatus.success; } logger.info("\n"); logger.info("///////////////////////////////////////////////////////////"); logger.info("/////////////// Cello finished playing ////////////////"); logger.info("///////////////////////////////////////////////////////////\n"); return; } /////////////////////////////////////////////////////////////////////////////////////////////// ////////////// DNACompiler functions /////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////// /** * * Use Eugene for rules-based permutation of txn unit order/orientation to generate additional plasmid variants. * * @param lc * @param gate_library * @param part_library */ public void generatePlasmids(LogicCircuit lc, GateLibrary gate_library, PartLibrary part_library, UCF ucf) { String name_Eug_circuit_rules = lc.get_assignment_name() + "_Eugene_circuit_module_rules.eug"; String name_Eug_circuit_parts = lc.get_assignment_name() + "_Eugene_circuit_module_part_list.txt"; String name_Eug_circuit_gates = lc.get_assignment_name() + "_Eugene_circuit_module_gate_list.txt"; String name_Eug_output_rules = lc.get_assignment_name() + "_Eugene_output_module_rules.eug"; String name_Eug_output_parts = lc.get_assignment_name() + "_Eugene_output_module_part_list.txt"; logger.info("=========== Setting gate parts according to assigned gate names"); //Plasmid.setGateParts(lc, gate_library, part_library); PlasmidUtil.setTxnUnits(lc, gate_library); EugeneAdaptor eugeneAdaptor = new EugeneAdaptor(); eugeneAdaptor.setThreadDependentLoggername(threadDependentLoggername); ArrayList<String> sensor_module_lines = Util.fileLines(_options.get_fin_sensor_module()); String sensor_module_sequence = ""; for(String s: sensor_module_lines) { sensor_module_sequence += s; } Part sensor_module_part = new Part("sensor_module", "backbone", sensor_module_sequence); ArrayList<Part> sensor_module_list = new ArrayList<Part>(); ArrayList<ArrayList<Part>> sensor_module_lists = new ArrayList<ArrayList<Part>>(); sensor_module_list.add(sensor_module_part); sensor_module_lists.add(sensor_module_list); lc.set_sensor_module_parts(sensor_module_lists); String circuit_eugene_file_string = ""; ucfAdaptor.setThreadDependentLoggername(threadDependentLoggername); ArrayList<String> eugene_part_rules = ucfAdaptor.getEugenePartRules(ucf); ArrayList<String> eugene_gate_rules = ucfAdaptor.getEugeneGateRules(ucf); eugeneAdaptor.set_eugene_part_rules(eugene_part_rules); eugeneAdaptor.set_eugene_gate_rules(eugene_gate_rules); String circuit_module_location_name = ucfAdaptor.getCircuitModuleLocationName(ucf); String output_module_location_name = ucfAdaptor.getOutputModuleLocationName(ucf); if(circuit_module_location_name == null || circuit_module_location_name.isEmpty() || output_module_location_name == null || output_module_location_name.isEmpty() || circuit_module_location_name.equals(output_module_location_name) ) { logger.info("=========== Eugene: circuit module and output module combined ==========="); ArrayList<Gate> logic_and_output_gates = new ArrayList<>(); logic_and_output_gates.addAll(lc.get_logic_gates()); logic_and_output_gates.addAll(lc.get_output_gates()); circuit_eugene_file_string = eugeneAdaptor.generateEugeneFile(logic_and_output_gates, name_Eug_circuit_rules, part_library, _options); logger.info("Eugene: combinatorial design of plasmid layouts...\n"); eugeneAdaptor.callEugene(name_Eug_circuit_rules, lc.get_circuit_module_parts(), part_library, _options); logger.info("Number of circuit module layouts: " + lc.get_circuit_module_parts().size()); } else if(!circuit_module_location_name.isEmpty() && ! output_module_location_name.isEmpty() && !circuit_module_location_name.equals(output_module_location_name)) { logger.info("=========== Eugene: circuit module ==========="); circuit_eugene_file_string = eugeneAdaptor.generateEugeneFile(lc.get_logic_gates(), name_Eug_circuit_rules, part_library, _options); logger.info("Eugene: combinatorial design of plasmid layouts...\n"); eugeneAdaptor.callEugene(name_Eug_circuit_rules, lc.get_circuit_module_parts(), part_library, _options); logger.info("Number of circuit module layouts: " + lc.get_circuit_module_parts().size()); logger.info("=========== Eugene: output module ============"); //_options.get_eugene_scars = false; String output_eugene_file_string = eugeneAdaptor.generateEugeneFile(lc.get_output_gates(), name_Eug_output_rules, part_library, _options); eugeneAdaptor.callEugene(name_Eug_output_rules, lc.get_output_module_parts(), part_library, _options); logger.info("Number of output module layouts: " + lc.get_output_module_parts().size()); } int p_counter = 0; for(ArrayList<Part> module: lc.get_circuit_module_parts()) { String N = lc.get_assignment_name() + "_P" + String.format("%03d", p_counter); ArrayList<String> parts_list = new ArrayList<String>(); ArrayList<String> gates_list = new ArrayList<String>(); for(Part p: module) { parts_list.add(p.get_direction() + p.get_name()); if(p.get_type().equals("cds")) { gates_list.add(p.get_direction() + "gate_" + p.get_name()); } } Util.fileWriter(_options.get_output_directory() + name_Eug_circuit_parts, N + " " + parts_list.toString()+"\n", true); Util.fileWriter(_options.get_output_directory() + name_Eug_circuit_gates, N + " " + gates_list.toString()+"\n", true); ++p_counter; } for(ArrayList<Part> module: lc.get_output_module_parts()) { String N = lc.get_assignment_name() + "_P" + String.format("%03d", p_counter); ArrayList<String> parts_list = new ArrayList<String>(); ArrayList<String> gates_list = new ArrayList<String>(); for (Part p : module) { parts_list.add(p.get_direction() + p.get_name()); } Util.fileWriter(_options.get_output_directory() + name_Eug_output_parts, N + " " + parts_list.toString()+"\n", true); } if(ucf.get_genetic_locations().isEmpty()) { lc.set_sensor_plasmid_parts(lc.get_sensor_module_parts()); lc.set_circuit_plasmid_parts(lc.get_circuit_module_parts()); lc.set_output_plasmid_parts(lc.get_output_module_parts()); } else { if (! ucf.get_genetic_locations().containsKey("sensor_module_location")) { lc.set_sensor_plasmid_parts(lc.get_sensor_module_parts()); } if (! ucf.get_genetic_locations().containsKey("circuit_module_location")) { logger.info("Setting circuit module parts"); lc.set_circuit_plasmid_parts(lc.get_circuit_module_parts()); } if (! ucf.get_genetic_locations().containsKey("output_module_location")) { lc.set_output_plasmid_parts(lc.get_output_module_parts()); } } GeneticLocationWriter.insertModulePartsIntoGeneticLocations(lc, ucf); // logger.info("Circuit module parts"); // logger.info(lc.get_circuit_module_parts().get(0).toString()); // // logger.info("Circuit plasmid parts"); // logger.info(lc.get_circuit_plasmid_parts().get(0).toString()); ArrayList<String> all_plasmid_strings = new ArrayList<>(); logger.info("\n=========== Writing plasmid files ============"); if(lc.get_sensor_plasmid_parts().size() > 0) { all_plasmid_strings.addAll( PlasmidUtil.writePlasmidFiles(lc.get_sensor_plasmid_parts(), lc.get_assignment_name(), "plasmid_sensor", _options.get_output_directory()) ); } if(lc.get_circuit_plasmid_parts().size() > 0) { all_plasmid_strings.addAll( PlasmidUtil.writePlasmidFiles(lc.get_circuit_plasmid_parts(), lc.get_assignment_name(), "plasmid_circuit", _options.get_output_directory()) ); } if(lc.get_output_plasmid_parts().size() > 0) { all_plasmid_strings.addAll( PlasmidUtil.writePlasmidFiles(lc.get_output_plasmid_parts(), lc.get_assignment_name(), "plasmid_output", _options.get_output_directory()) ); } logger.info("\n=========== SBOL for circuit plasmids ========"); //currently not writing an SBOL document for the output plasmid if the output module is on a different plasmid than the circuit. for(int i=0; i<lc.get_circuit_plasmid_parts().size(); ++i) { ArrayList<Part> plasmid = lc.get_circuit_plasmid_parts().get(i); SBOLCircuitWriter sbol_circuit_writer = new SBOLCircuitWriter(); sbol_circuit_writer.setCircuitName(lc.get_assignment_name()); String sbol_filename = lc.get_assignment_name() + "_sbol_circuit" + "_P" + String.format("%03d", i) + ".sbol"; String sbol_plasmid_name = lc.get_assignment_name() + "_P" + String.format("%03d", i); String sbol_document = sbol_circuit_writer.writeSBOLCircuit(sbol_filename, lc, plasmid, sbol_plasmid_name, _options); } PlasmidUtil.resetParentGates(lc); if(_options.is_figures()) { if (_options.is_dnaplotlib()) { logger.info("\n"); logger.info("=========== DNAPlotLib ======================="); logger.info("rendering genetic diagram image..."); PlotLibWriter.writeCircuitsForDNAPlotLib(lc.get_circuit_plasmid_parts(), lc.get_index(), _options); } } logger.info(""); } /** * * Automated figure generation. * */ public void generateFigures(LogicCircuit lc, GateLibrary gate_library) { Integer a = lc.get_index(); String name_wiring_xfer = lc.get_assignment_name() + "_wiring_xfer.dot"; String name_wiring_rpu = lc.get_assignment_name() + "_wiring_rpu.dot"; String name_wiring_grn = lc.get_assignment_name() + "_wiring_grn.dot"; Gnuplot gnuplot = new Gnuplot(_options.get_home(), _options.get_output_directory(), _options.get_jobID()); Graphviz graphviz = new Graphviz(_options.get_home(), _options.get_output_directory(), _options.get_jobID()); ScriptCommands script_commands = new ScriptCommands(_options.get_home(), _options.get_output_directory(), _options.get_jobID()); logger.info("=========== Graphviz wiring diagram =========="); Colors.setColors(); graphviz.printGraphvizDotText(lc, name_wiring_grn); script_commands.makeDot2Png(name_wiring_grn); if(_options.is_response_fn()) { logger.info("=========== Graphviz Xfer figures ============"); gnuplot.printGnuplotXfer(lc, _options); graphviz.printGraphvizXferPNG(lc, name_wiring_xfer); script_commands.makeCircuitRPUFigure(lc.get_assignment_name()); script_commands.makeDot2Png(name_wiring_xfer); } if(_options.is_snr()) { logger.info("=========== SNR figures ======================="); for(Gate g: lc.get_logic_gates()) { gnuplot.printGnuplotGateSNR(g, lc.get_assignment_name(), _options); } script_commands.makeCircuitSNRFigure(lc.get_assignment_name()); } if(_options.is_tandem_promoter()) { logger.info("=========== Tandem promoter figures ======================="); gnuplot.makeTandemPromoterHeatmaps(lc, gate_library, _options); InterpolateTandemPromoter itp = new InterpolateTandemPromoter(); HistogramBins hbins = new HistogramBins(); hbins.init(); for(Gate g: lc.get_Gates()) { if(g.Type == GateType.INPUT) { continue; } boolean tp_exists = false; String tp_name = ""; double[][] grid = new double[hbins.get_NBINS()][hbins.get_NBINS()]; Gate child1 = new Gate(); Gate child2 = new Gate(); ArrayList<String> fanin_gate_names = new ArrayList<>(); String var = "x"; if(g.get_variable_names().size() == 1) { var = g.get_variable_names().get(0); } if (g.get_variable_wires().get(var).size() == 2) { //hard-coded child1 = g.getChildren().get(0); child2 = g.getChildren().get(1); if (child1.Type == Gate.GateType.INPUT) { fanin_gate_names.add("input_" + child1.Name); } else { fanin_gate_names.add(child1.Name); } if (child2.Type == Gate.GateType.INPUT) { fanin_gate_names.add("input_" + child2.Name); } else { fanin_gate_names.add(child2.Name); } String tandem_promoter_name_1 = fanin_gate_names.get(0) + "_" + fanin_gate_names.get(1); String tandem_promoter_name_2 = fanin_gate_names.get(1) + "_" + fanin_gate_names.get(0); tp_name = tandem_promoter_name_1; if (gate_library.get_TANDEM_PROMOTERS().containsKey(tandem_promoter_name_1)) { grid = gate_library.get_TANDEM_PROMOTERS().get(tandem_promoter_name_1); tp_name = tandem_promoter_name_1; tp_exists = true; } else if (gate_library.get_TANDEM_PROMOTERS().containsKey(tandem_promoter_name_2)) { grid = gate_library.get_TANDEM_PROMOTERS().get(tandem_promoter_name_2); tp_name = tandem_promoter_name_2; tp_exists = true; } } if(tp_exists) { String file_points_on = "grid_tp_" + tp_name + "_points_on.txt"; String file_points_off = "grid_tp_" + tp_name + "_points_off.txt"; String file_interp = "grid_tp_" + tp_name + ".txt"; String file_points_on_path = _options.get_output_directory() + "/" + file_points_on; String file_points_off_path = _options.get_output_directory() + "/" + file_points_off; String file_interp_path = _options.get_output_directory() + "/" + file_interp; logger.info("////////////////////////////////////////// "); logger.info("making " + file_interp); itp.writeGridstoFiles(grid, file_interp_path, 5); String gate1_name = fanin_gate_names.get(0); String gate2_name = fanin_gate_names.get(1); String points_on = ""; String points_off = ""; String v = "x"; for(int row=0; row<g.get_logics().size(); ++row) { Double in1 = 0.0; Double in2 = 0.0; if (child1.Type == Gate.GateType.INPUT) { if (child1.get_logics().get(row) == 0) { in1 = Math.pow(10, hbins.get_LOGMIN()); } else if (child1.get_logics().get(row) == 1) { in1 = Math.pow(10, hbins.get_LOGMAX()); } } else { in1 = child1.get_inrpus().get(v).get(row); } if (child2.Type == Gate.GateType.INPUT) { if (child2.get_logics().get(row) == 0) { in2 = Math.pow(10, hbins.get_LOGMIN()); } else if (child2.get_logics().get(row) == 1) { in2 = Math.pow(10, hbins.get_LOGMAX()); } } else { in2 = child2.get_inrpus().get(v).get(row); } if (tp_name.startsWith(gate1_name) && tp_name.endsWith(gate2_name)) { //correct in1 and in2 order } else if (tp_name.startsWith(gate2_name) && tp_name.endsWith(gate1_name)) { Double temp = new Double(in1); in1 = in2; in2 = temp; } else { throw new IllegalStateException("Problem with tandem promoter lookup"); } Integer bin1 = HistogramUtil.bin_of_logrpu(Math.log10(in1), hbins); Integer bin2 = HistogramUtil.bin_of_logrpu(Math.log10(in2), hbins); int logic = g.get_logics().get(row); if (g.Type == GateType.NOR) { logic = BooleanLogic.computeNOT(logic); } if(logic == 0) { points_off += bin1 + " " + bin2 + " 1\n"; } if(logic == 1) { points_on += bin1 + " " + bin2 + " 1\n"; } } Util.fileWriter(file_points_on_path, points_on, false); Util.fileWriter(file_points_off_path, points_off, false); String cmd = "perl " + _options.get_home() + "/resources/scripts/make_tandem_promoter_heatmaps.pl " + _options.get_output_directory() + " " + _options.get_jobID() + " " + _options.get_home() + "/resources/scripts/" + " " + file_interp + " " + file_points_on + " " + file_points_off + " " + tp_name; String command_result = Util.executeCommand(cmd); } else { logger.info(tp_name + " DOES NOT EXIST "); } } } if (_options.is_truthtable_rpu()) { logger.info("=========== Truth table figure(s) ============"); if (_options.is_histogram()) { logger.info("=========== histogram multiplots ============="); String input_truth = ""; for(int i=0; i<lc.get_input_gates().get(0).get_logics().size(); ++i) { for (Gate g : lc.get_input_gates()) { input_truth += g.get_logics().get(i); } input_truth += ","; } gnuplot.makeHistogramMultiplot(lc, "truth", input_truth); for (Gate g : lc.get_logic_gates()) { gnuplot.makeHistogramMultiplotGate(g, lc.get_assignment_name(), "gate", input_truth); } /*for (Gate g : lc.get_input_gates()) { gnuplot.makeHistogramMultiplotGate(g, lc.get_assignment_name(), "gate"); }*/ for (Gate g : lc.get_output_gates()) { gnuplot.makeHistogramMultiplotGate(g, lc.get_assignment_name(), "gate", input_truth); } graphviz.printGraphvizDistrPNG(lc, name_wiring_rpu); script_commands.makeDot2Png(name_wiring_rpu); } else { logger.info("=========== bargraph multiplots =============="); gnuplot.makeTruthtableBargraph(lc, "truth"); for (Gate g : lc.get_logic_gates()) { gnuplot.makeTruthtableBargraph(g, lc.get_assignment_name(), "gate"); } /*for (Gate g : lc.get_input_gates()) { gnuplot.makeTruthtableBargraph(g, lc.get_assignment_name(), "gate"); }*/ for (Gate g : lc.get_output_gates()) { gnuplot.makeTruthtableBargraph(g, lc.get_assignment_name(), "gate"); } graphviz.printGraphvizDistrPNG(lc, name_wiring_rpu); script_commands.makeDot2Png(name_wiring_rpu); } } if(_options.is_toxicity() && _options.is_truthtable_tox()) { logger.info("============== cell growth plots ============="); gnuplot.makeCellGrowthFigure(lc, "toxicity"); } logger.info("=========== Table of predicted expression levels (RPU)"); String rpu_table = lc.printRPUTable(); String outfile_rputable = lc.get_assignment_name() + "_rputable.txt"; Util.fileWriter(_options.get_output_directory() + outfile_rputable, rpu_table, false); logger.info(rpu_table); if(_options.is_toxicity()) { logger.info("=========== Table of predicted cell growth (relative OD600)"); String tox_table = Toxicity.writeToxicityTable(lc); logger.info(tox_table); String outfile = lc.get_assignment_name() + "_toxtable.txt"; Util.fileWriter(_options.get_output_directory() + outfile, tox_table, false); } } /** * * set filepaths to load input, output, repressor, toxicity data. * * Command-line arguments can be used for custom file inputs * */ public void setPaths() { //Date: prefix for output files if(_options.get_jobID().equals("")) { java.util.Date date=new Date(); _options.set_jobID( "job_" + String.valueOf(date.getTime()) ); } if(_options.get_fin_sensor_module() == "") { _options.set_fin_sensor_module( _options.get_home() + _options.get_datapath() + "inputs/sensor_module.txt" ); } if(_options.get_fin_input_promoters() == "") { _options.set_fin_input_promoters( _options.get_home() + _options.get_datapath() + "inputs/Inputs.txt" ); } if(_options.get_fin_output_genes() == "") { _options.set_fin_output_genes( _options.get_home() + _options.get_datapath() + "outputs/Outputs.txt" ); } if(_options.get_UCFfilepath() == "") { _options.set_UCFfilepath( _options.get_home() + "/resources/UCF/Eco1C1G1T1.UCF.json" ); } if(_options.get_output_directory().equals("")) { _options.set_output_directory( _options.get_jobID() + "/" ); } } /** * * Prashant Vaidyanathan's NetlistSynthesizer generates the wiring diagram from Verilog input * * Flow 1: ABC to AND-Inverter Graph to NOR/NOT * Flow 2: Espresso to POS to NOR/NOT * Other: precomputed netlists for 3-input 1-output (by Swapnil Bhatia) * */ public LogicCircuit getAbstractCircuit(String verilog_filepath, UCF ucf) throws IOException, ParseException { if(_options.get_circuit_type() == CircuitType.sequential) { if( ! _options.get_synthesis().equals("originalstructural")) { throw new IllegalStateException("ARGUMENTS: sequential logic requires originalstructural logic synthesis."); } if(get_options().get_fin_sequential_waveform() == "") { throw new IllegalStateException("ARGUMENTS: missing sequential waveform"); } LogicCircuit abstract_lc = StructuralVerilogToDAG.createDAG(get_options().get_fin_verilog()); return abstract_lc; } LogicCircuit abstract_logic_circuit = new LogicCircuit(); ////////////////// Create LogicCircuit from NetSynth ////////////// //get Abstract Circuit with options org.cellocad.BU.dom.DAGW GW = new org.cellocad.BU.dom.DAGW(); String verilog_string = ""; ArrayList<String> verilog_lines = Util.fileLines(verilog_filepath); for(String s: verilog_lines) { verilog_string += s + "\n"; } List<NetSynthSwitch> switches = new ArrayList<>(); org.json.JSONArray motifLibrary = new org.json.JSONArray(); //convert org.simple.json to org.json for(int i=0; i<ucf.get_motif_library().size(); ++i) { String objString = ucf.get_motif_library().get(i).toString(); try { motifLibrary.put(new org.json.JSONObject(objString)); } catch (JSONException e) { e.printStackTrace(); } } NetSynth netsynth = new NetSynth("netSynth", Utilities.getNetSynthResourcesFilepath() ,_options.get_output_directory()); GW = netsynth.runNetSynth( verilog_filepath, new ArrayList<NetSynthSwitch>(), motifLibrary ); netsynth.cleanDirectory(); abstract_logic_circuit = new LogicCircuit(GW.Gates, GW.Wires); //Prashant needs to fix bug with extra output wire. LogicCircuit lc = abstract_logic_circuit; for(int i=0; i<lc.get_Wires().size(); ++i) { Wire w = lc.get_Wires().get(i); if(w.To.Index == w.From.Index) { lc.get_Wires().remove(i); i--; } } for(Gate g: abstract_logic_circuit.get_Gates()) { if(g.Outgoing != null) { g.Outgoing_wire_index = g.Outgoing.Index; } } for(Wire w: abstract_logic_circuit.get_Wires()) { if(w.From != null) { w.From_index = w.From.Index; } if(w.To != null) { w.To_index = w.To.Index; } if(w.Next != null) { w.Next_index = w.Next.Index; } } LogicCircuitUtil.renameGatesWires(abstract_logic_circuit); logger.info(Netlist.getNetlist(abstract_logic_circuit)); _abstract_lc = abstract_logic_circuit; return abstract_logic_circuit; } /** * * sorts LogicCircuit objects by score * * */ public static void sortLogicCircuitsByScore(ArrayList<LogicCircuit> circuits) { Collections.sort(circuits, new Comparator<LogicCircuit>() { public int compare(LogicCircuit lc1, LogicCircuit lc2){ int result = 0; if ( (lc2.get_scores().get_score() - lc1.get_scores().get_score()) > 1e-10 ){ result = 1; }else if ( (lc2.get_scores().get_score() - lc1.get_scores().get_score()) < -1.0e-10){ result = -1; } return result; } } ); } public ObjectNode lcToNode(LogicCircuit lc) { ObjectMapper mapper = new ObjectMapper(); ObjectNode node = mapper.valueToTree(lc); return node; } public String objToJSONString(Object o) { Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).setPrettyPrinting().create(); //Gson gson = new GsonBuilder().setPrettyPrinting().create(); String json = gson.toJson(o); return json.toString(); } public void objToJSON(Object o, String filename) { ObjectMapper mapper = new ObjectMapper(); try { mapper.writerWithDefaultPrettyPrinter().writeValue(new File(_options.get_home() + "/src/test/resources/"+filename), o); } catch (JsonGenerationException e) { e.printStackTrace(); } catch (JsonMappingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public LogicCircuit lcJSONToObj(GateLibrary gate_library) { GsonBuilder gson_builder = new GsonBuilder(); try { java.io.BufferedReader br = new java.io.BufferedReader( new java.io.FileReader(_options.get_home() + "/src/test/resources/circuit.json")); //convert the json string back to object LogicCircuit obj = gson_builder.create().fromJson(br, LogicCircuit.class); obj.reconnectCircuitByIndexes(); LogicCircuit lc = new LogicCircuit(obj); Evaluate.simulateLogic(lc); Evaluate.evaluateCircuit(lc, gate_library, _options); return lc; } catch (IOException e) { e.printStackTrace(); } return null; } public GateLibrary glJSONToObj() { GsonBuilder gson_builder = new GsonBuilder(); try { java.io.BufferedReader br = new java.io.BufferedReader( new java.io.FileReader(_options.get_home() + "/src/test/resources/gate_library.json")); //convert the json string back to object GateLibrary obj = gson_builder.create().fromJson(br, GateLibrary.class); return obj; } catch (IOException e) { e.printStackTrace(); } return null; } ///////////////////////// // // Private member data // ///////////////////////// private String _username = ""; @Getter @Setter private ArrayList<Assignment> _assignments = new ArrayList<>(); @Getter @Setter private LogicCircuit _abstract_lc = new LogicCircuit(); @Getter @Setter private ArrayList<LogicCircuit> _logic_circuits = new ArrayList<>(); @Getter @Setter private ResultStatus _result_status; @Getter private final Args _options = new Args(); private UCFAdaptor ucfAdaptor = new UCFAdaptor(); private UCFReader ucfReader = new UCFReader(); private UCFValidator ucfValidator = new UCFValidator(); private String threadDependentLoggername = String.valueOf(UUID.randomUUID()); private Logger logger; private Gson gson = new GsonBuilder().setPrettyPrinting().create(); }