/// <summary> /// Parses a list of file-lines, line by line, for parameter data /// Generally, expected to be called first in file parsing /// Parameter data is used in subsequent sections of the BNGL file /// </summary> /// <param name="info"> The strings (file lines) to parse for data</param> /// <param name="fdata"> The BNGL File data object that holds parsed data</param> /// <returns>0(int) for successfull completion</returns> private int ParseParameters(List <string> info, BNGLFileData fdata) { foreach (string p in info) { string[] p_arr = p.Split( new[] { " " }, StringSplitOptions.RemoveEmptyEntries); if (p_arr.Length != 2) { Debug.LogError(String.Format("{0} Parameter has too many or too few arguments.\n{1}", fileErrorMsg, p)); return(-1); } float num = 0; bool isNum = float.TryParse(p_arr[1], out num); if (isNum) // a number was assigned as a parameter value { fdata.parameters.Add(p_arr[0], num); } else // an equation (with parameters) was defined as a parameter value { num = MathParser.Evaluate(p_arr[1], fdata.parameters); fdata.parameters.Add(p_arr[0], num); } } return(0); }
private void ConstructEngineObjects(BNGLFileData fdata) { //@TODO // This is where a 1-1 mapping of BNGL data to unity objects would happen // e.g. constructing complex snapshots from ComplexFileData objects Debug.LogWarning("Converting BNGL objects to Unity Engine Objects is currently unimplemented"); }
/// <summary> /// Parses a list of file-lines, line by line, for molecule type data /// Generally, expected to be called second in file parsing /// Molecule types describe the allowed states of molecule binding-sites in the simulation /// </summary> /// <param name="info"> The strings (file lines) to parse for data</param> /// <param name="fdata"> The BNGL File data object that holds parsed data</param> /// <returns>0(int) for successfull completion</returns> private int ParseMoleculeTypes(List <string> info, BNGLFileData fdata) { // parse each molecule line-by-line foreach (string s in info) { for (int i = 0; i < info.Count; ++i) { string line = info[i]; MoleculeFileData md = ParseMolecule(line); fdata.molecules.Add(md); } } return(0); }
/// <summary> /// Parses a list of file-lines, line by line, for seed species data /// Generally, expected to be called third in file parsing /// Seed species are species present at the beginning of the simulation /// </summary> /// <param name="info"> The strings (file lines) to parse for data</param> /// <param name="fdata"> The BNGL File data object that holds parsed data</param> /// <returns>0(int) for successfull completion</returns> private int ParseSeedSpecies(List <string> info, BNGLFileData fdata) { foreach (string s in info) { int rp = s.IndexOf(")"); // assuming the following layout: // [molecule]"(" [binding-sites] ")" [numerical value] ComplexFileData cd = ParseComplex(s.Substring(0, rp + 1)); string iv_string = s.Substring(rp + 1).Trim(); // Check that a value was specified for the seed species if (String.IsNullOrEmpty(iv_string)) { Debug.LogError(String.Format("{0} Seed Species is missing a value.\n{1}", fileErrorMsg, s)); return(-1); } SeedSpeciesFileData ssd = new SeedSpeciesFileData(); ssd.complex = cd; float n = 0; bool isNum = float.TryParse(iv_string, out n); if (isNum) // A number was specified as the initial value for this seed species { ssd.initialValue = n; } else // A parameter was specified as the initial value for this seed species { // Check that the specified parameter was specified and parsed if (!fdata.parameters.ContainsKey(iv_string)) { Debug.LogError(String.Format("{0} A Seed Species referenced an undefined parameter.\n{1}", fileErrorMsg, s)); return(-1); } ssd.initialValue = fdata.parameters[iv_string]; } fdata.seedSpecies.Add(ssd); } return(0); }
/// <summary> /// Parses a list of file-lines, line by line, for observables data /// Generally, expected to be called fourth in file parsing /// Observables are quantities of interest that are measured (observed) at regular intervals /// </summary> /// <param name="info"> The strings (file lines) to parse for data</param> /// <param name="fdata"> The BNGL File data object that holds parsed data</param> /// <returns>0(int) for successfull completion</returns> private int ParseObservables(List <string> info, BNGLFileData fdata) { foreach (string s in info) { string tmp = s; if (Regex.IsMatch(tmp, @"^\d+")) // Check if this line starts with a number { tmp = s.Substring(s.IndexOf(" ")).Trim(); // index # will be delimited by space } string[] toParse = tmp.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries); ObservableFileData od = new ObservableFileData(); od.metricName = toParse[1]; od.complexOfInterest = ParseComplex(toParse[2]); fdata.observables.Add(od); } return(0); }
/// <summary> /// Parse a file's contents for keywords (words that signify the type of parsing needed) /// e.g. "molecule type" -> Molecule specific parsing /// </summary> /// <param name="file_contents"> A string containing the contents of a local file read into memory</param> private void ParseForKeywords(string file_contents, out BNGLFileData fdata) { fdata = new BNGLFileData(); // Divide the string by new lines string[] file_lines = file_contents.Split( new[] { "\r\n", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries); Queue <int> begin_indicies = new Queue <int>(); Queue <int> end_indicies = new Queue <int>(); Queue <string> keywords = new Queue <string>(); for (int i = 0; i < file_lines.Length; ++i) { // Check if this line is a comment if (file_lines[i].StartsWith(commentSymbol)) { continue; } // Record the indicies of the begin and end statements // Record relevant keywords attached to begin statements if (file_lines[i].StartsWith("begin")) { begin_indicies.Enqueue(i); keywords.Enqueue(file_lines[i].Substring(5)); continue; } if (file_lines[i].StartsWith("end")) { end_indicies.Enqueue(i); continue; } } // Validity checks if (begin_indicies.Count != end_indicies.Count) { Debug.LogError(String.Format("{0} the number of begin statments does not equal the number of end statements", fileErrorMsg)); return; } if (begin_indicies.Count != keywords.Count) { Debug.LogError(String.Format("{0} the number of begin statments does not equal the number of keywords", fileErrorMsg)); return; } // Divide the document into info-blocks and parse accordingly while (begin_indicies.Count > 0) { int begin = begin_indicies.Dequeue(); int end = end_indicies.Dequeue(); List <string> info = new List <string>(); string key = keywords.Dequeue().Trim().ToLower(); for (int j = begin + 1; j < end; ++j) // ignore the lines with 'begin' or 'end' { // Check for comment lines string currentLine = file_lines[j]; if (currentLine.Contains(commentSymbol)) { currentLine = currentLine.Substring(0, currentLine.IndexOf(commentSymbol)); // remove comments from file line } // Check for empty or null lines currentLine = currentLine.Trim(); if (string.IsNullOrEmpty(currentLine)) { continue; } // Check for the line continuation character while (currentLine.EndsWith(@"\") && j < (end - 1)) { j++; // remove the continuation character and append the next line currentLine = currentLine.Substring(0, currentLine.Length - 1) + file_lines[j]; } // If the line isn't a comment line, empty, or null, add the line to the parseable info info.Add(currentLine); } // If the keyword matches one of the defined symbols, call the needed parse-helper function if (symbols.ContainsKey(key)) { symbols[key].DynamicInvoke(info, fdata); } else { // Keyword not found in the known parsing keywords Debug.LogWarning(String.Format("{0} Unrecognized keyword in file.\n{1}", fileErrorMsg, key)); } } }
// Not needed for Unity Simulation Prototype at this moment private int ParseActions(List <string> info, BNGLFileData fdata) { Debug.LogWarning("Parsing actions is currently unimplemented. The actions defined in this BNGL file have been ignored."); return(-1); }
/// <summary> /// Parses a list of file-lines, line by line, for reaction rules data /// Generally, expected to be called fifth in file parsing /// Reaction Rules are a text equation that describe how molecules can interact /// </summary> /// <param name="info"> The strings (file lines) to parse for data</param> /// <param name="fdata"> The BNGL File data object that holds parsed data</param> /// <returns>0(int) for successfull completion</returns> private int ParseReactionRules(List <string> info, BNGLFileData fdata) { foreach (string s in info) { ReactionRulesFileData rd = new ReactionRulesFileData(); string tmp = s; if (Regex.IsMatch(tmp, @"^\d+")) // Check if this line starts with a number { tmp = s.Substring(s.IndexOf(" ")).Trim(); // index # will be delimited by space } // find keywords in reation def string int r_end = tmp.LastIndexOf(")"); // find the end of the last product (the end of the reaction def) string keywords = tmp.Substring(r_end + 1); // remove keywords from reaction def string tmp = tmp.Substring(0, r_end + 1); // parse keywords string[] keywords_arr = keywords.Split(new[] { " ", "," }, StringSplitOptions.RemoveEmptyEntries); foreach (string k in keywords_arr) { rd.keywords.Add(k.Trim()); } // Check if the reaction can occur in both directions if (tmp.Contains("<->")) { rd.isBidirectional = true; } // Copy the entire reaction into the description rd.description = tmp; // Find the indicies needed to split the string into reactants and products int productStart = tmp.IndexOf(">"); int reactantEnd = tmp.IndexOf("-"); if (tmp.Contains("<")) { reactantEnd = tmp.IndexOf("<"); } // Parse products and reactants string rs = tmp.Substring(0, reactantEnd); string ps = tmp.Substring(productStart + 1); string[] reactants = rs.Split(new[] { " + " }, StringSplitOptions.RemoveEmptyEntries); string[] products = ps.Split(new[] { " + " }, StringSplitOptions.RemoveEmptyEntries); foreach (string r in reactants) { rd.Reactants.Add(ParseComplex(r)); } foreach (string p in products) { rd.Products.Add(ParseComplex(p)); } } return(0); }