Merge branch 'master' of mus.cacr.caltech.edu:htsworkflow
authorDiane Trout <diane@caltech.edu>
Fri, 13 Apr 2012 17:57:18 +0000 (10:57 -0700)
committerDiane Trout <diane@caltech.edu>
Fri, 13 Apr 2012 17:57:18 +0000 (10:57 -0700)
57 files changed:
.gitignore
encode_submission/dt-overrides.turtle
encode_submission/encode_find.py
encode_submission/geo_gather.py [new file with mode: 0644]
encode_submission/submission_report.py [new file with mode: 0644]
encode_submission/test_encode_find.py
encode_submission/ucsc_gather.py
htsworkflow/frontend/experiments/fixtures/test_flowcells.json
htsworkflow/frontend/experiments/models.py
htsworkflow/frontend/samples/fixtures/initial_data.json
htsworkflow/frontend/samples/models.py
htsworkflow/frontend/templates/sample_header.html
htsworkflow/pipelines/desplit_fastq.py [new file with mode: 0644]
htsworkflow/pipelines/qseq2fastq.py
htsworkflow/pipelines/retrieve_config.py
htsworkflow/pipelines/runfolder.py
htsworkflow/pipelines/sequences.py
htsworkflow/pipelines/srf.py
htsworkflow/pipelines/summary.py
htsworkflow/pipelines/test/simulate_runfolder.py
htsworkflow/pipelines/test/test_qseq2fastq.py [deleted file]
htsworkflow/pipelines/test/test_retrive_config.py
htsworkflow/pipelines/test/test_runfolder_rta1_12.py [new file with mode: 0644]
htsworkflow/pipelines/test/test_sequences.py
htsworkflow/pipelines/test/test_summary.py [new file with mode: 0644]
htsworkflow/pipelines/test/testdata/aligned_config_1_12.xml [new file with mode: 0644]
htsworkflow/pipelines/test/testdata/demultiplex_1.12.4.2.xml [new file with mode: 0644]
htsworkflow/pipelines/test/testdata/demultiplexed_bustard_1.12.4.2.xml [new file with mode: 0644]
htsworkflow/pipelines/test/testdata/demultiplexed_summary_1.12.4.2.xml [new file with mode: 0644]
htsworkflow/pipelines/test/testdata/rta_basecalls_config_1.12.4.2.xml [new file with mode: 0755]
htsworkflow/pipelines/test/testdata/rta_intensities_config_1.12.4.2.xml [new file with mode: 0755]
htsworkflow/pipelines/test/testdata/sample_summary_1_12.htm [new file with mode: 0644]
htsworkflow/settings.py
htsworkflow/submission/condorfastq.py
htsworkflow/submission/daf.py
htsworkflow/submission/geo.py [new file with mode: 0644]
htsworkflow/submission/results.py [new file with mode: 0644]
htsworkflow/submission/submission.py [new file with mode: 0644]
htsworkflow/submission/test/__init__.py [new file with mode: 0644]
htsworkflow/submission/test/test_condorfastq.py [new file with mode: 0644]
htsworkflow/submission/test/test_daf.py
htsworkflow/submission/test/test_results.py [new file with mode: 0644]
htsworkflow/submission/test/test_ucsc.py
htsworkflow/submission/ucsc.py
htsworkflow/templates/__init__.py [new file with mode: 0644]
htsworkflow/templates/geo_submission.soft [new file with mode: 0644]
htsworkflow/templates/geo_submission.sparql [new file with mode: 0644]
htsworkflow/templates/qseq.condor [new file with mode: 0644]
htsworkflow/templates/split_fastq.condor [new file with mode: 0644]
htsworkflow/templates/srf.condor [new file with mode: 0644]
htsworkflow/util/api.py
htsworkflow/util/conversion.py
htsworkflow/util/rdfhelp.py
htsworkflow/util/test/test_conversion.py [new file with mode: 0644]
scripts/htsw-runfolder
scripts/htsw-update-archive
templates/config_form.html [deleted file]

index 190a7eb4eabd3d7b26b1bb101c62b30485576401..f766e367363debc6965984b4a77442da280e2348 100644 (file)
@@ -1,6 +1,7 @@
 *~
 *.py[co]
 .coverage
+*,cover
 *.egg-info
 .noseids
 .ropeproject
index ffe27591399c7abdd9d006dff7223240185f73ee..c8127773e85fdaecc1e8bf1916154eb1a5576884 100644 (file)
@@ -61,7 +61,7 @@
 
 # woldlab jun 18 1x75-Directional-H1-hESC-Rep1
 <http://encodesubmit.ucsc.edu/pipeline/show/1633>
-    ucscSubmission:library_urn <http://jumpgate.caltech.edu/library/10947> .
+    ucscSubmission:library_urn <http://jumpgate.caltech.edu/library/10947/> .
 
 # woldlab jun 18 1x75-Directional-HeLa-Rep1
 <http://encodesubmit.ucsc.edu/pipeline/show/1634>
index 6608a05de61154713d9e47bd8ab37b71424c520d..24ed16872cf7654d25cd40f5b0ad977976512e52 100644 (file)
@@ -44,7 +44,7 @@ LIBRARY_NS = RDF.NS("http://jumpgate.caltech.edu/library/")
 from htsworkflow.submission.ucsc import \
      daf_download_url, \
      ddf_download_url, \
-     get_ucsc_file_index, \
+     get_encodedcc_file_index, \
      submission_view_url, \
      UCSCEncodePipeline
 
@@ -60,8 +60,10 @@ USER_URL = 'http://encodesubmit.ucsc.edu/pipeline/show_user'
 USERNAME = 'detrout'
 CHARSET = 'utf-8'
 
-GOLDEN_PATH_TEST = "http://hgdownload-test.cse.ucsc.edu/goldenPath/"\
-                   "{genome}/encodeDCC/{composite}/"
+SL_MAP = {'SL2970': '02970',
+          'SL2971': '02971',
+          'SL2973': '02973',}
+
 def main(cmdline=None):
     """
     Parse command line arguments
@@ -76,12 +78,14 @@ def main(cmdline=None):
         logging.basicConfig(level=logging.DEBUG)
     elif opts.verbose:
         logging.basicConfig(level=logging.INFO)
+    else:
+        logging.basicConfig(level=logging.ERROR)
 
     htsw_authdata = api.make_auth_from_opts(opts, parser)
     htswapi = api.HtswApi(opts.host, htsw_authdata)
 
     cookie = None
-    model = get_model(opts.load_model, DBDIR)
+    model = get_model(opts.model, DBDIR)
 
     if opts.load_rdf is not None:
         ns_uri = submissionOntology[''].uri
@@ -92,25 +96,38 @@ def main(cmdline=None):
     else:
         limit = args
 
+    if opts.reload_libraries:
+        reload_libraries(model, args)
+        return
+
     if opts.update:
+        opts.update_submission = True
+        opts.update_libraries = True
+        opts.update_ucsc_downloads = True
+
+    if opts.update_submission:
         cookie = login(cookie=cookie)
         load_my_submissions(model, limit=limit, cookie=cookie)
-        load_encode_libraries(model, htswapi)
+
+    if opts.update_libraries:
+        load_encode_assigned_libraries(model, htswapi)
+        load_unassigned_submitted_libraries(model)
+
+    if opts.update_ucsc_downloads:
         our_tracks = [
             {'genome':'hg19', 'composite':'wgEncodeCaltechRnaSeq'},
             {'genome':'mm9',  'composite':'wgEncodeCaltechHist'},
-            {'genome':'mm9',  'composite':'wgEncodeCaltechHistone'},
+            #{'genome':'mm9',  'composite':'wgEncodeCaltechHistone'},
             {'genome':'mm9',  'composite':'wgEncodeCaltechTfbs'}
         ]
         for track_info in our_tracks:
-            load_encodedcc_files(model, GOLDEN_PATH_TEST.format(**track_info))
-
+            load_encodedcc_files(model, **track_info )
 
     if opts.sparql is not None:
         sparql_query(model, opts.sparql)
 
     if opts.find_submission_with_no_library:
-        find_submissions_with_no_library(model)
+        report_submissions_with_no_library(model)
 
     if opts.print_rdf:
         serializer = get_serializer(name=opts.rdf_parser_name)
@@ -122,21 +139,27 @@ def make_parser():
     """
     parser = OptionParser()
     commands = OptionGroup(parser, "Commands")
-    commands.add_option('--load-model', default=None,
+    commands.add_option('--model', default=None,
       help="Load model database")
     commands.add_option('--load-rdf', default=None,
       help="load rdf statements into model")
     commands.add_option('--print-rdf', action="store_true", default=False,
       help="print ending model state")
     commands.add_option('--update', action="store_true", default=False,
-      help="Query remote data sources and update our database")
-    #commands.add_option('--update-ucsc-status', default=None,
-    #  help="download status from ucsc, requires filename for extra rules")
-    #commands.add_option('--update-ddfs', action="store_true", default=False,
-    #  help="download ddf information for known submission")
-    #commands.add_option('--update-library', default=None,
-    #  help="download library info from htsw, "\
-    #       "requires filename for extra rules")
+      help="Do all updates")
+    commands.add_option('--update-submission', action="store_true",
+                        default=False,
+      help="download status from ucsc")
+    commands.add_option('--update-ucsc-downloads', action="store_true",
+                        default=False,
+      help="Update download locations from UCSC")
+    commands.add_option('--update-libraries', action="store_true",
+                        default=False,
+      help="download library info from htsw")
+    commands.add_option('--reload-libraries', action="store_true",
+                        default=False,
+                        help="Delete and redownload library information. "\
+                             "Optionally list specific library IDs.")
     parser.add_option_group(commands)
 
     queries = OptionGroup(parser, "Queries")
@@ -234,6 +257,17 @@ def add_submission_to_library_urn(model, submissionUrn, predicate, library_id):
         LOGGER.debug("Found: {0}".format(str(query)))
 
 
+def report_submissions_with_no_library(model):
+    missing = find_submissions_with_no_library(model)
+    for row in results:
+        subid = row['subid']
+        name = row['name']
+        print "# {0}".format(name)
+        print "<{0}>".format(subid.uri)
+        print "  encodeSubmit:library_urn "\
+              "<http://jumpgate.caltech.edu/library/> ."
+        print ""
+
 def find_submissions_with_no_library(model):
     missing_lib_query_text = """
 PREFIX submissionOntology:<{submissionOntology}>
@@ -247,15 +281,39 @@ WHERE {{
 }}""".format(submissionOntology=submissionOntology[''].uri)
     missing_lib_query = RDF.SPARQLQuery(missing_lib_query_text)
 
-    results = missing_lib_query.execute(model)
-    for row in results:
-        subid = row['subid']
-        name = row['name']
-        print "# {0}".format(name)
-        print "<{0}>".format(subid.uri)
-        print "  encodeSubmit:library_urn "\
-              "<http://jumpgate.caltech.edu/library/> ."
-        print ""
+    return missing_lib_query.execute(model)
+
+
+def find_unscanned_submitted_libraries(model):
+    """Scan model for libraries that don't have library details loaded
+    """
+    unscanned_libraries = """
+PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX submissionOntology:<{submissionOntology}>
+
+SELECT distinct ?submission ?library_urn
+WHERE {{
+  ?submission submissionOntology:library_urn ?library_urn .
+  OPTIONAL {{ ?library_urn rdf:type ?library_type  }}
+  FILTER(!BOUND(?library_type))
+}}""".format(submissionOntology=submissionOntology[''].uri)
+    query = RDF.SPARQLQuery(unscanned_libraries)
+    return query.execute(model)
+
+def find_all_libraries(model):
+    """Scan model for every library marked as
+    """
+    libraries = """
+PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
+PREFIX libraryOntology:<{libraryOntology}>
+
+SELECT distinct ?library_urn
+WHERE {{
+  ?library_urn rdf:type ?library_type .
+  FILTER(regex(?libray
+}}""".format(libraryOntology=libraryOntology[''].uri)
+    query = RDF.SPARQLQuery(libraries)
+    return query.execute(model)
 
 
 def add_submission_creation_date(model, subUrn, cookie):
@@ -264,15 +322,17 @@ def add_submission_creation_date(model, subUrn, cookie):
     if len(creation_dates) == 0:
         LOGGER.info("Getting creation date for: {0}".format(str(subUrn)))
         submissionTree = get_url_as_tree(str(subUrn), 'GET', cookie)
-        parse_submission_page(model, cells, subUrn)
+        parse_submission_page(model, submissionTree, subUrn)
     else:
         LOGGER.debug("Found creation date for: {0}".format(str(subUrn)))
 
+
 def get_creation_dates(model, subUrn):
     query = RDF.Statement(subUrn, CREATION_DATE, None)
     creation_dates = list(model.find_statements(query))
     return creation_dates
 
+
 def parse_submission_page(model, submissionTree, subUrn):
     cells = submissionTree.findall('.//td')
     dateTimeType = xsdNS['dateTime']
@@ -384,7 +444,7 @@ def add_ddf_statements(model, statusNode, ddf_string):
                 add_stmt(model, fileNode, predicate, object)
 
 
-def load_encode_libraries(model, htswapi):
+def load_encode_assigned_libraries(model, htswapi):
     """Get libraries associated with encode.
     """
     encodeFilters = ["/library/?affiliations__id__exact=44",
@@ -400,22 +460,91 @@ def load_encode_libraries(model, htswapi):
         libraries = model.find_statements(query)
         for statement in libraries:
             libraryUrn = statement.subject
-            LOGGER.info("Scanning {0}".format(str(libraryUrn)))
             load_library_detail(model, libraryUrn)
 
 
-def load_encodedcc_files(model, base_url):
-    if base_url[-1] != '/':
-        base_url += '/'
+def load_unassigned_submitted_libraries(model):
+    unassigned = find_unscanned_submitted_libraries(model)
+    for query_record in unassigned:
+        library_urn = query_record['library_urn']
+        LOGGER.warn("Unassigned, submitted library: {0}".format(library_urn))
+        load_library_detail(model, library_urn)
+
+def reload_libraries(model, library_list):
+    if len(library_list) == 0:
+        # reload everything.
+        queryset = find_all_libraries(model)
+        libraries = ( str(s['library_urn']) for s in queryset )
+    else:
+        libraries = ( user_library_id_to_library_urn(l) for l in library_list )
+
+    for library_urn in libraries:
+        delete_library(model, library_urn)
+        load_library_detail(model, library_urn)
+
+def user_library_id_to_library_urn(library_id):
+    split_url = urlparse.urlsplit(library_id)
+    if len(split_url.scheme) == 0:
+        return LIBRARY_NS[library_id]
+    else:
+        return library_id
+
+def delete_library(model, library_urn):
+    if not isinstance(library_urn, RDF.Node):
+        raise ValueError("library urn must be a RDF.Node")
+
+    LOGGER.info("Deleting {0}".format(str(library_urn.uri)))
+    lane_query = RDF.Statement(library_urn, libraryOntology['has_lane'],None)
+    for lane in model.find_statements(lane_query):
+        delete_lane(model, lane.object)
+    library_attrib_query = RDF.Statement(library_urn, None, None)
+    for library_attrib in model.find_statements(library_attrib_query):
+        LOGGER.debug("Deleting {0}".format(str(library_attrib)))
+        del model[library_attrib]
+
+
+def delete_lane(model, lane_urn):
+    if not isinstance(lane_urn, RDF.Node):
+        raise ValueError("lane urn must be a RDF.Node")
+
+    delete_lane_mapping(model, lane_urn)
+    lane_attrib_query = RDF.Statement(lane_urn,None,None)
+    for lane_attrib in model.find_statements(lane_attrib_query):
+        LOGGER.debug("Deleting {0}".format(str(lane_attrib)))
+        del model[lane_attrib]
+
+
+def delete_lane_mapping(model, lane_urn):
+    if not isinstance(lane_urn, RDF.Node):
+        raise ValueError("lane urn must be a RDF.Node")
+
+    lane_mapping_query = RDF.Statement(lane_urn,
+                                       libraryOntology['has_mappings'],
+                                       None)
+    for lane_mapping in model.find_statements(lane_mapping_query):
+        mapping_attrib_query = RDF.Statement(lane_mapping.object,
+                                             None,
+                                             None)
+        for mapping_attrib in model.find_statements(mapping_attrib_query):
+            LOGGER.debug("Deleting {0}".format(str(mapping_attrib)))
+            del model[mapping_attrib]
+
+
+def load_encodedcc_files(model, genome, composite):
+    file_index = ucsc.get_encodedcc_file_index(genome, composite)
+    if file_index is None:
+        return
 
-    file_index = ucsc.get_ucsc_file_index(base_url)
     for filename, attributes in file_index.items():
-        s = RDF.Node(RDF.Uri(base_url + filename))
+        s = RDF.Node(RDF.Uri(filename))
+        model.add_statement(
+            RDF.Statement(s, TYPE_N, submissionOntology['ucsc_track']))
         for name, value in attributes.items():
             p = RDF.Node(DCC_NS[name])
             o = RDF.Node(value)
             model.add_statement(RDF.Statement(s,p,o))
 
+
 def load_library_detail(model, libraryUrn):
     """Grab detail information from library page
     """
@@ -426,7 +555,11 @@ def load_library_detail(model, libraryUrn):
     LOGGER.debug(log_message.format(len(results), libraryUrn))
     if len(results) == 0:
         LOGGER.info("Loading {0}".format(str(libraryUrn)))
-        rdfaParser.parse_into_model(model, libraryUrn.uri)
+        try:
+            body = get_url_as_text(str(libraryUrn.uri), 'GET')
+            rdfaParser.parse_string_into_model(model, body, libraryUrn.uri)
+        except httplib2.HttpLib2ErrorWithResponse, e:
+            LOGGER.error(str(e))
     elif len(results) == 1:
         pass  # Assuming that a loaded dataset has one record
     else:
@@ -440,11 +573,15 @@ def get_library_id(name):
     '11039'
     >>> get_library_id('10150 C2C12-24h-myogenin-2PCR-Rep1.32mers')
     '10150'
+    >>> get_library_id('2x75-GM12892-rep2-SL2970')
+    '02970'
     """
     match = re.search(r"([ -]|^)(?P<id>([\d]{5})|(SL[\d]{4}))", name)
     library_id = None
     if match is not None:
         library_id = match.group('id')
+    if library_id in SL_MAP:
+        library_id = SL_MAP[library_id]
     return library_id
 
 
@@ -522,6 +659,7 @@ def get_url_as_tree(url, method, cookie=None):
         msg = "error accessing {0}, status {1}"
         msg = msg.format(url, response['status'])
         e = httplib2.HttpLib2ErrorWithResponse(msg, response, content)
+        raise e
 
 
 def get_url_as_text(url, method, cookie=None):
@@ -536,6 +674,7 @@ def get_url_as_text(url, method, cookie=None):
         msg = "error accessing {0}, status {1}"
         msg = msg.format(url, response['status'])
         e = httplib2.HttpLib2ErrorWithResponse(msg, response, content)
+        raise e
 
 ################
 #  old stuff
diff --git a/encode_submission/geo_gather.py b/encode_submission/geo_gather.py
new file mode 100644 (file)
index 0000000..9a1f51e
--- /dev/null
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+from ConfigParser import SafeConfigParser
+import fnmatch
+from glob import glob
+import json
+import logging
+import netrc
+from optparse import OptionParser, OptionGroup
+import os
+from pprint import pprint, pformat
+import shlex
+from StringIO import StringIO
+import stat
+import sys
+import time
+import types
+import urllib
+import urllib2
+import urlparse
+from zipfile import ZipFile
+
+import RDF
+
+if not 'DJANGO_SETTINGS_MODULE' in os.environ:
+    os.environ['DJANGO_SETTINGS_MODULE'] = 'htsworkflow.settings'
+
+
+from htsworkflow.util import api
+from htsworkflow.util.rdfhelp import \
+     dafTermOntology, \
+     fromTypedNode, \
+     get_model, \
+     get_serializer, \
+     load_into_model, \
+     sparql_query, \
+     submissionOntology
+from htsworkflow.submission.daf import get_submission_uri
+from htsworkflow.submission.results import ResultMap
+from htsworkflow.submission.geo import GEOSubmission
+from htsworkflow.submission.condorfastq import CondorFastqExtract
+
+logger = logging.getLogger(__name__)
+
+def main(cmdline=None):
+    parser = make_parser()
+    opts, args = parser.parse_args(cmdline)
+    submission_uri = None
+
+    if opts.debug:
+        logging.basicConfig(level = logging.DEBUG )
+    elif opts.verbose:
+        logging.basicConfig(level = logging.INFO )
+    else:
+        logging.basicConfig(level = logging.WARNING )
+
+    apidata = api.make_auth_from_opts(opts, parser)
+
+    model = get_model(opts.model, opts.db_path)
+    mapper = None
+    if opts.name:
+        mapper = GEOSubmission(opts.name,  model)
+        if opts.library_url is not None:
+            mapper.library_url = opts.library_url
+        submission_uri = get_submission_uri(opts.name)
+
+
+    if opts.load_rdf is not None:
+        if submission_uri is None:
+            parser.error("Please specify the submission name")
+        load_into_model(model, 'turtle', opts.load_rdf, submission_uri)
+
+    results = ResultMap()
+    for a in args:
+        results.add_results_from_file(a)
+
+    if opts.make_tree_from is not None:
+        results.make_tree_from(opts.make_tree_from)
+
+    if opts.fastq:
+        extractor = CondorFastqExtract(opts.host, apidata, opts.sequence,
+                                       force=opts.force)
+        extractor.create_scripts(results)
+
+    if opts.scan_submission:
+        mapper.scan_submission_dirs(results)
+
+    if opts.make_soft:
+        mapper.make_soft(results)
+
+    if opts.sparql:
+        sparql_query(model, opts.sparql)
+
+    if opts.print_rdf:
+        writer = get_serializer()
+        print writer.serialize_model_to_string(model)
+
+
+def make_parser():
+    parser = OptionParser()
+
+    model = OptionGroup(parser, 'model')
+    model.add_option('--name', help="Set submission name")
+    model.add_option('--db-path', default=None,
+                     help="set rdf database path")
+    model.add_option('--model', default=None,
+      help="Load model database")
+    model.add_option('--load-rdf', default=None,
+      help="load rdf statements into model")
+    model.add_option('--sparql', default=None, help="execute sparql query")
+    model.add_option('--print-rdf', action="store_true", default=False,
+      help="print ending model state")
+    parser.add_option_group(model)
+    # commands
+    commands = OptionGroup(parser, 'commands')
+    commands.add_option('--make-tree-from',
+                      help="create directories & link data files",
+                      default=None)
+    commands.add_option('--fastq', default=False, action="store_true",
+                        help="generate scripts for making fastq files")
+    commands.add_option('--scan-submission', default=False, action="store_true",
+                      help="Import metadata for submission into our model")
+    commands.add_option('--make-soft', help='make the soft file', default=False,
+                      action="store_true")
+
+    parser.add_option_group(commands)
+
+    parser.add_option('--force', default=False, action="store_true",
+                      help="Force regenerating fastqs")
+    parser.add_option('--daf', default=None, help='specify daf name')
+    parser.add_option('--library-url', default=None,
+                      help="specify an alternate source for library information")
+    # debugging
+    parser.add_option('--verbose', default=False, action="store_true",
+                      help='verbose logging')
+    parser.add_option('--debug', default=False, action="store_true",
+                      help='debug logging')
+
+    api.add_auth_options(parser)
+
+    return parser
+
+
+if __name__ == "__main__":
+    main()
diff --git a/encode_submission/submission_report.py b/encode_submission/submission_report.py
new file mode 100644 (file)
index 0000000..3f55479
--- /dev/null
@@ -0,0 +1,164 @@
+import argparse
+import RDF
+import jinja2
+from pprint import pprint
+
+from htsworkflow.util.rdfhelp import \
+     dafTermOntology, \
+     dublinCoreNS, \
+     get_model, \
+     get_serializer, \
+     sparql_query, \
+     submissionOntology, \
+     libraryOntology, \
+     load_into_model, \
+     rdfNS, \
+     rdfsNS, \
+     xsdNS
+TYPE_N = rdfNS['type']
+CREATION_DATE = libraryOntology['date']
+
+from encode_find import DBDIR
+
+DEFAULT_GENOME='hg19'
+DEFAULT_OUTPUT='/tmp/submission_report.html'
+
+def main(cmdline=None):
+    parser = make_parser()
+    args = parser.parse_args(cmdline)
+    model = get_model('encode', DBDIR)
+    report = what_have_we_done(model, genome=args.genome)
+    with open(DEFAULT_OUTPUT,'w') as stream:
+        stream.write(report)
+
+def make_parser():
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--genome', default=DEFAULT_GENOME,
+                        help='limit to one genome')
+    parser.add_argument('--output', default='/tmp/submission_report.html',
+                        help="specify where to write to write report")
+    return parser
+
+SUBMISSION_QUERY = """
+PREFIX xsd:<http://www.w3.org/2001/XMLSchema#>
+PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#>
+PREFIX ucscSubmission:<http://jumpgate.caltech.edu/wiki/UcscSubmissionOntology#>
+PREFIX libraryOntology:<http://jumpgate.caltech.edu/wiki/LibraryOntology#>
+PREFIX daf: <http://jumpgate.caltech.edu/wiki/UcscDaf#>
+PREFIX ddf: <http://encodesubmit.ucsc.edu/pipeline/download_ddf#>
+
+SELECT distinct ?assembly ?experiment ?library_urn ?library_name ?submission ?submission_status ?submission_name ?date
+WHERE {{
+  ?submission ucscSubmission:library_urn ?library_urn ;
+              ucscSubmission:has_status ?status ;
+              ucscSubmission:name ?submission_name ;
+              libraryOntology:date ?date .
+  ?status daf:assembly ?assembly ;
+          ucscSubmission:status ?submission_status .
+  OPTIONAL {{ ?library_urn libraryOntology:name ?library_name . }}
+  OPTIONAL {{ ?library_urn libraryOntology:experiment_type ?experiment . }}
+  FILTER(!regex(?submission_status, "revoked", "i"))
+  {assembly_filter}
+}}
+ORDER BY ?assembly ?experiment ?library_urn ?submission
+"""
+
+SUBMISSION_TEMPLATE = '''
+<html>
+<head>
+<style type="text/css">
+table { border-width: 0 0 1px 1px; border-style: solid; }
+th,td { border-width: 1px 1px 0 0; border-style: solid; margin: 0;}
+.library { font-size: 18pt; background-color: #EEF; }
+.submission { font-size: 12pt; background-color: #EFE;}
+</style>
+  <title>Submission report for {{ genome }}</title>
+</head>
+<body>
+<h1>Genome: {{ genome }}</h1>
+{% for experiment in libraries %}
+  <h2>{{ experiment }}</h2>
+  <table>
+    <thead>
+      <tr class="library">
+      <td>Library ID</td>
+      <td colspan="3">Library Name</td>
+      </tr>
+      <tr class="submission">
+      <td>Submission ID</td>
+      <td>Last Updated</td>
+      <td>Status</td>
+      <td>Submission name</td>
+      </tr>
+    </thead>
+    <tbody>
+      {% for liburn, records in libraries[experiment]|dictsort %}
+      <!-- {{ liburn }} -->
+      <tr class="library">
+        <td>
+          <a href="{{libraries[experiment][liburn].0.library_urn}}">
+            {{ libraries[experiment][liburn].0.library_urn | trim_rdf}}
+          </a>
+        </td>
+        <td colspan="3">{{ libraries[experiment][liburn].0.library_name }}</td>
+      </tr>
+      {% for record in records|sort %}
+      <tr class="submission">
+        <td><a href="{{record.submission}}">{{record.submission|trim_rdf}}</a></td>
+        <td>{{ record.date|timestamp_to_date }}</td>
+        <td>{{ record.submission_status }}</td>
+        <td>{{ record.submission_name }}</td>
+      </tr>
+      {% endfor %}
+    {% endfor %}
+    </tbody>
+  </table>
+{% endfor %}
+  </body>
+</html>
+'''
+
+def what_have_we_done(model, genome):
+    assembly_filter = ''
+    assembly_filter = 'FILTER(regex(?assembly, "{0}", "i"))'.format(genome)
+
+    query = SUBMISSION_QUERY.format(
+        assembly_filter=assembly_filter
+    )
+    compiled_query = RDF.SPARQLQuery(query)
+    submissions = compiled_query.execute(model)
+    libraries = group_by_library(submissions)
+    environment = jinja2.Environment()
+    environment.filters['trim_rdf'] = trim_rdf
+    environment.filters['timestamp_to_date'] = timestamp_to_date
+    template = environment.from_string(SUBMISSION_TEMPLATE)
+    return template.render(libraries=libraries,
+                           genome=genome)
+
+def group_by_library(submissions):
+    libraries = {}
+    for record in submissions:
+        urn = str(record['library_urn'].uri)
+        experiment = str(record['experiment'])
+        libraries.setdefault(experiment, {}).setdefault(urn, []).append(record)
+    return libraries
+
+def trim_rdf(value):
+    if value is None:
+        return
+    value = str(value)
+    if len(value) == 0:
+        return value
+    if value[-1] == '/':
+        value = value[:-1]
+    split_value = value.split('/')
+    if len(split_value) == 0:
+        return value
+    return split_value[-1]
+
+def timestamp_to_date(value):
+    datestamp, timestamp = str(value).split('T')
+    return datestamp
+
+if __name__ == "__main__":
+    main()
index 9beb10239d184cc6021bb5bd08e35c75e2cea978..cb6216711bb078caf9e880522b8f2c383ddfdf85 100644 (file)
@@ -44,6 +44,101 @@ class TestEncodeFind(unittest.TestCase):
         object_date = fromTypedNode(dates[0].object)
         self.assertEqual(object_date, datetime(2011,12,7,15,23,0))
 
+    def test_delete_simple_lane(self):
+        model = get_model()
+        parser = RDF.Parser(name='turtle')
+        parser.parse_string_into_model(model, '''@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix : <http://www.w3.org/1999/xhtml> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+@prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#> .
+
+<http://jumpgate.caltech.edu/lane/1232>
+    libns:flowcell <http://jumpgate.caltech.edu/flowcell/42JV5AAXX/> ;
+    libns:total_unique_locations 5789938 .
+
+''', 'http://jumpgate.caltech.edu/library/')
+        urn = RDF.Node(RDF.Uri('http://jumpgate.caltech.edu/lane/1232'))
+        encode_find.delete_lane(model, urn)
+        self.failUnlessEqual(len(model), 0)
+
+    def test_delete_lane_with_mapping(self):
+        model = get_model()
+        parser = RDF.Parser(name='turtle')
+        parser.parse_string_into_model(model, '''@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix : <http://www.w3.org/1999/xhtml> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+@prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#> .
+
+<http://jumpgate.caltech.edu/lane/1232>
+    libns:flowcell <http://jumpgate.caltech.edu/flowcell/42JV5AAXX/> ;
+    libns:has_mappings _:bnode110110 ;
+    libns:total_unique_locations 5789938 .
+
+_:bnode110110
+    libns:mapped_to "newcontam_UK.fa"@en ;
+    libns:reads 42473 .
+''', 'http://jumpgate.caltech.edu/library/')
+        self.failUnlessEqual(len(model), 5)
+        urn = RDF.Node(RDF.Uri('http://jumpgate.caltech.edu/lane/1232'))
+        encode_find.delete_lane(model, urn)
+        self.failUnlessEqual(len(model), 0)
+
+    def test_delete_library(self):
+        model = get_model()
+        parser = RDF.Parser(name='turtle')
+        parser.parse_string_into_model(model, '''@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
+@prefix : <http://www.w3.org/1999/xhtml> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+@prefix libns: <http://jumpgate.caltech.edu/wiki/LibraryOntology#> .
+
+<http://jumpgate.caltech.edu/lane/1232>
+    libns:flowcell <http://jumpgate.caltech.edu/flowcell/42JV5AAXX/> ;
+    libns:has_mappings _:bnode110110 ;
+    libns:total_unique_locations 5789938 .
+
+<http://jumpgate.caltech.edu/library/11011/>
+    libns:affiliation "ENCODE"@en, "ENCODE_Tier1"@en, "Georgi Marinov"@en ;
+    libns:has_lane <http://jumpgate.caltech.edu/lane/1232> ;
+    libns:library_id "11011"@en ;
+    libns:library_type "None"@en ;
+    a "libns:library"@en ;
+    <http://www.w3.org/1999/xhtml/vocab#stylesheet> <http://jumpgate.caltech.edu/static/css/app.css>, <http://jumpgate.caltech.edu/static/css/data-browse-index.css> .
+
+_:bnode110110
+    libns:mapped_to "newcontam_UK.fa"@en ;
+    libns:reads 42473 .
+
+<http://jumpgate.caltech.edu/lane/1903>
+    libns:flowcell <http://jumpgate.caltech.edu/flowcell/62WCKAAXX/> ;
+    libns:has_mappings _:bnode120970 ;
+    libns:total_unique_locations 39172114 .
+
+<http://jumpgate.caltech.edu/library/12097/>
+    libns:has_lane <http://jumpgate.caltech.edu/lane/1903> ;
+    libns:library_id "12097"@en ;
+    libns:library_type "Paired End (non-multiplexed)"@en ;
+    a "libns:library"@en .
+
+_:bnode120970
+    libns:mapped_to "newcontam_UK.fa"@en ;
+    libns:reads 64 .
+''', 'http://jumpgate.caltech.edu/library')
+        urn = RDF.Node(RDF.Uri('http://jumpgate.caltech.edu/library/11011/'))
+        encode_find.delete_library(model, urn)
+        q = RDF.Statement(None, encode_find.libraryOntology['reads'], None)
+        stmts = list(model.find_statements(q))
+        self.failUnlessEqual(len(stmts), 1)
+        self.failUnlessEqual(fromTypedNode(stmts[0].object),
+                             64)
+
+        q = RDF.Statement(None, encode_find.libraryOntology['library_id'], None)
+        stmts = list(model.find_statements(q))
+        self.failUnlessEqual(len(stmts), 1)
+        self.failUnlessEqual(fromTypedNode(stmts[0].object),
+                             '12097')
 
 def suite():
     return unittest.makeSuite(TestEncodeFind, "test")
index fd8db12ebb87cd6769ed895f065aa5e03131c765..1cdf0118f6f990943adec84ab90492be44f360fe 100644 (file)
@@ -17,6 +17,7 @@ import types
 import urllib
 import urllib2
 import urlparse
+from zipfile import ZipFile
 
 import RDF
 
@@ -30,9 +31,10 @@ from htsworkflow.util.rdfhelp import \
      sparql_query, \
      submissionOntology
 from htsworkflow.submission.daf import \
-     DAFMapper, \
+     UCSCSubmission, \
      MetadataLookupException, \
      get_submission_uri
+from htsworkflow.submission.results import ResultMap
 from htsworkflow.submission.condorfastq import CondorFastqExtract
 
 logger = logging.getLogger('ucsc_gather')
@@ -51,9 +53,10 @@ def main(cmdline=None):
 
     apidata = api.make_auth_from_opts(opts, parser)
 
-    model = get_model(opts.load_model)
+    model = get_model(opts.model, opts.db_path)
+    mapper = None
     if opts.name:
-        mapper = DAFMapper(opts.name, opts.daf,  model)
+        mapper = UCSCSubmssion(opts.name, opts.daf,  model)
         if opts.library_url is not None:
             mapper.library_url = opts.library_url
         submission_uri = get_submission_uri(opts.name)
@@ -67,28 +70,33 @@ def main(cmdline=None):
     if opts.make_ddf and opts.daf is None:
         parser.error("Please specify your daf when making ddf files")
 
-    library_result_map = []
+    results = ResultMap()
     for a in args:
-        library_result_map.extend(read_library_result_map(a))
+        results.add_results_from_file(a)
 
     if opts.make_tree_from is not None:
-        make_tree_from(opts.make_tree_from, library_result_map)
+        results.make_tree_from(opts.make_tree_from)
 
     if opts.link_daf:
-        if opts.daf is None:
-            parser.error("Please specify daf filename with --daf")
-        link_daf(opts.daf, library_result_map)
+        if mapper is None:
+            parser.error("Specify a submission model")
+        if mapper.daf is None:
+            parser.error("Please load a daf first")
+        mapper.link_daf(results)
 
     if opts.fastq:
         extractor = CondorFastqExtract(opts.host, apidata, opts.sequence,
                                        force=opts.force)
-        extractor.build_fastqs(library_result_map)
+        extractor.create_scripts(results)
 
     if opts.scan_submission:
-        scan_submission_dirs(mapper, library_result_map)
+        mapper.scan_submission_dirs(results)
 
     if opts.make_ddf:
-        make_all_ddfs(mapper, library_result_map, opts.daf, force=opts.force)
+        make_all_ddfs(mapper, results, opts.daf, force=opts.force)
+
+    if opts.zip_ddf:
+        zip_ddfs(mapper, results, opts.daf)
 
     if opts.sparql:
         sparql_query(model, opts.sparql)
@@ -103,7 +111,9 @@ def make_parser():
 
     model = OptionGroup(parser, 'model')
     model.add_option('--name', help="Set submission name")
-    model.add_option('--load-model', default=None,
+    model.add_option('--db-path', default=None,
+                     help="set rdf database path")
+    model.add_option('--model', default=None,
       help="Load model database")
     model.add_option('--load-rdf', default=None,
       help="load rdf statements into model")
@@ -124,6 +134,9 @@ def make_parser():
                         help="link daf into submission directories")
     commands.add_option('--make-ddf', help='make the ddfs', default=False,
                       action="store_true")
+    commands.add_option('--zip-ddf', default=False, action='store_true',
+                        help='zip up just the metadata')
+
     parser.add_option_group(commands)
 
     parser.add_option('--force', default=False, action="store_true",
@@ -141,52 +154,6 @@ def make_parser():
 
     return parser
 
-def make_tree_from(source_path, library_result_map):
-    """Create a tree using data files from source path.
-    """
-    for lib_id, lib_path in library_result_map:
-        if not os.path.exists(lib_path):
-            logger.info("Making dir {0}".format(lib_path))
-            os.mkdir(lib_path)
-        source_lib_dir = os.path.abspath(os.path.join(source_path, lib_path))
-        if os.path.exists(source_lib_dir):
-            pass
-        for filename in os.listdir(source_lib_dir):
-            source_pathname = os.path.join(source_lib_dir, filename)
-            target_pathname = os.path.join(lib_path, filename)
-            if not os.path.exists(source_pathname):
-                raise IOError("{0} does not exist".format(source_pathname))
-            if not os.path.exists(target_pathname):
-                os.symlink(source_pathname, target_pathname)
-                logger.info(
-                    'LINK {0} to {1}'.format(source_pathname, target_pathname))
-
-
-def link_daf(daf_path, library_result_map):
-    if not os.path.exists(daf_path):
-        raise RuntimeError("%s does not exist, how can I link to it?" % (daf_path,))
-
-    base_daf = os.path.basename(daf_path)
-
-    for lib_id, result_dir in library_result_map:
-        if not os.path.exists(result_dir):
-            raise RuntimeError("Couldn't find target directory %s" %(result_dir,))
-        submission_daf = os.path.join(result_dir, base_daf)
-        if not os.path.exists(submission_daf):
-            if not os.path.exists(daf_path):
-                raise RuntimeError("Couldn't find daf: %s" %(daf_path,))
-            os.link(daf_path, submission_daf)
-
-
-def scan_submission_dirs(view_map, library_result_map):
-    """Look through our submission directories and collect needed information
-    """
-    for lib_id, result_dir in library_result_map:
-        logger.info("Importing %s from %s" % (lib_id, result_dir))
-        try:
-            view_map.import_submission_dir(result_dir, lib_id)
-        except MetadataLookupException, e:
-            logger.error("Skipping %s: %s" % (lib_id, str(e)))
 
 def make_all_ddfs(view_map, library_result_map, daf_name, make_condor=True, force=False):
     dag_fragment = []
@@ -233,7 +200,7 @@ WHERE {
   OPTIONAL { ?library libraryOntology:library_id ?labExpId }
   OPTIONAL { ?library libraryOntology:library_id ?labVersion }
   OPTIONAL { ?library libraryOntology:replicate ?replicate }
-  OPTIONAL { ?library libraryOntology:condition ?treatment }
+  OPTIONAL { ?library libraryOntology:condition_term ?treatment }
   OPTIONAL { ?library ucscDaf:protocol ?protocol }
   OPTIONAL { ?library ucscDaf:readType ?readType }
   OPTIONAL { ?library ucscDaf:strain ?strain }
@@ -248,7 +215,7 @@ ORDER BY  ?submitView"""
         logger.error("Need name for %s" % (str(submissionNode)))
         return []
 
-    ddf_name = name + '.ddf'
+    ddf_name = make_ddf_name(name)
     if outdir is not None:
         outfile = os.path.join(outdir, ddf_name)
         output = open(outfile,'w')
@@ -310,23 +277,25 @@ ORDER BY  ?submitView"""
     return dag_fragments
 
 
-def read_library_result_map(filename):
-    """
-    Read a file that maps library id to result directory.
-    Does not support spaces in filenames.
-
-    For example:
-      10000 result/foo/bar
+def zip_ddfs(view_map, library_result_map, daf_name):
+    """zip up just the ddf & daf files
     """
-    stream = open(filename,'r')
+    rootdir = os.getcwd()
+    for lib_id, result_dir in library_result_map:
+        submissionNode = view_map.get_submission_node(result_dir)
+        nameNode = view_map.model.get_target(submissionNode,
+                                             submissionOntology['name'])
+        name = fromTypedNode(nameNode)
+        if name is None:
+            logger.error("Need name for %s" % (str(submissionNode)))
+            continue
 
-    results = []
-    for line in stream:
-        line = line.rstrip()
-        if not line.startswith('#') and len(line) > 0 :
-            library_id, result_dir = line.split()
-            results.append((library_id, result_dir))
-    return results
+        zip_name = '../{0}.zip'.format(lib_id)
+        os.chdir(os.path.join(rootdir, result_dir))
+        with ZipFile(zip_name, 'w') as stream:
+            stream.write(make_ddf_name(name))
+            stream.write(daf_name)
+        os.chdir(rootdir)
 
 
 def make_condor_archive_script(name, files, outdir=None):
@@ -417,24 +386,6 @@ def make_dag_fragment(ininame, archive_condor, upload_condor):
     return fragments
 
 
-def get_library_info(host, apidata, library_id):
-    url = api.library_url(host, library_id)
-    contents = api.retrieve_info(url, apidata)
-    return contents
-
-
-def make_submission_section(line_counter, files, attributes):
-    """
-    Create a section in the submission ini file
-    """
-    inifile = [ "[line%s]" % (line_counter,) ]
-    inifile += ["files=%s" % (",".join(files))]
-
-    for k,v in attributes.items():
-        inifile += ["%s=%s" % (k,v)]
-    return inifile
-
-
 def make_base_name(pathname):
     base = os.path.basename(pathname)
     name, ext = os.path.splitext(base)
index e6ad6e314f28d3bd8e31ba8e7c2954e3f8b9eeaa..63cf30bcab89bd77b788fd296140ba95e7f712f7 100644 (file)
             "antibody": null
         }
     },
+    {
+        "pk": "13044",
+        "model": "samples.library",
+        "fields": {
+            "ten_nM_dilution": false,
+            "gel_cut_size": 225,
+            "library_name": "Dual Indexed Test",
+            "creation_date": "2009-08-26",
+            "cell_line": null,
+            "library_species": 9,
+            "library_type": 9,
+            "multiplex_id": "N701-N501",
+            "made_by": "Lorian",
+            "affiliations": [
+                2
+            ],
+            "replicate": 1,
+            "condition": null,
+            "hidden": false,
+            "stopping_point": "2A",
+            "tags": [],
+            "made_for": "",
+            "amplified_from_sample": 11043,
+            "notes": "8/21/2009 11:57:54\tColor: Orange",
+            "undiluted_concentration": "22.4",
+            "successful_pM": null,
+            "experiment_type": 2,
+            "antibody": null
+        }
+    },
     {
         "pk": "11045",
         "model": "samples.library",
        "pM": "7"
        }
    },
+  {"pk": 1379,
+   "model": "experiments.lane",
+   "fields": {
+       "comment": "",
+       "library": "13044",
+       "cluster_estimate": 196000,
+       "flowcell": 151,
+       "lane_number": 4,
+       "pM": "7"
+       }
+   },
+
     {
         "pk": "11044",
         "model": "samples.library",
index c66a639cae0ab669ce52b3fb3b17e7b765930bbe..bd92eb4037269bf8a9e5c24ca70b2671057a1878 100644 (file)
@@ -28,7 +28,8 @@ RESCAN_DELAY = 1
 try:
     RESCAN_DELAY = int(settings.RESCAN_DELAY)
 except (ValueError, AttributeError):
-    logger.error("Missing or invalid settings.RESCAN_DELAY")
+    logger.error("Missing or invalid settings.RESCAN_DELAY, "\
+                 "defaulting to %s" % (RESCAN_DELAY,))
 
 RUN_STATUS_CHOICES = (
     (0, 'Sequencer running'), ##Solexa Data Pipeline Not Yet Started'),
index 2a5af14cfe328879b8d5edd0988c4cdd394f1488..76a221e029f920d1181b969017b4a273c61ca2ab 100644 (file)
         "is_paired_end": true
      }
   },
+  {
+     "model": "samples.LibraryType",
+     "pk": 9,
+     "fields": {
+        "name": "Dual Index Illumina",
+        "can_multiplex": true,
+        "is_paired_end": true
+     }
+  },
   {
      "model": "samples.ExperimentType",
      "pk": 1,
       "adapter_type": 5,
       "sequence": "CTTGTA"
     }
-  }
+  },
+  {"fields": {"adapter_type": 9,
+             "multiplex_id": "N501",
+             "sequence": "TAGATCGC"},
+  "model": "samples.multiplexindex",
+  "pk": 74
+  },
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N502",
+             "sequence": "CTCTCTAT"},
+  "model": "samples.multiplexindex",
+  "pk": 75},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N503",
+             "sequence": "TATCCTCT"},
+  "model": "samples.multiplexindex",
+  "pk": 76},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N504",
+             "sequence": "AGAGTAGA"},
+  "model": "samples.multiplexindex",
+  "pk": 77},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N505",
+             "sequence": "GTAAGGAG"},
+  "model": "samples.multiplexindex",
+  "pk": 78},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N506",
+             "sequence": "ACTGCATA"},
+  "model": "samples.multiplexindex",
+  "pk": 79},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N507",
+             "sequence": "AAGGAGTA"},
+  "model": "samples.multiplexindex",
+  "pk": 80},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N508",
+             "sequence": "CTAAGCCT"},
+  "model": "samples.multiplexindex",
+  "pk": 81},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N701",
+             "sequence": "TAAGGCGA"},
+  "model": "samples.multiplexindex",
+  "pk": 82},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N702",
+             "sequence": "CGTACTAG"},
+  "model": "samples.multiplexindex",
+  "pk": 83},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N703",
+             "sequence": "AGGCAGAA"},
+  "model": "samples.multiplexindex",
+  "pk": 84},
+ {"fields": {"adapter_type": 9, "multiplex_id": "N704", "sequence": "TCCTGA"},
+  "model": "samples.multiplexindex",
+  "pk": 85},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N705",
+             "sequence": "GGACTCCT"},
+  "model": "samples.multiplexindex",
+  "pk": 86},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N706",
+             "sequence": "TAGGCATG"},
+  "model": "samples.multiplexindex",
+  "pk": 87},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N707",
+             "sequence": "CTCTCTAC"},
+  "model": "samples.multiplexindex",
+  "pk": 88},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N708",
+             "sequence": "CAGAGAGG"},
+  "model": "samples.multiplexindex",
+  "pk": 89},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N709",
+             "sequence": "GCTACGCT"},
+  "model": "samples.multiplexindex",
+  "pk": 90},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N710",
+             "sequence": "CGAGGCTG"},
+  "model": "samples.multiplexindex",
+  "pk": 91},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N711",
+             "sequence": "AAGAGGCA"},
+  "model": "samples.multiplexindex",
+  "pk": 92},
+ {"fields": {"adapter_type": 9,
+             "multiplex_id": "N712",
+             "sequence": "GTAGAGGA"},
+  "model": "samples.multiplexindex",
+  "pk": 93}
 ]
index 2eeaaecbe3b3aa9d3fc4c651e9774c70b6e4e383..de6fc11dc3d1bb407e43011a59128f8b3f733a4b 100644 (file)
@@ -144,7 +144,7 @@ class LibraryType(models.Model):
 class MultiplexIndex(models.Model):
     """Map adapter types to the multiplex sequence"""
     adapter_type = models.ForeignKey(LibraryType)
-    multiplex_id = models.CharField(max_length=3, null=False)
+    multiplex_id = models.CharField(max_length=6, null=False)
     sequence = models.CharField(max_length=12, blank=True, null=True)
 
     class Meta:
@@ -244,23 +244,41 @@ class Library(models.Model):
       if self.multiplex_id is None or len(self.multiplex_id) == 0:
           return 'Err: id empty'
       sequences = {}
-      multiplex_ids = self.multiplex_id.split(',')
-      for multiplex_id in multiplex_ids:
-          try:
-              multiplex = MultiplexIndex.objects.get(
-                  adapter_type = self.library_type.id,
-                  multiplex_id = multiplex_id)
-              sequences[multiplex_id] = multiplex.sequence
-          except MultiplexIndex.DoesNotExist, e:
-              sequences[multiplex_id] = 'Err: index not found'
+      multiplex_expressions = self.multiplex_id.split(',')
+      for multiplex_term in multiplex_expressions:
+          pairs = multiplex_term.split('-')
+          if len(pairs) == 1:
+              key = pairs[0]
+              seq = self._lookup_index(pairs[0])
+          elif len(pairs) == 2:
+              key = pairs[0] + '-' + pairs[1]
+              seq0 = self._lookup_index(pairs[0])
+              seq1 = self._lookup_index(pairs[1])
+              if seq0 is None or seq1 is None:
+                  seq = None
+              else:
+                  seq = seq0 + '-' + seq1
+          else:
+              raise RuntimeError("Too many - seperated sequences")
+          if seq is None:
+              seq = 'Err: index not found'
+          sequences[key] = seq
       return sequences
 
+  def _lookup_index(self, multiplex_id):
+      try:
+          multiplex = MultiplexIndex.objects.get(
+              adapter_type = self.library_type.id,
+              multiplex_id = multiplex_id)
+          return multiplex.sequence
+      except MultiplexIndex.DoesNotExist, e:
+          return None
+
   def index_sequence_text(self, seperator=' '):
       """Return formatted multiplex index sequences"""
       sequences = self.index_sequences()
       if sequences is None:
           return ""
-
       multiplex_ids = sequences.keys()
       multiplex_ids.sort()
       return seperator.join(( "%s:%s" %(i,sequences[i]) for i in multiplex_ids))
index e3cbeb18ce1e1c04d7f2228503097fd9589024eb..217c31795c6363332e13ebc0b50820745a87572d 100644 (file)
@@ -4,7 +4,7 @@
     <b>Library ID</b>:
        <a href="{{lib.get_absolute_url}}"><span property="libns:library_id">{{ lib.id }}</span></a>
        {% if user.is_staff %}<a href="{{lib.get_admin_url}}"><img class="icon_button" src="/media/img/admin/icon_changelink.gif"/></a>{% endif %}
-       <br property="rdf:type" content="libns:library"/>
+       <br rel="rdf:type" resource="libns:library"/>
     <b>Name</b>:
       <span property="libns:name">{{ lib.library_name }}</span>
     <br/>
diff --git a/htsworkflow/pipelines/desplit_fastq.py b/htsworkflow/pipelines/desplit_fastq.py
new file mode 100644 (file)
index 0000000..0624aaa
--- /dev/null
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+"""Write fastq data from multiple compressed files into a single file
+"""
+
+from glob import glob
+import os
+from optparse import OptionParser
+import sys
+
+from htsworkflow.version import version
+from htsworkflow.util.opener import autoopen
+from htsworkflow.util.conversion import parse_slice
+
+SEQ_HEADER = 0
+SEQUENCE = 1
+QUAL_HEADER = 2
+QUALITY = 3
+INVALID = -1
+
+
+def main(cmdline=None):
+    """Command line driver: [None, 'option', '*.fastq.bz2']
+    """
+    parser = make_parser()
+    opts, args = parser.parse_args(cmdline)
+
+    if opts.version:
+        print (version())
+        return 0
+
+    if opts.output is not None:
+        output = open(opts.output, 'w')
+    else:
+        output = sys.stdout
+
+    desplitter = DesplitFastq(file_generator(args), output)
+    desplitter.trim = parse_slice(opts.slice)
+    desplitter.run()
+
+    return 0
+
+
+def make_parser():
+    """Generate an option parser for above main function"""
+
+    usage = '%prog: [options] *.fastq.gz'
+    parser = OptionParser(usage)
+
+    parser.add_option('-o', '--output', default=None,
+                      help='output fastq file')
+    parser.add_option('-s', '--slice',
+                      help="specify python slice, e.g. 0:75, 0:-1",
+                      default=None)
+    parser.add_option("--version", default=False, action="store_true",
+                      help="report software version")
+    return parser
+
+
+def file_generator(pattern_list):
+    """Given a list of glob patterns return decompressed streams
+    """
+    for pattern in pattern_list:
+        for filename in glob(pattern):
+            yield autoopen(filename, 'r')
+
+
+class DesplitFastq(object):
+    """Merge multiple fastq files into a single file"""
+    def __init__(self, sources, destination):
+        self.sources = sources
+        self.destination = destination
+
+        self.making_fastq = True
+        self.trim = slice(None)
+
+    def run(self):
+        """Do the conversion
+
+        This is here so we can run via threading/multiprocessing APIs
+        """
+        state = SEQ_HEADER
+        for stream in self.sources:
+            for line in stream:
+                line = line.rstrip()
+                if state == SEQ_HEADER:
+                    self.destination.write(line)
+                    state = SEQUENCE
+                elif state == SEQUENCE:
+                    self.destination.write(line[self.trim])
+                    state = QUAL_HEADER
+                elif state == QUAL_HEADER:
+                    self.destination.write(line)
+                    state = QUALITY
+                elif state == QUALITY:
+                    self.destination.write(line[self.trim])
+                    state = SEQ_HEADER
+                self.destination.write(os.linesep)
+
+
+if __name__ == "__main__":
+    main()
index ac44c1edde131f198e5d02f9d64a644bcdb00f68..2f017eb2dc0f4817448b4bae14eebd5b2657772f 100644 (file)
@@ -1,4 +1,6 @@
 #!/usr/bin/env python
+"""Convert a collection of qseq or a tar file of qseq files to a fastq file
+"""
 from glob import glob
 import os
 from optparse import OptionParser
@@ -7,22 +9,26 @@ import sys
 import tarfile
 
 from htsworkflow.version import version
+from htsworkflow.util.conversion import parse_slice
+
 
 def main(cmdline=None):
+    """Command line driver: [None, '-i', 'tarfile', '-o', 'target.fastq']
+    """
     parser = make_parser()
     opts, args = parser.parse_args(cmdline)
 
     if opts.version:
         print version()
         return 0
-    
+
     if opts.infile is not None:
         qseq_generator = tarfile_generator(opts.infile)
     elif len(args) > 0:
         qseq_generator = file_generator(args)
     else:
         qseq_generator = [sys.stdin]
-            
+
     if opts.output is not None:
         output = open(opts.output, 'w')
     else:
@@ -43,19 +49,21 @@ def main(cmdline=None):
 
 
 def make_parser():
+    """Return option parser"""
     usage = "%prog: [options] *_qseq.txt\nProduces Phred33 files by default"
     parser = OptionParser(usage)
     parser.add_option("-a", "--fasta", default=False, action="store_true",
                       help="produce fasta files instead of fastq files")
-    parser.add_option("-f", "--flowcell", default=None, 
+    parser.add_option("-f", "--flowcell", default=None,
                       help="Set flowcell ID for output file")
     parser.add_option("-i", "--infile", default=None,
-      help='source tar file (if reading from an archive instead of a directory)')
+                      help='source tar file (if reading from an archive '\
+                           'instead of a directory)')
     parser.add_option("-o", "--output", default=None,
                       help="output fastq file")
     parser.add_option("-n", "--nopass-output", default=None,
-                      help="if provided send files that failed illumina filter "\
-                           "to a differentfile")
+                      help="if provided send files that failed "\
+                           "illumina filter to a differentfile")
     parser.add_option("-s", "--slice",
                       help="specify python slice, e.g. 0:75, 0:-1",
                       default=None)
@@ -63,64 +71,24 @@ def make_parser():
                       action="store_true")
     parser.add_option("--version", default=False, action="store_true",
                       help="report software version")
-    
-    return parser
-
-            
-def file_generator(pattern_list):
-    for pattern in pattern_list:
-        for filename in glob(pattern):
-            yield open(filename,"r")
-
-
-def tarfile_generator(tarfilename):
-    archive = tarfile.open(tarfilename,'r|*')
-    for tarinfo in archive:
-        yield archive.extractfile(tarinfo)
 
+    return parser
 
-def parse_slice(slice_text):
-    if slice_text is None or len(slice_text) == 0:
-        return slice(None)
-        
-    slice_data = []
-    for element in slice_text.split(':'):
-        if len(element) == 0:
-            element = None
-        else:
-            element = int(element)
-        slice_data.append(element)
-
-    return slice(*slice_data)
 
-            
 def file_generator(pattern_list):
+    """Given a list of glob patterns yield open streams for matching files"""
     for pattern in pattern_list:
         for filename in glob(pattern):
-            yield open(filename,"r")
+            yield open(filename, "r")
 
 
 def tarfile_generator(tarfilename):
-    archive = tarfile.open(tarfilename,'r|*')
+    """Yield open streams for files inside a tarfile"""
+    archive = tarfile.open(tarfilename, 'r|*')
     for tarinfo in archive:
         yield archive.extractfile(tarinfo)
 
 
-def parse_slice(slice_text):
-    if slice_text is None or len(slice_text) == 0:
-        return slice(None)
-        
-    slice_data = []
-    for element in slice_text.split(':'):
-        if len(element) == 0:
-            element = None
-        else:
-            element = int(element)
-        slice_data.append(element)
-
-    return slice(*slice_data)
-
-
 class Qseq2Fastq(object):
     """
     Convert qseq files to fastq (or fasta) files.
@@ -132,47 +100,33 @@ class Qseq2Fastq(object):
             self.nopass_destination = nopass_destination
         else:
             self.nopass_destination = pass_destination
-        
+
         self.fastq = True
         self.flowcell_id = None
         self.trim = slice(None)
-        self.reportFilter = False
+        self.report_filter = False
 
     def _format_flowcell_id(self):
         """
         Return formatted flowcell ID
         """
         if self.flowcell_id is not None:
-            return self.flowcell_id+"_"
+            return self.flowcell_id + "_"
         else:
             return ""
-    
-    def _convert_illumina_quality(self, illumina_quality):
-        """
-        Convert an Illumina ASCII encoded quality score to a Phred ASCII quality score.
-        """
-        # Illumina scores are Phred + 64
-        # Fastq scores are Phread + 33
-        # the following code grabs the string, converts to short ints and
-        # subtracts 31 (64-33) to convert between the two score formats.
-        # The numpy solution is twice as fast as some of my other
-        # ideas for the conversion.
-        # sorry about the uglyness in changing from character, to 8-bit int
-        # and back to a character array
-        quality = numpy.asarray(illumina_quality,'c')
-        quality.dtype = numpy.uint8
-        quality -= 31
-        quality.dtype = '|S1' # I'd like to know what the real numpy char type is
-        return quality
-        
+
     def run(self):
+        """Run conversion
+        (Used to match threading/multiprocessing API)
+        """
         if self.fastq:
-            header_template = '@' 
+            header_template = '@'
         else:
             # fasta case
             header_template = '>'
-        header_template += self._format_flowcell_id() + '%s_%s:%s:%s:%s:%s/%s%s%s'
-        
+        header_template += self._format_flowcell_id() + \
+                           '%s_%s:%s:%s:%s:%s/%s%s%s'
+
         for qstream in self.sources:
             for line in qstream:
                 # parse line
@@ -183,19 +137,19 @@ class Qseq2Fastq(object):
                 tile = record[3]
                 x = record[4]
                 y = record[5]
-                index = record[6]
+                #index = record[6]
                 read = record[7]
-                sequence = record[8].replace('.','N')
-                quality = self._convert_illumina_quality(record[9])
+                sequence = record[8].replace('.', 'N')
+                quality = convert_illumina_quality(record[9])
 
                 # add pass qc filter if we want it
                 pass_qc = int(record[10])
-                if self.reportFilter:
+                if self.report_filter:
                     pass_qc_msg = " pf=%s" % (pass_qc)
                 else:
                     pass_qc_msg = ""
 
-                header = header_template  % ( \
+                header = header_template % ( \
                     machine_name,
                     run_number,
                     lane_number,
@@ -206,13 +160,12 @@ class Qseq2Fastq(object):
                     pass_qc_msg,
                     os.linesep)
 
-
                 # if we passed the filter write to the "good" file
                 if pass_qc:
                     destination = self.pass_destination
                 else:
                     destination = self.nopass_destination
-                
+
                 destination.write(header)
                 destination.write(sequence[self.trim])
                 destination.write(os.linesep)
@@ -222,5 +175,24 @@ class Qseq2Fastq(object):
                     destination.write(quality[self.trim].tostring())
                     destination.write(os.linesep)
 
+def convert_illumina_quality(illumina_quality):
+    """Convert an Illumina quality score to a Phred ASCII quality score.
+    """
+    # Illumina scores are Phred + 64
+    # Fastq scores are Phread + 33
+    # the following code grabs the string, converts to short ints and
+    # subtracts 31 (64-33) to convert between the two score formats.
+    # The numpy solution is twice as fast as some of my other
+    # ideas for the conversion.
+    # sorry about the uglyness in changing from character, to 8-bit int
+    # and back to a character array
+    quality = numpy.asarray(illumina_quality, 'c')
+    quality.dtype = numpy.uint8
+    quality -= 31
+     # I'd like to know what the real numpy char type is
+    quality.dtype = '|S1'
+    return quality
+
+
 if __name__ == "__main__":
     main()
index 94d8f5036089a47daeaad4a4b3f44a58540d0555..bd220a0ee854472e643df0b4e15ea3d4e3ac1ea1 100644 (file)
@@ -17,6 +17,7 @@ except ImportError, e:
 
 from htsworkflow.frontend.auth import apidata
 from htsworkflow.util import api
+from htsworkflow.util import alphanum
 from htsworkflow.util.url import normalize_url
 from htsworkflow.pipelines.genome_mapper import \
      getAvailableGenomes, \
@@ -410,7 +411,7 @@ def format_pooled_libraries(shared, library):
     elif (type(sequences) == types.DictType):
         pooled = []
         multiplex_ids = sequences.keys()
-        multiplex_ids.sort(key=int)
+        multiplex_ids.sort(cmp=alphanum.alphanum)
         for multiplex_id in multiplex_ids:
             sample = {}
             sample.update(shared)
index 4a2b4cdc3704fccb1b7fbdd5f48211c86851b6c4..3389c2d9ab8ad6f3ffc4b2378c0c8fcd7ff8139a 100644 (file)
@@ -555,7 +555,10 @@ def extract_results(runs, output_base_dir=None, site="individual", num_jobs=1, r
             lanes.append(lane)
 
         run_name = srf.pathname_to_run_name(r.pathname)
-        if raw_format == 'qseq':
+        seq_cmds = []
+        if raw_format == 'fastq':
+            srf.copy_hiseq_project_fastqs(run_name, r.bustard.pathname, site, cycle_dir)
+        elif raw_format == 'qseq':
             seq_cmds = srf.make_qseq_commands(run_name, r.bustard.pathname, lanes, site, cycle_dir)
         elif raw_format == 'srf':
             seq_cmds = srf.make_srf_commands(run_name, r.bustard.pathname, lanes, site, cycle_dir, 0)
index 993bcc94979cf5c3c6fe12eaa3c4b4b062a28581..772af7b432754245b7a5eddb9ab3b1de45842eb7 100644 (file)
@@ -1,8 +1,10 @@
 """
 Utilities to work with the various eras of sequence archive files
 """
+import collections
 import logging
 import os
+import types
 import re
 
 LOGGER = logging.getLogger(__name__)
@@ -29,12 +31,34 @@ CREATE TABLE %(table)s (
 """ %( {'table': SEQUENCE_TABLE_NAME} )
     return cursor.execute(sql)
 
+FlowcellPath = collections.namedtuple('FlowcellPath',
+                                      'flowcell start stop project')
+
 class SequenceFile(object):
     """
     Simple container class that holds the path to a sequence archive
     and basic descriptive information.
     """
-    def __init__(self, filetype, path, flowcell, lane, read=None, pf=None, cycle=None):
+    def __init__(self, filetype, path, flowcell, lane,
+                 read=None,
+                 pf=None,
+                 cycle=None,
+                 project=None,
+                 index=None,
+                 split=None):
+        """Store various fields used in our sequence files
+
+        filetype is one of 'qseq', 'srf', 'fastq'
+        path = location of file
+        flowcell = files flowcell id
+        lane = which lane
+        read = which sequencer read, usually 1 or 2
+        pf = did it pass filter
+        cycle = cycle dir name e.g. C1-202
+        project = projed name from HiSeq, probably library ID
+        index = HiSeq barcode index sequence
+        split = file fragment from HiSeq (Since one file is split into many)
+        """
         self.filetype = filetype
         self.path = path
         self.flowcell = flowcell
@@ -42,12 +66,15 @@ class SequenceFile(object):
         self.read = read
         self.pf = pf
         self.cycle = cycle
+        self.project = project
+        self.index = index
+        self.split = split
 
     def __hash__(self):
         return hash(self.key())
 
     def key(self):
-        return (self.flowcell, self.lane)
+        return (self.flowcell, self.lane, self.read, self.project, self.split)
 
     def unicode(self):
         return unicode(self.path)
@@ -56,7 +83,15 @@ class SequenceFile(object):
         """
         Equality is defined if everything but the path matches
         """
-        attributes = ['filetype','flowcell', 'lane', 'read', 'pf', 'cycle']
+        attributes = ['filetype',
+                      'flowcell',
+                      'lane',
+                      'read',
+                      'pf',
+                      'cycle',
+                      'project',
+                      'index',
+                      'split']
         for a in attributes:
             if getattr(self, a) != getattr(other, a):
                 return False
@@ -114,7 +149,16 @@ def get_flowcell_cycle(path):
     """
     Extract flowcell, cycle from pathname
     """
-    rest, cycle = os.path.split(path)
+    path = os.path.normpath(path)
+    project = None
+    rest, tail = os.path.split(path)
+    if tail.startswith('Project_'):
+        # we're in a multiplexed sample
+        project = tail
+        rest, cycle = os.path.split(rest)
+    else:
+        cycle = tail
+
     rest, flowcell = os.path.split(rest)
     cycle_match = re.match("C(?P<start>[0-9]+)-(?P<stop>[0-9]+)", cycle)
     if cycle_match is None:
@@ -128,10 +172,10 @@ def get_flowcell_cycle(path):
     if stop is not None:
         stop = int(stop)
 
-    return flowcell, start, stop
+    return FlowcellPath(flowcell, start, stop, project)
 
 def parse_srf(path, filename):
-    flowcell_dir, start, stop = get_flowcell_cycle(path)
+    flowcell_dir, start, stop, project = get_flowcell_cycle(path)
     basename, ext = os.path.splitext(filename)
     records = basename.split('_')
     flowcell = records[4]
@@ -145,7 +189,7 @@ def parse_srf(path, filename):
     return SequenceFile('srf', fullpath, flowcell, lane, cycle=stop)
 
 def parse_qseq(path, filename):
-    flowcell_dir, start, stop = get_flowcell_cycle(path)
+    flowcell_dir, start, stop, project = get_flowcell_cycle(path)
     basename, ext = os.path.splitext(filename)
     records = basename.split('_')
     fullpath = os.path.join(path, filename)
@@ -162,20 +206,40 @@ def parse_qseq(path, filename):
 def parse_fastq(path, filename):
     """Parse fastq names
     """
-    flowcell_dir, start, stop = get_flowcell_cycle(path)
-    basename, ext = os.path.splitext(filename)
+    flowcell_dir, start, stop, project = get_flowcell_cycle(path)
+    basename = re.sub('\.fastq(\.gz|\.bz2)?$', '', filename)
     records = basename.split('_')
     fullpath = os.path.join(path, filename)
-    flowcell = records[4]
-    lane = int(records[5][1])
-    read = int(records[6][1])
-    pf = parse_fastq_pf_flag(records)
+    if project is not None:
+        # demultiplexed sample!
+        flowcell = flowcell_dir
+        lane = int(records[2][-1])
+        read = int(records[3][-1])
+        pf = True # as I understand it hiseq runs toss the ones that fail filter
+        index = records[1]
+        project_id = records[0]
+        split = records[4]
+        sequence_type = 'split_fastq'
+    else:
+        flowcell = records[4]
+        lane = int(records[5][1])
+        read = int(records[6][1])
+        pf = parse_fastq_pf_flag(records)
+        index = None
+        project_id = None
+        split = None
+        sequence_type = 'fastq'
 
     if flowcell_dir != flowcell:
         LOGGER.warn("flowcell %s found in wrong directory %s" % \
                          (flowcell, path))
 
-    return SequenceFile('fastq', fullpath, flowcell, lane, read, pf=pf, cycle=stop)
+    return SequenceFile(sequence_type, fullpath, flowcell, lane, read,
+                        pf=pf,
+                        cycle=stop,
+                        project=project_id,
+                        index=index,
+                        split=split)
 
 def parse_fastq_pf_flag(records):
     """Take a fastq filename split on _ and look for the pass-filter flag
@@ -200,7 +264,7 @@ def parse_eland(path, filename, eland_match=None):
     if eland_match is None:
         eland_match = eland_re.match(filename)
     fullpath = os.path.join(path, filename)
-    flowcell, start, stop = get_flowcell_cycle(path)
+    flowcell, start, stop, project = get_flowcell_cycle(path)
     if eland_match.group('lane'):
         lane = int(eland_match.group('lane'))
     else:
@@ -216,6 +280,9 @@ def scan_for_sequences(dirs):
     Scan through a list of directories for sequence like files
     """
     sequences = []
+    if type(dirs) in types.StringTypes:
+        raise ValueError("You probably want a list or set, not a string")
+
     for d in dirs:
         LOGGER.info("Scanning %s for sequences" % (d,))
         if not os.path.exists(d):
@@ -226,15 +293,16 @@ def scan_for_sequences(dirs):
             for f in filenames:
                 seq = None
                 # find sequence files
-                if raw_seq_re.match(f):
-                    if f.endswith('.md5'):
-                        continue
-                    elif f.endswith('.srf') or f.endswith('.srf.bz2'):
-                        seq = parse_srf(path, f)
-                    elif qseq_re.match(f):
-                        seq = parse_qseq(path, f)
-                    elif f.endswith('fastq') or f.endswith('.fastq.bz2'):
-                        seq = parse_fastq(path, f)
+                if f.endswith('.md5'):
+                    continue
+                elif f.endswith('.srf') or f.endswith('.srf.bz2'):
+                    seq = parse_srf(path, f)
+                elif qseq_re.match(f):
+                    seq = parse_qseq(path, f)
+                elif f.endswith('.fastq') or \
+                     f.endswith('.fastq.bz2') or \
+                     f.endswith('.fastq.gz'):
+                    seq = parse_fastq(path, f)
                 eland_match = eland_re.match(f)
                 if eland_match:
                     if f.endswith('.md5'):
index c313efe76e303db6a3508342204f482e87736a72..4f20ce1873fa42527b52619670ffc7caad8dd2ee 100644 (file)
@@ -1,6 +1,7 @@
 from glob import glob
 import logging
 import os
+import shutil
 
 from htsworkflow.util import queuecommands
 
@@ -150,6 +151,32 @@ def make_qseq_commands(run_name, bustard_dir, lanes, site_name, destdir, cmdleve
 
   return cmd_list
 
+def copy_hiseq_project_fastqs(run_name, basecall_dir, site_name, destdir):
+    """
+    make a subprocess-friendly list of command line arguments to save HiSeq fastq files
+
+    run_name - most of the file name (run folder name is a good choice)
+    basecall_dir - location of unaligned files.
+    site_name - name of your "sequencing site" or "Individual"
+    destdir - root of where to save fastq files
+    """
+    # clean up pathname
+    LOGGER.info("run_name %s" % (run_name,))
+
+    cmd_list = []
+    project_dirs = glob(os.path.join(basecall_dir, 'Project_*'))
+    for project_dir in project_dirs:
+        _, project_name = os.path.split(project_dir)
+        sample_files = glob(os.path.join(project_dir, 'Sample*', '*.fastq*'))
+        project_dest = os.path.join(destdir, project_name)
+        if not os.path.exists(project_dest):
+            LOGGER.info("Making: %s" % (project_dest))
+            os.mkdir(project_dest)
+
+        for fastq_file in sample_files:
+            shutil.copy(fastq_file, project_dest)
+
+
 def run_commands(new_dir, cmd_list, num_jobs):
     LOGGER.info("chdir to %s" % (new_dir,))
     curdir = os.getcwd()
index d63f2654b21e27f553ad7c1a15f47459db80a78b..8c5ab7f91215d7c38198c124e1014b6637dd738a 100644 (file)
@@ -2,10 +2,13 @@
 Analyze the Summary.htm file produced by GERALD
 """
 import logging
+import re
 import types
 from pprint import pprint
 
-from htsworkflow.pipelines.runfolder import ElementTree
+#from htsworkflow.pipelines.runfolder import ElementTree
+from lxml import html
+from lxml import etree
 from htsworkflow.util.ethelp import indent, flatten
 
 LOGGER = logging.getLogger(__name__)
@@ -62,11 +65,13 @@ class Summary(object):
             self.percent_error_rate = None
 
             if html is not None:
-                self.set_elements_from_html(html)
+                self.set_elements_from_source(html)
             if xml is not None:
                 self.set_elements(xml)
 
-        def set_elements_from_html(self, data):
+        def set_elements_from_source(self, data):
+            """Read from an initial summary data file. Either xml or html
+            """
             if not len(data) in (8,10):
                 raise RuntimeError("Summary.htm file format changed, len(data)=%d" % (len(data),))
 
@@ -112,7 +117,7 @@ class Summary(object):
                 setattr(self, LRSName, parse_xml_mean_range(node))
 
         def get_elements(self):
-            lane_result = ElementTree.Element(
+            lane_result = etree.Element(
                             Summary.LaneResultSummary.LANE_RESULT_SUMMARY,
                             {'lane': unicode(self.lane), 'end': unicode(self.end)})
             for tag, variable_name in Summary.LaneResultSummary.TAGS.items():
@@ -127,7 +132,7 @@ class Summary(object):
                       *value
                     )
                 else:
-                    element = ElementTree.SubElement(lane_result, tag)
+                    element = etree.SubElement(lane_result, tag)
                     element.text = unicode(value)
             return lane_result
 
@@ -200,11 +205,16 @@ class Summary(object):
         The contents of the h2 tag is considered to the name
         of the table.
         """
-        # tree = ElementTree.parse(pathname).getroot()
+        if isxml_file(pathname):
+            tree = etree.parse(pathname).getroot()
+        else:
+            # html
+            tree = html.parse(pathname).getroot()
+        # tree = etree.parse(pathname).getroot()
         # hack for 1.1rc1, this should be removed when possible.
-        file_body = open(pathname).read()
-        file_body = file_body.replace('CHASTITY<=', 'CHASTITY&lt;=')
-        tree = ElementTree.fromstring(file_body)
+        #file_body = open(pathname).read()
+        #file_body = file_body.replace('CHASTITY<=', 'CHASTITY&lt;=')
+        #tree = etree.fromstring(file_body)
 
         # are we reading the xml or the html version of the Summary file?
         if tree.tag.lower() == 'summary':
@@ -247,14 +257,19 @@ class Summary(object):
 
     ###### START HTML Table Extraction ########
     def _extract_named_tables_from_html(self, tree):
-        body = tree.find('body')
         tables = {}
-        for i in range(len(body)):
-            if body[i].tag == 'h2' and body[i+1].tag == 'table':
-                # we have an interesting table
-                name = flatten(body[i])
-                table = body[i+1]
-                data = self._parse_table(table)
+        for t in tree.findall('*//table'):
+            previous = t.getprevious()
+            if previous is None:
+                previous = t.getparent()
+
+            if previous.tag.lower() == 'div':
+                previous = previous.getprevious()
+
+            if previous.tag in ('h2', 'p'):
+                # we have a table
+                name = flatten(previous)
+                data = self._parse_table(t)
                 tables[name] = data
         return tables
 
@@ -290,7 +305,7 @@ class Summary(object):
     ###### END HTML Table Extraction ########
 
     def get_elements(self):
-        summary = ElementTree.Element(Summary.SUMMARY,
+        summary = etree.Element(Summary.SUMMARY,
                                       {'version': unicode(Summary.XML_VERSION)})
         for end in self.lane_results:
             for lane in end.values():
@@ -318,7 +333,7 @@ class Summary(object):
         Debugging function, report current object
         """
         tree = self.get_elements()
-        print ElementTree.tostring(tree)
+        print etree.tostring(tree)
 
 def tonumber(v):
     """
@@ -351,9 +366,9 @@ def parse_mean_range(value):
 
 def make_mean_range_element(parent, name, mean, deviation):
     """
-    Make an ElementTree subelement <Name mean='mean', deviation='deviation'/>
+    Make an etree subelement <Name mean='mean', deviation='deviation'/>
     """
-    element = ElementTree.SubElement(parent, name,
+    element = etree.SubElement(parent, name,
                                      { 'mean': unicode(mean),
                                        'deviation': unicode(deviation)})
     return element
@@ -398,6 +413,22 @@ def parse_xml_mean_range(element):
 
     return (mean_value, stddev_value)
 
+def isxml_file(fname):
+    with open(fname,'r') as stream:
+        return isxml_stream(stream)
+
+def isxml_stream(stream):
+    """Return true or false if its sort of an xml file
+    """
+    pos = stream.tell()
+    line = stream.readline()
+    stream.seek(pos)
+    if re.match("<\?xml.*?>", line):
+        # attempt at xml
+        return True
+    else:
+        return False
+
 if __name__ == "__main__":
     # test code
     from optparse import OptionParser
index c07783ef3f8f7323b2e73ea6687d9d4846852eaa..42cf421587b227bc466b8248e4b58124a775ac65 100644 (file)
@@ -1,7 +1,7 @@
 """
 Create simulated solexa/illumina runfolders for testing
 """
-
+import gzip
 import os
 import shutil
 
@@ -55,6 +55,25 @@ def make_bustard_config132(image_dir):
     destination = os.path.join(image_dir, 'config.xml')
     shutil.copy(source, destination)
 
+def make_aligned_config_1_12(aligned_dir):
+    """This is rouglhly equivalent to the old gerald file"""
+    source = os.path.join(TESTDATA_DIR, 'aligned_config_1_12.xml')
+    destination = os.path.join(aligned_dir, 'config.xml')
+    shutil.copy(source, destination)
+
+def make_unaligned_config_1_12(unaligned_dir):
+    demultiplex_pairs = [ # (src,
+      # dest),
+        (os.path.join(TESTDATA_DIR, 'demultiplex_1.12.4.2.xml'),
+         os.path.join(unaligned_dir, 'DemultiplexConfig.xml')),
+        (os.path.join(TESTDATA_DIR, 'demultiplexed_bustard_1.12.4.2.xml'),
+         os.path.join(unaligned_dir, 'DemultiplexConfig.xml')),
+        (os.path.join(TESTDATA_DIR, 'demultiplexed_summary_1.12.4.2.xml'),
+         os.path.join(unaligned_dir, 'DemultiplexConfig.xml')),
+    ]
+    for src, dest in demultiplex_pairs:
+        shutil.copy(src, dest)
+
 def make_rta_intensities_1460(data_dir, version='1.4.6.0'):
     """
     Construct an artificial RTA Intensities parameter file and directory
@@ -107,6 +126,19 @@ def make_rta_intensities_1_10(data_dir, version='1.10.36.0'):
 
     return intensities_dir
 
+def make_rta_intensities_1_12(data_dir, version='1.12.4.2'):
+    """
+    Construct an artificial RTA Intensities parameter file and directory
+    """
+    intensities_dir = os.path.join(data_dir, 'Intensities')
+    if not os.path.exists(intensities_dir):
+      os.mkdir(intensities_dir)
+
+    param_file = os.path.join(TESTDATA_DIR, 'rta_intensities_config_1.12.4.2.xml')
+    shutil.copy(param_file, os.path.join(intensities_dir, 'RTAConfig.xml'))
+
+    return intensities_dir
+
 def make_rta_basecalls_1870(intensities_dir):
     """
     Construct an artificial RTA Intensities parameter file and directory
@@ -134,6 +166,21 @@ def make_rta_basecalls_1_10(intensities_dir):
 
     return basecalls_dir
 
+def make_rta_basecalls_1_12(intensities_dir):
+    """
+    Construct an artificial RTA Intensities parameter file and directory
+    """
+    basecalls_dir = os.path.join(intensities_dir, 'BaseCalls')
+    if not os.path.exists(basecalls_dir):
+        os.mkdir(basecalls_dir)
+
+    make_qseqs(basecalls_dir, basecall_info=ABXX_BASE_CALL_INFO)
+    param_file = os.path.join(TESTDATA_DIR, 'rta_basecalls_config_1.12.4.2.xml')
+    shutil.copy(param_file, os.path.join(basecalls_dir, 'config.xml'))
+
+    return basecalls_dir
+
+
 def make_qseqs(bustard_dir, basecall_info=None):
     """
     Fill gerald directory with qseq files
@@ -234,6 +281,9 @@ def make_matrix_dir_rta160(bustard_dir):
 def make_matrix_dir_rta_1_10(bustard_dir):
     make_matrix_dir_rta160(bustard_dir)
 
+def make_matrix_dir_rta_1_12(bustard_dir):
+    make_matrix_dir_rta160(bustard_dir)
+
 def make_phasing_dir(bustard_dir):
     """
     Create several phasing files in <bustard_dir>/Phasing/
@@ -394,6 +444,199 @@ _bbbbbaaababaabbbbab]D]aaaaaaaaaaaaaa
         f.write(seq)
         f.close()
 
+UNALIGNED_READS = [1,2]
+UNALIGNED_SAMPLES = [ (1, UNALIGNED_READS, '11111', None, None),
+                      (2, UNALIGNED_READS, '11112', None, None),
+                      (3, UNALIGNED_READS, '11113', 1, 'ATCACG'),
+                      (3, UNALIGNED_READS, '11113', 2, 'CGATGT'),
+                      (3, UNALIGNED_READS, '11113', 3, 'TTAGGC'),
+                      (4, UNALIGNED_READS, '11114', 6, 'GCCAAT'),
+                      (5, UNALIGNED_READS, '11115', 1, 'ATCACG'),
+                      (5, UNALIGNED_READS, '11116', 7, 'ACTTGA'),
+                      (5, UNALIGNED_READS, '11117', 9, 'GATCAG'),
+                      (6, UNALIGNED_READS, '11118', 1, 'ATCACG'),
+                      (7, UNALIGNED_READS, '11119', 2, 'CGATGT'),
+                      (8, UNALIGNED_READS, '11120', 3, 'TTAGGC'),
+                      (1, UNALIGNED_READS, None, None, None),
+                      (2, UNALIGNED_READS, None, None, None),
+                      (3, UNALIGNED_READS, None, None, None),
+                      (4, UNALIGNED_READS, None, None, None),
+                      (5, UNALIGNED_READS, None, None, None)]
+
+
+def make_aligned_eland_export(aligned_dir, flowcell_id):
+    summary_source = os.path.join(TESTDATA_DIR, 'sample_summary_1_12.htm')
+    for lane, read, project_id, index_id, index_seq in UNALIGNED_SAMPLES:
+        paths = DemultiplexedPaths(aligned_dir,
+                                   flowcell_id,
+                                   lane,
+                                   project_id,
+                                   index_id,
+                                   index_seq)
+        paths.make_sample_dirs()
+        paths.make_summary_dirs()
+        summary_dest = os.path.join(paths.summary_dir, 'Sample_Summary.htm')
+        shutil.copy(summary_source, summary_dest)
+
+        body = get_unaligned_sample_export(lane, index_seq)
+        for split in ['001','002']:
+            for read in UNALIGNED_READS:
+                suffix = 'R{0}_{1}_export.txt.gz'.format(read, split)
+                pathname = paths.make_test_filename(suffix)
+                stream = gzip.open(pathname, 'w')
+                stream.write(body)
+                stream.close()
+
+
+def make_unaligned_fastqs_1_12(unaligned_dir, flowcell_id):
+    """Create a default mix of unaligned sample files
+    """
+    for lane, read, name, index_id, index in UNALIGNED_SAMPLES:
+        make_unaligned_fastq_sample_1_12(unaligned_dir,
+                                         flowcell_id,
+                                         lane,
+                                         read,
+                                         name,
+                                         index_id,
+                                         index)
+
+def make_unaligned_fastq_sample_1_12(unaligned_dir,
+                                     flowcell_id,
+                                     lane,
+                                     reads,
+                                     project_id,
+                                     index_id=None,
+                                     index_seq=None):
+
+    paths = DemultiplexedPaths(unaligned_dir,
+                               flowcell_id,
+                               lane,
+                               project_id,
+                               index_id,
+                               index_seq)
+    paths.make_sample_dirs()
+
+    sample_seq = get_unaligned_sample_fastq_data(flowcell_id, lane, index_seq)
+    for split in ['001','002']:
+        for read in reads:
+            suffix = 'R{0}_{1}.fastq.gz'.format(read, split)
+            pathname = paths.make_test_filename(suffix)
+            stream = gzip.open(pathname, 'w')
+            stream.write(sample_seq)
+            stream.close()
+
+    sheetname = os.path.join(paths.sample_dir, 'SampleSheet.csv')
+    stream = open(sheetname, 'w')
+    stream.write('FCID,Lane,SampleID,SampleRef,Index,Description,Control,Recipe,Operator,SampleProject'+os.linesep)
+    template = '{flowcell},{lane},{id},mm9,{index},Sample #{id},N,PR_indexing,Operator,{sample_project}'+os.linesep
+    stream.write(template.format(flowcell=flowcell_id,
+                                 lane=lane,
+                                 id=paths.sample_id,
+                                 index=paths.index_seq,
+                                 sample_project=paths.sample_project))
+    stream.close()
+
+
+class DemultiplexedPaths(object):
+    def __init__(self, basedir, flowcell_id, lane, project_id, index_id, index_seq):
+        if lane not in LANE_LIST:
+            raise ValueError("Invalid lane ID: {0}".format(lane))
+        self.basedir = basedir
+        self.flowcell_id = flowcell_id
+        self.lane = lane
+
+        if project_id is None:
+            # undetermined
+            self.index_seq = ''
+            self.sample_id = 'lane{0}'.format(lane)
+            self.sample_project = 'Undetermined_indices'
+            self.rootname = 'lane{lane}_Undetermined_L00{lane}_'.format(
+                lane=lane)
+            self.project_dir = 'Undetermined_indices'
+            self.sample_dir = 'Sample_lane{lane}'.format(lane=lane)
+        elif index_seq is None:
+            self.index_seq = ''
+            self.sample_id = project_id
+            self.sample_project = '{project_id}'.format(project_id=project_id)
+            self.rootname = '{project_id}_NoIndex_L00{lane}_'.format(
+                project_id=project_id,
+                lane=lane)
+            self.project_dir = 'Project_' + self.sample_project
+            self.sample_dir = 'Sample_{project_id}'.format(
+                project_id=project_id)
+        else:
+            self.index_seq = index_seq
+            self.sample_id = project_id
+            self.sample_project = '{project_id}_Index{index_id}'.format(
+                project_id=project_id,
+                index_id=index_id)
+            self.rootname = '{project_id}_{index}_L00{lane}_'.format(
+                project_id=project_id,
+                index=index_seq,
+                lane=lane)
+            self.project_dir = 'Project_' + self.sample_project
+            self.sample_dir = 'Sample_{project_id}'.format(
+                project_id=project_id)
+
+        self.project_dir = os.path.join(self.basedir, self.project_dir)
+        self.sample_dir = os.path.join(self.project_dir, self.sample_dir)
+        self.summary_dir = 'Summary_Stats_{0}'.format(self.flowcell_id)
+        self.summary_dir = os.path.join(self.project_dir, self.summary_dir)
+
+
+    def make_sample_dirs(self):
+        if not os.path.isdir(self.project_dir):
+            os.mkdir(self.project_dir)
+        if not os.path.isdir(self.sample_dir):
+            os.mkdir(self.sample_dir)
+
+    def make_summary_dirs(self):
+        if not os.path.isdir(self.summary_dir):
+            os.mkdir(self.summary_dir)
+
+    def make_test_filename(self, suffix):
+        filename = self.rootname + suffix
+        pathname = os.path.join(self.sample_dir, filename)
+        return pathname
+
+    def dump(self):
+        print ('index seq: {0}'.format(self.index_seq))
+
+        print ('project dir: {0}'.format(self.project_dir))
+        print ('sample dir: {0}'.format(self.sample_dir))
+        print ('rootname: {0}'.format(self.rootname))
+        print ('path: {0}'.format(
+            os.path.join(self.project_dir,
+                         self.sample_dir,
+                         self.rootname+'R1_001.fastq.gz')))
+
+
+def get_unaligned_sample_fastq_data(flowcell_id, lane, index_seq):
+    seq = """@HWI-ST0787:101:{flowcell}:{lane}:1101:2416:3469 1:Y:0:{index}
+TCCTTCATTCCACCGGAGTCTGTGGAATTCTCGGGTGCCAAGGAACTCCA
++
+CCCFFFFFHHHHHJJJJJJJJJIJJJJJJJJJJJJJJJJIIJJIIJJJJJ
+@HWI-ST0787:101:{flowcell}:{lane}:1101:2677:3293 1:Y:0:{index}
+TGGAAATCCATTGGGGTTTCCCCTGGAATTCTCGGGTGCCAAGGAACTCC
++
+@CCFF3BDHHHHHIIIIIHHIIIDIIIGIIIEGIIIIIIIIIIIIIIIHH
+@HWI-ST0787:101:{flowcell}:{lane}:1101:2616:3297 1:Y:0:{index}
+TAATACTGCCGGGTAATGATGGCTGGAATTCTCGGGTGCCAAGGAACTCC
++
+CCCFFFFFHHHHHCGHJJJJJJJJJJJJJJJJJIIJJJJJJJJJIHJJJI
+@HWI-ST0787:101:{flowcell}:{lane}:1101:2545:3319 1:N:0:{index}
+TCCTTCATTCCACCGGAGTCTGCTGGAATTCTCGGGTGCCAAGGAACTCC
++
+CCCFFFFFHHHFHJGIGHIJHIIGHIGIGIGEHFIJJJIHIJHJIIJJIH
+""".format(flowcell=flowcell_id, lane=lane, index=index_seq)
+    return seq
+
+def get_unaligned_sample_export(lane, index_seq):
+    body = """HWI-ST0787\t102\t{lane}\t1101\t1207\t1993\t{index}\t1\tAANGGATTCGATCCGGCTTAAGAGATGAAAACCGAAAGGGCCGACCGAA\taaBS`ccceg[`ae[dRR_[[SPPPP__ececfYYWaegh^\\ZLLY\\X`\tNM\t\t\t\t\t\t
+HWI-ST0787\t102     {lane}       1101    1478    1997    {index}  1       CAAGAACCCCGGGGGGGGGGGGGCAGAGAGGGGGAATTTTTTTTTTGTT       BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB       NM                                                                                      N
+HWI-ST0787      102     {lane}       1101    1625    1994    {index}  1       AANAATGCTACAGAGACAAAACAAAACTGATATGAAAGTTGAGAATAAA       \^BS\cccgegg[Q[QQQ[`egdgffbeggfgh^^YcfgfhXaHY^O^c       chrII.fa
+""".format(lane=lane, index=index_seq)
+    return body
 
 def ls_tree(root):
     for dirpath, dirnames, filenames in os.walk(root):
diff --git a/htsworkflow/pipelines/test/test_qseq2fastq.py b/htsworkflow/pipelines/test/test_qseq2fastq.py
deleted file mode 100644 (file)
index 1c32924..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python
-
-import unittest
-
-import htsworkflow.pipelines.qseq2fastq as qseq2fastq
-
-class TestQseq2Fastq(unittest.TestCase):
-    def test_parse_slice(self):
-        s = qseq2fastq.parse_slice("1:")
-        self.failUnlessEqual(s.start, 1)
-        self.failUnlessEqual(s.stop, None)
-
-        s = qseq2fastq.parse_slice("0:2")
-        self.failUnlessEqual(s.start, 0)
-        self.failUnlessEqual(s.stop, 2)
-
-def suite():
-    return unittest.makeSuite(TestQseq2Fastq, 'test')
-
-if __name__ == "__main__":
-    unittest.main(defaultTest="suite")
-    
index cb5650191e79f886da243c9837bcfa61291fbb1f..1d0404aa42ec16baff63780f9afa7298e7d04f9b 100644 (file)
@@ -54,19 +54,33 @@ class RetrieveTestCases(TestCase):
 
         output = StringIO()
         save_sample_sheet(output, options, flowcell_info)
+        print output.buf
+
         output.seek(0)
         sheet = list(csv.DictReader(output))
-        expected = [{'SampleProject': '12044_index1', 'Index': 'ATCACG'},
-                    {'SampleProject': '12044_index2', 'Index': 'CGATGT'},
-                    {'SampleProject': '12044_index3', 'Index': 'TTAGGC'},
-                    {'SampleProject': '11045_index1', 'Index': 'ATCACG'},
+        expected = [{'SampleProject': '12044_index1',
+                     'Index': 'ATCACG',
+                     'Lane': '3',
+                     },
+                    {'SampleProject': '12044_index2',
+                     'Index': 'CGATGT',
+                     'Lane': '3',
+                     },
+                    {'SampleProject': '12044_index3',
+                     'Index': 'TTAGGC',
+                     'Lane': '3',
+                     },
+                    {'SampleProject': '11045_index1',
+                     'Index': 'ATCACG',
+                     'Lane': '3',
+                     },
+                    {'SampleProject': '13044_indexN701-N501',
+                     'Index': 'TAAGGCGA-TAGATCGC',
+                     'Lane': '4',
+                     }
                     ]
-        for i in range(4):
-            self.assertEqual(sheet[i]['SampleProject'],
-                             expected[i]['SampleProject'])
-            self.assertEqual(sheet[i]['Index'],
-                             expected[i]['Index'])
-            self.assertEqual(sheet[i]['FCID'], fcid)
-            self.assertEqual(sheet[i]['Lane'], '3')
-
-
+        self.failUnlessEqual(len(sheet), len(expected))
+        for s, e in zip(sheet, expected):
+            for key in e.keys():
+                self.failUnlessEqual(s[key], e[key],
+                  "%s != %s for key %s" % (s[key],e[key], key))
diff --git a/htsworkflow/pipelines/test/test_runfolder_rta1_12.py b/htsworkflow/pipelines/test/test_runfolder_rta1_12.py
new file mode 100644 (file)
index 0000000..927cf61
--- /dev/null
@@ -0,0 +1,291 @@
+#!/usr/bin/env python
+
+from datetime import datetime, date
+import os
+import tempfile
+import shutil
+import unittest
+
+from htsworkflow.pipelines import eland
+from htsworkflow.pipelines import ipar
+from htsworkflow.pipelines import bustard
+from htsworkflow.pipelines import gerald
+from htsworkflow.pipelines import runfolder
+from htsworkflow.pipelines.runfolder import ElementTree
+
+from htsworkflow.pipelines.test.simulate_runfolder import *
+
+
+def make_runfolder(obj=None):
+    """
+    Make a fake runfolder, attach all the directories to obj if defined
+    """
+    # make a fake runfolder directory
+    flowcell_id = 'D07K6ACXX'
+    temp_dir = tempfile.mkdtemp(prefix='tmp_runfolder_')
+
+    runfolder_dir = os.path.join(temp_dir,
+                                 '110815_SN787_0101_A{0}'.format(flowcell_id))
+    os.mkdir(runfolder_dir)
+
+    data_dir = os.path.join(runfolder_dir, 'Data')
+    os.mkdir(data_dir)
+
+    intensities_dir = make_rta_intensities_1_12(data_dir)
+
+    basecalls_dir = make_rta_basecalls_1_12(intensities_dir)
+    make_matrix_dir_rta_1_12(basecalls_dir)
+
+    unaligned_dir = os.path.join(runfolder_dir, "Unaligned")
+    os.mkdir(unaligned_dir)
+    make_unaligned_fastqs_1_12(unaligned_dir, flowcell_id)
+    make_unaligned_config_1_12(unaligned_dir)
+
+    aligned_dir = os.path.join(runfolder_dir, "Aligned")
+    os.mkdir(aligned_dir)
+    make_aligned_eland_export(aligned_dir, flowcell_id)
+    make_aligned_config_1_12(aligned_dir)
+
+    if obj is not None:
+        obj.temp_dir = temp_dir
+        obj.runfolder_dir = runfolder_dir
+        obj.data_dir = data_dir
+        obj.image_analysis_dir = intensities_dir
+        obj.bustard_dir = unaligned_dir
+        obj.gerald_dir = aligned_dir
+
+
+class RunfolderTests(unittest.TestCase):
+    """
+    Test components of the runfolder processing code
+    which includes firecrest, bustard, and gerald
+    """
+    def setUp(self):
+        # attaches all the directories to the object passed in
+        make_runfolder(self)
+
+    def tearDown(self):
+        shutil.rmtree(self.temp_dir)
+
+    def test_bustard(self):
+        """Construct a bustard object"""
+        b = bustard.bustard(self.bustard_dir)
+        self.failUnlessEqual(b.version, '1.8.70.0')
+        self.failUnlessEqual(b.date,    None)
+        self.failUnlessEqual(b.user,    None)
+        self.failUnlessEqual(len(b.phasing), 0)
+
+        xml = b.get_elements()
+        b2 = bustard.Bustard(xml=xml)
+        self.failUnlessEqual(b.version, b2.version)
+        self.failUnlessEqual(b.date,    b2.date )
+        self.failUnlessEqual(b.user,    b2.user)
+
+    def test_gerald(self):
+        # need to update gerald and make tests for it
+        g = gerald.gerald(self.gerald_dir)
+
+        self.failUnlessEqual(g.version,
+            '@(#) Id: GERALD.pl,v 1.171 2008/05/19 17:36:14 mzerara Exp')
+        self.failUnlessEqual(g.date, datetime(2009,2,22,21,15,59))
+        self.failUnlessEqual(len(g.lanes), len(g.lanes.keys()))
+        self.failUnlessEqual(len(g.lanes), len(g.lanes.items()))
+
+
+        # list of genomes, matches what was defined up in
+        # make_gerald_config.
+        # the first None is to offset the genomes list to be 1..9
+        # instead of pythons default 0..8
+        genomes = [None,
+                   '/g/mm9',
+                   '/g/mm9',
+                   '/g/elegans190',
+                   '/g/arabidopsis01222004',
+                   '/g/mm9',
+                   '/g/mm9',
+                   '/g/mm9',
+                   '/g/mm9', ]
+
+        # test lane specific parameters from gerald config file
+        for i in range(1,9):
+            cur_lane = g.lanes[i]
+            self.failUnlessEqual(cur_lane.analysis, 'eland_extended')
+            self.failUnlessEqual(cur_lane.eland_genome, genomes[i])
+            self.failUnlessEqual(cur_lane.read_length, '37')
+            self.failUnlessEqual(cur_lane.use_bases, 'Y'*37)
+
+        # I want to be able to use a simple iterator
+        for l in g.lanes.values():
+          self.failUnlessEqual(l.analysis, 'eland_extended')
+          self.failUnlessEqual(l.read_length, '37')
+          self.failUnlessEqual(l.use_bases, 'Y'*37)
+
+        # test data extracted from summary file
+        clusters = [None,
+                    (281331, 11169), (203841, 13513),
+                    (220889, 15653), (137294, 14666),
+                    (129388, 14525), (262092, 10751),
+                    (185754, 13503), (233765, 9537),]
+
+        self.failUnlessEqual(len(g.summary), 1)
+        for i in range(1,9):
+            summary_lane = g.summary[0][i]
+            self.failUnlessEqual(summary_lane.cluster, clusters[i])
+            self.failUnlessEqual(summary_lane.lane, i)
+
+        xml = g.get_elements()
+        # just make sure that element tree can serialize the tree
+        xml_str = ElementTree.tostring(xml)
+        g2 = gerald.Gerald(xml=xml)
+        return
+
+        # do it all again after extracting from the xml file
+        self.failUnlessEqual(g.version, g2.version)
+        self.failUnlessEqual(g.date, g2.date)
+        self.failUnlessEqual(len(g.lanes.keys()), len(g2.lanes.keys()))
+        self.failUnlessEqual(len(g.lanes.items()), len(g2.lanes.items()))
+
+        # test lane specific parameters from gerald config file
+        for i in range(1,9):
+            g_lane = g.lanes[i]
+            g2_lane = g2.lanes[i]
+            self.failUnlessEqual(g_lane.analysis, g2_lane.analysis)
+            self.failUnlessEqual(g_lane.eland_genome, g2_lane.eland_genome)
+            self.failUnlessEqual(g_lane.read_length, g2_lane.read_length)
+            self.failUnlessEqual(g_lane.use_bases, g2_lane.use_bases)
+
+        # test (some) summary elements
+        self.failUnlessEqual(len(g.summary), 1)
+        for i in range(1,9):
+            g_summary = g.summary[0][i]
+            g2_summary = g2.summary[0][i]
+            self.failUnlessEqual(g_summary.cluster, g2_summary.cluster)
+            self.failUnlessEqual(g_summary.lane, g2_summary.lane)
+
+            g_eland = g.eland_results
+            g2_eland = g2.eland_results
+            for lane in g_eland.results[0].keys():
+                g_results = g_eland.results[0][lane]
+                g2_results = g2_eland.results[0][lane]
+                self.failUnlessEqual(g_results.reads,
+                                     g2_results.reads)
+                if isinstance(g_results, eland.ElandLane):
+                  self.failUnlessEqual(len(g_results.mapped_reads),
+                                       len(g2_results.mapped_reads))
+                  for k in g_results.mapped_reads.keys():
+                      self.failUnlessEqual(g_results.mapped_reads[k],
+                                           g2_results.mapped_reads[k])
+
+                  self.failUnlessEqual(len(g_results.match_codes),
+                                       len(g2_results.match_codes))
+                  for k in g_results.match_codes.keys():
+                      self.failUnlessEqual(g_results.match_codes[k],
+                                           g2_results.match_codes[k])
+
+
+    def test_eland(self):
+        return
+        hg_map = {'Lambda.fa': 'Lambda.fa'}
+        for i in range(1,22):
+          short_name = 'chr%d.fa' % (i,)
+          long_name = 'hg18/chr%d.fa' % (i,)
+          hg_map[short_name] = long_name
+
+        genome_maps = { 1:hg_map, 2:hg_map, 3:hg_map, 4:hg_map,
+                        5:hg_map, 6:hg_map, 7:hg_map, 8:hg_map }
+        eland_container = gerald.eland(self.gerald_dir, genome_maps=genome_maps)
+
+        # I added sequence lanes to the last 2 lanes of this test case
+        for i in range(1,7):
+            lane = eland_container.results[0][i]
+            self.failUnlessEqual(lane.reads, 6)
+            self.failUnlessEqual(lane.sample_name, "s")
+            self.failUnlessEqual(lane.lane_id, i)
+            self.failUnlessEqual(len(lane.mapped_reads), 17)
+            self.failUnlessEqual(lane.mapped_reads['hg18/chr5.fa'], 4)
+            self.failUnlessEqual(lane.match_codes['U0'], 3)
+            self.failUnlessEqual(lane.match_codes['R0'], 2)
+            self.failUnlessEqual(lane.match_codes['U1'], 1)
+            self.failUnlessEqual(lane.match_codes['R1'], 9)
+            self.failUnlessEqual(lane.match_codes['U2'], 0)
+            self.failUnlessEqual(lane.match_codes['R2'], 12)
+            self.failUnlessEqual(lane.match_codes['NM'], 1)
+            self.failUnlessEqual(lane.match_codes['QC'], 0)
+
+        # test scarf
+        lane = eland_container.results[0][7]
+        self.failUnlessEqual(lane.reads, 5)
+        self.failUnlessEqual(lane.sample_name, 's')
+        self.failUnlessEqual(lane.lane_id, 7)
+        self.failUnlessEqual(lane.sequence_type, eland.SequenceLane.SCARF_TYPE)
+
+        # test fastq
+        lane = eland_container.results[0][8]
+        self.failUnlessEqual(lane.reads, 3)
+        self.failUnlessEqual(lane.sample_name, 's')
+        self.failUnlessEqual(lane.lane_id, 8)
+        self.failUnlessEqual(lane.sequence_type, eland.SequenceLane.FASTQ_TYPE)
+
+        xml = eland_container.get_elements()
+        # just make sure that element tree can serialize the tree
+        xml_str = ElementTree.tostring(xml)
+        e2 = gerald.ELAND(xml=xml)
+
+        for i in range(1,9):
+            l1 = eland_container.results[0][i]
+            l2 = e2.results[0][i]
+            self.failUnlessEqual(l1.reads, l2.reads)
+            self.failUnlessEqual(l1.sample_name, l2.sample_name)
+            self.failUnlessEqual(l1.lane_id, l2.lane_id)
+            if isinstance(l1, eland.ElandLane):
+              self.failUnlessEqual(len(l1.mapped_reads), len(l2.mapped_reads))
+              self.failUnlessEqual(len(l1.mapped_reads), 17)
+              for k in l1.mapped_reads.keys():
+                  self.failUnlessEqual(l1.mapped_reads[k],
+                                       l2.mapped_reads[k])
+
+              self.failUnlessEqual(len(l1.match_codes), 9)
+              self.failUnlessEqual(len(l1.match_codes), len(l2.match_codes))
+              for k in l1.match_codes.keys():
+                  self.failUnlessEqual(l1.match_codes[k],
+                                       l2.match_codes[k])
+            elif isinstance(l1, eland.SequenceLane):
+                self.failUnlessEqual(l1.sequence_type, l2.sequence_type)
+
+    def test_runfolder(self):
+        return
+        runs = runfolder.get_runs(self.runfolder_dir)
+
+        # do we get the flowcell id from the filename?
+        self.failUnlessEqual(len(runs), 1)
+        name = 'run_4286GAAXX_%s.xml' % ( date.today().strftime('%Y-%m-%d'),)
+        self.failUnlessEqual(runs[0].name, name)
+
+        # do we get the flowcell id from the FlowcellId.xml file
+        make_flowcell_id(self.runfolder_dir, '207BTAAXY')
+        runs = runfolder.get_runs(self.runfolder_dir)
+        self.failUnlessEqual(len(runs), 1)
+        name = 'run_207BTAAXY_%s.xml' % ( date.today().strftime('%Y-%m-%d'),)
+        self.failUnlessEqual(runs[0].name, name)
+
+        r1 = runs[0]
+        xml = r1.get_elements()
+        xml_str = ElementTree.tostring(xml)
+
+        r2 = runfolder.PipelineRun(xml=xml)
+        self.failUnlessEqual(r1.name, r2.name)
+        self.failIfEqual(r2.image_analysis, None)
+        self.failIfEqual(r2.bustard, None)
+        self.failIfEqual(r2.gerald, None)
+
+
+def suite():
+    return unittest.makeSuite(RunfolderTests,'test')
+
+if __name__ == "__main__":
+    #unittest.main(defaultTest="suite")
+    class Test(object): pass
+    t = Test()
+    make_runfolder(t)
+    print ('path ' + t.runfolder_dir)
+
index 3587e6505325571e8327291aa9e80d2ac93ded17..e00f5ec8efaf12ee2a94d70749407c44fe754742 100644 (file)
@@ -4,24 +4,56 @@ import unittest
 
 from htsworkflow.pipelines import sequences
 
+
 class SequenceFileTests(unittest.TestCase):
     """
     Make sure the sequence archive class works
     """
+    def test_get_flowcell_cycle(self):
+        tests = [
+            ('/root/42BW9AAXX/C1-152',
+             sequences.FlowcellPath('42BW9AAXX', 1, 152, None)),
+            ('/root/42BW9AAXX/C1-152/',
+             sequences.FlowcellPath('42BW9AAXX', 1, 152, None)),
+            ('/root/42BW9AAXX/C1-152/Project_12345',
+             sequences.FlowcellPath('42BW9AAXX', 1, 152, 'Project_12345')),
+            ('/root/42BW9AAXX/C1-152/Project_12345/',
+             sequences.FlowcellPath('42BW9AAXX', 1, 152, 'Project_12345')),
+        ]
+
+        for t in tests:
+            path = sequences.get_flowcell_cycle(t[0])
+            self.failUnlessEqual(path, t[1])
+
     def test_flowcell_cycle(self):
         """
         Make sure code to parse directory heirarchy works
         """
         path = '/root/42BW9AAXX/C1-152'
-        flowcell, start, stop = sequences.get_flowcell_cycle(path)
+        flowcell, start, stop, project = sequences.get_flowcell_cycle(path)
 
         self.failUnlessEqual(flowcell, '42BW9AAXX')
         self.failUnlessEqual(start, 1)
         self.failUnlessEqual(stop, 152)
+        self.failUnlessEqual(project, None)
 
         path = '/root/42BW9AAXX/other'
         self.failUnlessRaises(ValueError, sequences.get_flowcell_cycle, path)
 
+    def test_flowcell_project_cycle(self):
+        """
+        Make sure code to parse directory heirarchy works
+        """
+        path = '/root/42BW9AAXX/C1-152/Project_12345_Index1'
+        flowcell, start, stop, project = sequences.get_flowcell_cycle(path)
+
+        self.failUnlessEqual(flowcell, '42BW9AAXX')
+        self.failUnlessEqual(start, 1)
+        self.failUnlessEqual(stop, 152)
+        self.failUnlessEqual(project, 'Project_12345_Index1')
+
+        path = '/root/42BW9AAXX/other'
+        self.failUnlessRaises(ValueError, sequences.get_flowcell_cycle, path)
 
     def test_srf(self):
         path = '/root/42BW9AAXX/C1-38'
@@ -90,6 +122,52 @@ class SequenceFileTests(unittest.TestCase):
         self.failUnlessEqual(f.pf, False)
         self.failUnlessEqual(f.cycle, 38)
 
+    def test_project_fastq(self):
+        path = '/root/42BW9AAXX/C1-38/Project_12345'
+        name = '11111_NoIndex_L001_R1_001.fastq.gz'
+        pathname = os.path.join(path,name)
+        f = sequences.parse_fastq(path, name)
+
+        self.failUnlessEqual(f.filetype, 'split_fastq')
+        self.failUnlessEqual(f.path, pathname)
+        self.failUnlessEqual(f.flowcell, '42BW9AAXX')
+        self.failUnlessEqual(f.lane, 1)
+        self.failUnlessEqual(f.read, 1)
+        self.failUnlessEqual(f.pf, True)
+        self.failUnlessEqual(f.project, '11111')
+        self.failUnlessEqual(f.index, 'NoIndex')
+        self.failUnlessEqual(f.cycle, 38)
+
+        name = '11112_AAATTT_L001_R2_003.fastq.gz'
+        pathname = os.path.join(path,name)
+        f = sequences.parse_fastq(path, name)
+
+        self.failUnlessEqual(f.filetype, 'split_fastq')
+        self.failUnlessEqual(f.path, pathname)
+        self.failUnlessEqual(f.flowcell, '42BW9AAXX')
+        self.failUnlessEqual(f.lane, 1)
+        self.failUnlessEqual(f.read, 2)
+        self.failUnlessEqual(f.pf, True)
+        self.failUnlessEqual(f.project, '11112')
+        self.failUnlessEqual(f.index, 'AAATTT')
+        self.failUnlessEqual(f.cycle, 38)
+
+    def test_project_fastq_hashing(self):
+        """Can we tell the difference between sequence files?
+        """
+        path = '/root/42BW9AAXX/C1-38/Project_12345'
+        names = [('11111_NoIndex_L001_R1_001.fastq.gz',
+                  '11111_NoIndex_L001_R2_001.fastq.gz'),
+                 ('11112_NoIndex_L001_R1_001.fastq.gz',
+                  '11112_NoIndex_L001_R1_002.fastq.gz')
+                 ]
+        for a_name, b_name in names:
+            a = sequences.parse_fastq(path, a_name)
+            b = sequences.parse_fastq(path, b_name)
+            self.failIfEqual(a, b)
+            self.failIfEqual(a.key(), b.key())
+            self.failIfEqual(hash(a), hash(b))
+
     def test_eland(self):
         path = '/root/42BW9AAXX/C1-38'
         name = 's_4_eland_extended.txt.bz2'
@@ -134,7 +212,7 @@ class SequenceFileTests(unittest.TestCase):
         db = sqlite3.connect(":memory:")
         c = db.cursor()
         sequences.create_sequence_table(c)
-        
+
         data = [('/root/42BW9AAXX/C1-152',
                 'woldlab_090622_HWI-EAS229_0120_42BW9AAXX_l1_r1.tar.bz2'),
                 ('/root/42BW9AAXX/C1-152',
@@ -151,7 +229,7 @@ class SequenceFileTests(unittest.TestCase):
         count = c.execute("select count(*) from sequences")
         row = count.fetchone()
         self.failUnlessEqual(row[0], 4)
+
 
 def suite():
     return unittest.makeSuite(SequenceFileTests,'test')
diff --git a/htsworkflow/pipelines/test/test_summary.py b/htsworkflow/pipelines/test/test_summary.py
new file mode 100644 (file)
index 0000000..ab9f962
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+import os
+from StringIO import StringIO
+import unittest
+
+from htsworkflow.pipelines import summary
+from simulate_runfolder import TESTDATA_DIR
+
+class SummaryTests(unittest.TestCase):
+    """Test elements of the summary file parser
+    """
+    def test_is_xml(self):
+        xmlfile = StringIO('<?xml version="1.0"?>\n<tag>\n')
+        htmlfile = StringIO('<html>\n<head></head>\n<body><p></p></body>\n</html>')
+
+        self.failUnlessEqual(summary.isxml_stream(xmlfile), True)
+        self.failUnlessEqual(xmlfile.tell(), 0)
+
+        self.failUnlessEqual(summary.isxml_stream(htmlfile), False)
+
+    def test_xml_summary_file(self):
+        pathname = os.path.join(TESTDATA_DIR, 'Summary-casava1.7.xml')
+        s = summary.Summary(pathname)
+        self.failUnlessEqual(len(s.lane_results[0]), 8)
+        self.failUnlessEqual(s.lane_results[0][1].cluster, (1073893, 146344))
+
+    def test_html_summary_file(self):
+        pathname = os.path.join(TESTDATA_DIR, 'Summary-ipar130.htm')
+        s = summary.Summary(pathname)
+        self.failUnlessEqual(len(s.lane_results[0]), 8)
+        self.failUnlessEqual(s.lane_results[0][1].cluster, (126910, 4300))
+
+    def test_hiseq_sample_summary_file(self):
+        pathname = os.path.join(TESTDATA_DIR, 'sample_summary_1_12.htm')
+        s = summary.Summary(pathname)
+
+def suite():
+    return unittest.makeSuite(SummaryTests,'test')
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="suite")
diff --git a/htsworkflow/pipelines/test/testdata/aligned_config_1_12.xml b/htsworkflow/pipelines/test/testdata/aligned_config_1_12.xml
new file mode 100644 (file)
index 0000000..2b7f3af
--- /dev/null
@@ -0,0 +1,234 @@
+<?xml version="1.0"?>
+<RunParameters>
+  <Barcodes>
+  </Barcodes>
+  <Defaults>
+    <ANALYSIS>none</ANALYSIS>
+    <CHROM_NAME_SOURCE>fileName</CHROM_NAME_SOURCE>
+    <CHROM_NAME_VALIDATION>on</CHROM_NAME_VALIDATION>
+    <CMDPREFIX></CMDPREFIX>
+    <DATASET_POST_RUN_COMMAND></DATASET_POST_RUN_COMMAND>
+    <ELAND_EXTENDED_MULTI_READS>off</ELAND_EXTENDED_MULTI_READS>
+    <ELAND_FASTQ_FILES_PER_PROCESS>3</ELAND_FASTQ_FILES_PER_PROCESS>
+    <ELAND_GENOME></ELAND_GENOME>
+    <ELAND_GENOME_MASK>*.fa</ELAND_GENOME_MASK>
+    <ELAND_MAX_MATCHES></ELAND_MAX_MATCHES>
+    <ELAND_PARAMS></ELAND_PARAMS>
+    <ELAND_REPEAT></ELAND_REPEAT>
+    <ELAND_RNA_GENE_MD_GROUP_LABEL></ELAND_RNA_GENE_MD_GROUP_LABEL>
+    <ELAND_RNA_GENOME_ANNOTATION></ELAND_RNA_GENOME_ANNOTATION>
+    <ELAND_RNA_GENOME_CONTAM></ELAND_RNA_GENOME_CONTAM>
+    <ELAND_RNA_GENOME_CONTAM_MASK>*.fa</ELAND_RNA_GENOME_CONTAM_MASK>
+    <ELAND_RNA_MULTI_READS>off</ELAND_RNA_MULTI_READS>
+    <ELAND_SEED_LENGTH1>32</ELAND_SEED_LENGTH1>
+    <ELAND_SEED_LENGTH2></ELAND_SEED_LENGTH2>
+    <EMAIL_DOMAIN>domain.com</EMAIL_DOMAIN>
+    <EMAIL_LIST>${logName}</EMAIL_LIST>
+    <EMAIL_SERVER>localhost:25</EMAIL_SERVER>
+    <EXPT_DIR>/mmjggl/nicodemus/data01/sequencer/110815_SN787_0101_AD07K6ACXX/Unaligned_1MM</EXPT_DIR>
+    <FLAT_TXT_GZ_SUFFIX>Flat.txt.gz</FLAT_TXT_GZ_SUFFIX>
+    <FLOWCELL>D07K6ACXX</FLOWCELL>
+    <GENE_MD_GZ_SUFFIX>_gene.md.gz</GENE_MD_GZ_SUFFIX>
+    <INCREASED_SENSITIVITY></INCREASED_SENSITIVITY>
+    <KAGU_PAIR_PARAMS>--muf 0</KAGU_PAIR_PARAMS>
+    <KAGU_PARAMS>--mmaq 4</KAGU_PARAMS>
+    <NUM_LEADING_DIRS_TO_STRIP>2</NUM_LEADING_DIRS_TO_STRIP>
+    <OA_SUFFIX>.oa</OA_SUFFIX>
+    <ORIGINAL_READS>1</ORIGINAL_READS>
+    <ORIGINAL_READ_LENGTH1>50</ORIGINAL_READ_LENGTH1>
+    <ORPHAN_ALIGNER_PARAMS>2</ORPHAN_ALIGNER_PARAMS>
+    <OUT_DIR>/mmjggl/nicodemus/data01/sequencer/110815_SN787_0101_AD07K6ACXX/Aligned_1MM</OUT_DIR>
+    <PAS_PARAMS></PAS_PARAMS>
+    <RAMM_REPORT_TYPE></RAMM_REPORT_TYPE>
+    <READS>1</READS>
+    <READ_LENGTH1>49</READ_LENGTH1>
+    <RNAQC_COUNT_CLUSTERS_CMD>$(WC) -l</RNAQC_COUNT_CLUSTERS_CMD>
+    <RNAQC_COUNT_CLUSTERS_NAME>totalClusters</RNAQC_COUNT_CLUSTERS_NAME>
+    <RNAQC_COUNT_GENOME_CMD>($(GREP) -cvE '^((NM|QC|RM|[0-9]+:[0-9]+:[0-9]+)$$|splice_sites)' || exit 0)</RNAQC_COUNT_GENOME_CMD>
+    <RNAQC_COUNT_GENOME_NAME>genomeUsable</RNAQC_COUNT_GENOME_NAME>
+    <RNAQC_COUNT_NM_CMD>($(FGREP) -wc NM || exit 0)</RNAQC_COUNT_NM_CMD>
+    <RNAQC_COUNT_NM_NAME>noMatch</RNAQC_COUNT_NM_NAME>
+    <RNAQC_COUNT_PF_CMD>$(WC) -l</RNAQC_COUNT_PF_CMD>
+    <RNAQC_COUNT_PF_NAME>PFClusters</RNAQC_COUNT_PF_NAME>
+    <RNAQC_COUNT_QC_CMD>($(FGREP) -wc QC || exit 0)</RNAQC_COUNT_QC_CMD>
+    <RNAQC_COUNT_QC_NAME>QC</RNAQC_COUNT_QC_NAME>
+    <RNAQC_COUNT_RM_CMD>($(FGREP) -wc RM || exit 0)</RNAQC_COUNT_RM_CMD>
+    <RNAQC_COUNT_RM_NAME>repeatMasked</RNAQC_COUNT_RM_NAME>
+    <RNAQC_COUNT_SPLICE_CMD>($(FGREP) -c splice_sites || exit 0)</RNAQC_COUNT_SPLICE_CMD>
+    <RNAQC_COUNT_SPLICE_NAME>spliceUsable</RNAQC_COUNT_SPLICE_NAME>
+    <RNAQC_COUNT_USABLE_CMD>$(CUT) -f13 |($(EGREP) [0-9] || exit 0)|$(WC) -l</RNAQC_COUNT_USABLE_CMD>
+    <RNAQC_COUNT_USABLE_NAME>usable</RNAQC_COUNT_USABLE_NAME>
+    <RNAQC_FIND_CONTAMS_CMD>($(GREP) -vE '^(NM|QC|RM|[0-9]+:[0-9]+:[0-9]+)$$' || exit 0)</RNAQC_FIND_CONTAMS_CMD>
+    <SAMTOOLS_GENOME></SAMTOOLS_GENOME>
+    <SEQGENEMD2REFFLAT_PARAMS></SEQGENEMD2REFFLAT_PARAMS>
+    <SINGLESEED></SINGLESEED>
+    <SPLCSTS_PARAMS>-v $(CASAVA_LOG_LEVEL)</SPLCSTS_PARAMS>
+    <SQUASH_GENOME_PARAMS></SQUASH_GENOME_PARAMS>
+    <UNGAPPED></UNGAPPED>
+    <USE_BASES>y*n</USE_BASES>
+    <USE_BASES1>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyn</USE_BASES1>
+    <WEB_DIR_ROOT>http://host.domain.com/yourshare/</WEB_DIR_ROOT>
+    <WITH_ORPHAN_ALIGNER>true</WITH_ORPHAN_ALIGNER>
+  </Defaults>
+  <Lanes>
+    <Lane index="1">
+      <Barcodes></Barcodes>
+      <Defaults>
+        <ANALYSIS>eland_extended</ANALYSIS>
+        <CHROM_NAME_SOURCE>fileName</CHROM_NAME_SOURCE>
+        <ELAND_GENOME>/mmjggl/nicodemus/data01/genomes/elegans190/chromosomes/</ELAND_GENOME>
+        <ELAND_GENOME_MASK>*.fa</ELAND_GENOME_MASK>
+        <ELAND_SEED_LENGTH1>32</ELAND_SEED_LENGTH1>
+        <READS>1</READS>
+        <READ_LENGTH1>49</READ_LENGTH1>
+        <Tiles>1101 1102 1103 1104 1105 1106 1107 1108 1201 1202 1203 1204 1205 1206 1207 1208 1301 1302 1303 1304 1305 1306 1307 1308 2101 2102 2103 2104 2105 2106 2107 2108 2201 2202 2203 2204 2205 2206 2207 2208 2301 2302 2303 2304 2305 2306 2307 2308</Tiles>
+        <USE_BASES>Y*n</USE_BASES>
+        <USE_BASES1>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyn</USE_BASES1>
+      </Defaults>
+      <Projects></Projects>
+      <References></References>
+      <Samples></Samples>
+    </Lane>
+    <Lane index="2">
+      <Barcodes></Barcodes>
+      <Defaults>
+        <ANALYSIS>eland_extended</ANALYSIS>
+        <CHROM_NAME_SOURCE>fileName</CHROM_NAME_SOURCE>
+        <ELAND_GENOME>/mmjggl/nicodemus/data01/genomes/elegans190/chromosomes/</ELAND_GENOME>
+        <ELAND_GENOME_MASK>*.fa</ELAND_GENOME_MASK>
+        <ELAND_SEED_LENGTH1>32</ELAND_SEED_LENGTH1>
+        <READS>1</READS>
+        <READ_LENGTH1>49</READ_LENGTH1>
+        <Tiles>1101 1102 1103 1104 1105 1106 1107 1108 1201 1202 1203 1204 1205 1206 1207 1208 1301 1302 1303 1304 1305 1306 1307 1308 2101 2102 2103 2104 2105 2106 2107 2108 2201 2202 2203 2204 2205 2206 2207 2208 2301 2302 2303 2304 2305 2306 2307 2308</Tiles>
+        <USE_BASES>Y*n</USE_BASES>
+        <USE_BASES1>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyn</USE_BASES1>
+      </Defaults>
+      <Projects></Projects>
+      <References></References>
+      <Samples></Samples>
+    </Lane>
+    <Lane index="4">
+      <Barcodes></Barcodes>
+      <Defaults>
+        <ANALYSIS>eland_extended</ANALYSIS>
+        <CHROM_NAME_SOURCE>fileName</CHROM_NAME_SOURCE>
+        <ELAND_GENOME>/mmjggl/nicodemus/data01/genomes/hg18/chromosomes/</ELAND_GENOME>
+        <ELAND_GENOME_MASK>*.fa</ELAND_GENOME_MASK>
+        <ELAND_SEED_LENGTH1>32</ELAND_SEED_LENGTH1>
+        <READS>1</READS>
+        <READ_LENGTH1>49</READ_LENGTH1>
+        <Tiles>1101 1102 1103 1104 1105 1106 1107 1108 1201 1202 1203 1204 1205 1206 1207 1208 1301 1302 1303 1304 1305 1306 1307 1308 2101 2102 2103 2104 2105 2106 2107 2108 2201 2202 2203 2204 2205 2206 2207 2208 2301 2302 2303 2304 2305 2306 2307 2308</Tiles>
+        <USE_BASES>Y*n</USE_BASES>
+        <USE_BASES1>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyn</USE_BASES1>
+      </Defaults>
+      <Projects></Projects>
+      <References></References>
+      <Samples></Samples>
+    </Lane>
+    <Lane index="5">
+      <Barcodes></Barcodes>
+      <Defaults>
+        <ANALYSIS>eland_extended</ANALYSIS>
+        <CHROM_NAME_SOURCE>fileName</CHROM_NAME_SOURCE>
+        <ELAND_GENOME>/mmjggl/nicodemus/data01/genomes/hg18/chromosomes/</ELAND_GENOME>
+        <ELAND_GENOME_MASK>*.fa</ELAND_GENOME_MASK>
+        <ELAND_SEED_LENGTH1>32</ELAND_SEED_LENGTH1>
+        <READS>1</READS>
+        <READ_LENGTH1>49</READ_LENGTH1>
+        <Tiles>1101 1102 1103 1104 1105 1106 1107 1108 1201 1202 1203 1204 1205 1206 1207 1208 1301 1302 1303 1304 1305 1306 1307 1308 2101 2102 2103 2104 2105 2106 2107 2108 2201 2202 2203 2204 2205 2206 2207 2208 2301 2302 2303 2304 2305 2306 2307 2308</Tiles>
+        <USE_BASES>Y*n</USE_BASES>
+        <USE_BASES1>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyn</USE_BASES1>
+      </Defaults>
+      <Projects></Projects>
+      <References></References>
+      <Samples></Samples>
+    </Lane>
+    <Lane index="6">
+      <Barcodes></Barcodes>
+      <Defaults>
+        <ANALYSIS>eland_extended</ANALYSIS>
+        <CHROM_NAME_SOURCE>fileName</CHROM_NAME_SOURCE>
+        <ELAND_GENOME>/mmjggl/nicodemus/data01/genomes/hg18/chromosomes/</ELAND_GENOME>
+        <ELAND_GENOME_MASK>*.fa</ELAND_GENOME_MASK>
+        <ELAND_SEED_LENGTH1>32</ELAND_SEED_LENGTH1>
+        <READS>1</READS>
+        <READ_LENGTH1>49</READ_LENGTH1>
+        <Tiles>1101 1102 1103 1104 1105 1106 1107 1108 1201 1202 1203 1204 1205 1206 1207 1208 1301 1302 1303 1304 1305 1306 1307 1308 2101 2102 2103 2104 2105 2106 2107 2108 2201 2202 2203 2204 2205 2206 2207 2208 2301 2302 2303 2304 2305 2306 2307 2308</Tiles>
+        <USE_BASES>Y*n</USE_BASES>
+        <USE_BASES1>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyn</USE_BASES1>
+      </Defaults>
+      <Projects></Projects>
+      <References></References>
+      <Samples></Samples>
+    </Lane>
+    <Lane index="7">
+      <Barcodes></Barcodes>
+      <Defaults>
+        <ANALYSIS>none</ANALYSIS>
+        <Tiles>1101 1102 1103 1104 1105 1106 1107 1108 1201 1202 1203 1204 1205 1206 1207 1208 1301 1302 1303 1304 1305 1306 1307 1308 2101 2102 2103 2104 2105 2106 2107 2108 2201 2202 2203 2204 2205 2206 2207 2208 2301 2302 2303 2304 2305 2306 2307 2308</Tiles>
+      </Defaults>
+      <Projects></Projects>
+      <References></References>
+      <Samples></Samples>
+    </Lane>
+    <Lane index="8">
+      <Barcodes></Barcodes>
+      <Defaults>
+        <ANALYSIS>none</ANALYSIS>
+        <Tiles>1101 1102 1103 1104 1105 1106 1107 1108 1201 1202 1203 1204 1205 1206 1207 1208 1301 1302 1303 1304 1305 1306 1307 1308 2101 2102 2103 2104 2105 2106 2107 2108 2201 2202 2203 2204 2205 2206 2207 2208 2301 2302 2303 2304 2305 2306 2307 2308</Tiles>
+      </Defaults>
+      <Projects></Projects>
+      <References></References>
+      <Samples></Samples>
+    </Lane>
+    <Lane index="3">
+      <Barcodes></Barcodes>
+      <Defaults>
+        <Tiles>1101 1102 1103 1104 1105 1106 1107 1108 1201 1202 1203 1204 1205 1206 1207 1208 1301 1302 1303 1304 1305 1306 1307 1308 2101 2102 2103 2104 2105 2106 2107 2108 2201 2202 2203 2204 2205 2206 2207 2208 2301 2302 2303 2304 2305 2306 2307 2308</Tiles>
+      </Defaults>
+      <Projects></Projects>
+      <References></References>
+      <Samples></Samples>
+    </Lane>
+  </Lanes>
+  <Projects>
+    <Project name="12383">
+      <ANALYSIS>eland_extended</ANALYSIS>
+      <CHROM_NAME_SOURCE>fileName</CHROM_NAME_SOURCE>
+      <ELAND_GENOME>/mmjggl/nicodemus/data01/genomes/hg18/chromosomes/</ELAND_GENOME>
+      <ELAND_GENOME_MASK>*.fa</ELAND_GENOME_MASK>
+      <ELAND_SEED_LENGTH1>32</ELAND_SEED_LENGTH1>
+      <READS>1</READS>
+      <READ_LENGTH1>49</READ_LENGTH1>
+      <USE_BASES>Y*n</USE_BASES>
+      <USE_BASES1>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyn</USE_BASES1>
+    </Project>
+    <Project name="Undetermined_indices">
+      <ANALYSIS>none</ANALYSIS>
+    </Project>
+  </Projects>
+  <References>
+    <Reference name="mm9">
+      <ANALYSIS>eland_extended</ANALYSIS>
+      <CHROM_NAME_SOURCE>fileName</CHROM_NAME_SOURCE>
+      <ELAND_GENOME>/mmjggl/nicodemus/data01/genomes/mm9/chromosomes/</ELAND_GENOME>
+      <ELAND_GENOME_MASK>*.fa</ELAND_GENOME_MASK>
+      <ELAND_SEED_LENGTH1>32</ELAND_SEED_LENGTH1>
+      <READS>1</READS>
+      <READ_LENGTH1>49</READ_LENGTH1>
+      <USE_BASES>Y*n</USE_BASES>
+      <USE_BASES1>yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyn</USE_BASES1>
+    </Reference>
+  </References>
+  <Samples>
+  </Samples>
+  <Software CmdAndArgs="/mmjggl/nicodemus/data01/casava-v1.8.1/bin/configureAlignment.pl config.txt --EXPT_DIR /mmjggl/nicodemus/data01/sequencer/110815_SN787_0101_AD07K6ACXX/Unaligned_1MM/ --OUT_DIR /mmjggl/nicodemus/data01/sequencer/110815_SN787_0101_AD07K6ACXX/Aligned_1MM -make" Name="configureAlignment.pl" Version="CASAVA-1.8.1">
+    <Software CmdAndArgs="/mmjggl/nicodemus/data01/casava-v1.8.1/bin/configureBclToFastq.pl --input-dir Data/Intensities/BaseCalls/ --output-dir Unaligned_1MM --sample-sheet Data/Intensities/BaseCalls/SampleSheet.csv --mismatches 1" Name="configureBclToFastq.pl" Version="CASAVA-1.8.1">
+      <Software Name="RTA" Version="1.12.4.2">
+        <Software Name="RTA" Version="1.12.4.2">
+          <Software Name="HiSeq Control Software" Platform="HiSeq" Version="1.4.8" />
+        </Software>
+      </Software>
+    </Software>
+  </Software>
+</RunParameters>
diff --git a/htsworkflow/pipelines/test/testdata/demultiplex_1.12.4.2.xml b/htsworkflow/pipelines/test/testdata/demultiplex_1.12.4.2.xml
new file mode 100644 (file)
index 0000000..e7ee38d
--- /dev/null
@@ -0,0 +1,71 @@
+<DemultiplexConfig>
+  <Software Version="CASAVA-1.8.1" CmdAndArgs="/mmjggl/nicodemus/data01/casava-v1.8.1/bin/configureBclToFastq.pl --input-dir Data/Intensities/BaseCalls/ --output-dir Unaligned --sample-sheet Data/Intensities/BaseCalls/SampleSheet.csv" Name="configureBclToFastq.pl">
+    <Software Version="1.12.4.2" Name="RTA">
+      <Software Version="1.12.4.2" Name="RTA">
+        <Software Version="1.4.8" Platform="HiSeq" Name="HiSeq Control Software" />
+      </Software>
+    </Software>
+  </Software>
+  <FlowcellInfo ID="D07K6ACXX" Operator="Lorian" Recipe="SR_indexing" Desc="">
+    <Lane Number="1">
+      <Sample ProjectId="12281" Control="N" Index="ACAGTG" SampleId="12281" Desc="Index #5 AWCon cell#3_N2" Ref="elegans190" />
+      <Sample ProjectId="12279" Control="N" Index="CGATGT" SampleId="12279" Desc="Index #2 AWCon cell#1_N2" Ref="elegans190" />
+      <Sample ProjectId="12280" Control="N" Index="TGACCA" SampleId="12280" Desc="Index #4 AWCon cell#2_N2" Ref="elegans190" />
+      <Sample ProjectId="Undetermined_indices" Control="N" Index="Undetermined" SampleId="lane1" Desc="Clusters with unmatched barcodes for lane 1" Ref="unknown" />
+    </Lane>
+    <Lane Number="2">
+      <Sample ProjectId="12345" Control="N" Index="ACAGTG" SampleId="12345" Desc="Index #5 3 AWC ablated CX3695" Ref="elegans190" />
+      <Sample ProjectId="12283" Control="N" Index="CAGATC" SampleId="12283" Desc="Index #7 AWCon cell#5_N2" Ref="elegans190" />
+      <Sample ProjectId="12282" Control="N" Index="GCCAAT" SampleId="12282" Desc="Index #6 AWCon cell#4_N2" Ref="elegans190" />
+      <Sample ProjectId="Undetermined_indices" Control="N" Index="Undetermined" SampleId="lane2" Desc="Clusters with unmatched barcodes for lane 2" Ref="unknown" />
+    </Lane>
+    <Lane Number="3">
+      <Sample ProjectId="12331" Control="N" Index="ACAGTG" SampleId="12331" Desc="Index #5 060111 FLDN2b(d8.5) H3K4me3 ChIP" Ref="mm9" />
+      <Sample ProjectId="12383" Control="N" Index="CGATGT" SampleId="12383" Desc="Index #2 jwp ix-65 ni 16h" Ref="hg18" />
+      <Sample ProjectId="12330" Control="N" Index="TGACCA" SampleId="12330" Desc="Index #4 060111 Bcl11bKO DL4 FLDN2a H3K4me3 ChIP" Ref="mm9" />
+      <Sample ProjectId="Undetermined_indices" Control="N" Index="Undetermined" SampleId="lane3" Desc="Clusters with unmatched barcodes for lane 3" Ref="unknown" />
+    </Lane>
+    <Lane Number="4">
+      <Sample ProjectId="12385" Control="N" Index="ACAGTG" SampleId="12385" Desc="Index #5 jwp ix-65 i 16h" Ref="hg18" />
+      <Sample ProjectId="12386" Control="N" Index="GCCAAT" SampleId="12386" Desc="Index #6 jwp ix-71 NI 16h" Ref="hg18" />
+      <Sample ProjectId="12384" Control="N" Index="TGACCA" SampleId="12384" Desc="index #4 jwp ix-65 RD 16h" Ref="hg18" />
+      <Sample ProjectId="Undetermined_indices" Control="N" Index="Undetermined" SampleId="lane4" Desc="Clusters with unmatched barcodes for lane 4" Ref="unknown" />
+    </Lane>
+    <Lane Number="5">
+      <Sample ProjectId="12387" Control="N" Index="CAGATC" SampleId="12387" Desc="Index #7 jwp ix-71 RD 16h" Ref="hg18" />
+      <Sample ProjectId="12388" Control="N" Index="CTTGTA" SampleId="12388" Desc="Index #12 jwp ix-71 i 16h" Ref="hg18" />
+      <Sample ProjectId="Undetermined_indices" Control="N" Index="Undetermined" SampleId="lane5" Desc="Clusters with unmatched barcodes for lane 5" Ref="unknown" />
+    </Lane>
+    <Lane Number="6">
+      <Sample ProjectId="12391" Control="N" Index="ACTTGA" SampleId="12391" Desc="Index #8 jwp ix-63 NI 4h" Ref="hg18" />
+      <Sample ProjectId="12392" Control="N" Index="GATCAG" SampleId="12392" Desc="Index #9 jwp ix-63 DHT 10uM PA 4h" Ref="hg18" />
+      <Sample ProjectId="12393" Control="N" Index="TAGCTT" SampleId="12393" Desc="Index #10 jwp ix-63 DHT 4h" Ref="hg18" />
+      <Sample ProjectId="Undetermined_indices" Control="N" Index="Undetermined" SampleId="lane6" Desc="Clusters with unmatched barcodes for lane 6" Ref="unknown" />
+    </Lane>
+    <Lane Number="7">
+      <Sample ProjectId="12348_Index5" Control="N" Index="ACAGTG" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="12348_Index8" Control="N" Index="ACTTGA" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="12348_Index1" Control="N" Index="ATCACG" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="12348_Index7" Control="N" Index="CAGATC" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="12348_Index2" Control="N" Index="CGATGT" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="12348_Index9" Control="N" Index="GATCAG" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="12348_Index6" Control="N" Index="GCCAAT" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="12348_Index4" Control="N" Index="TGACCA" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="12348_Index3" Control="N" Index="TTAGGC" SampleId="12348" Desc="Indices #1-9 Small RNA OSS TJ-GFP and constr.E-H" Ref="dm3" />
+      <Sample ProjectId="Undetermined_indices" Control="N" Index="Undetermined" SampleId="lane7" Desc="Clusters with unmatched barcodes for lane 7" Ref="unknown" />
+    </Lane>
+    <Lane Number="8">
+      <Sample ProjectId="12382_Index5" Control="N" Index="ACAGTG" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index8" Control="N" Index="ACTTGA" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index1" Control="N" Index="ATCACG" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index7" Control="N" Index="CAGATC" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index2" Control="N" Index="CGATGT" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index9" Control="N" Index="GATCAG" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index6" Control="N" Index="GCCAAT" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index10" Control="N" Index="TAGCTT" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index4" Control="N" Index="TGACCA" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="12382_Index3" Control="N" Index="TTAGGC" SampleId="12382" Desc="Small RNA Index #RPI1-RPI10 Human bladder cancer small RNA" Ref="hg18" />
+      <Sample ProjectId="Undetermined_indices" Control="N" Index="Undetermined" SampleId="lane8" Desc="Clusters with unmatched barcodes for lane 8" Ref="unknown" />
+    </Lane>
+  </FlowcellInfo>
+</DemultiplexConfig>
diff --git a/htsworkflow/pipelines/test/testdata/demultiplexed_bustard_1.12.4.2.xml b/htsworkflow/pipelines/test/testdata/demultiplexed_bustard_1.12.4.2.xml
new file mode 100644 (file)
index 0000000..ea6a596
--- /dev/null
@@ -0,0 +1,503 @@
+<?xml version="1.0"?>
+<BaseCallAnalysis xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <Run Name="BaseCalls">
+    <BaseCallParameters>
+      <ChastityThreshold>0.6</ChastityThreshold>
+      <Matrix Path="">
+        <AutoFlag>2</AutoFlag>
+        <AutoLane>0</AutoLane>
+        <Cycle>1</Cycle>
+        <CycleOffset>0</CycleOffset>
+        <FirstCycle>1</FirstCycle>
+        <LastCycle>50</LastCycle>
+        <Read>1</Read>
+      </Matrix>
+      <Matrix Path="">
+        <AutoFlag>2</AutoFlag>
+        <AutoLane>0</AutoLane>
+        <Cycle>51</Cycle>
+        <CycleOffset>0</CycleOffset>
+        <FirstCycle>51</FirstCycle>
+        <LastCycle>57</LastCycle>
+        <Read>2</Read>
+      </Matrix>
+      <Phasing Path="">
+        <AutoFlag>2</AutoFlag>
+        <AutoLane>0</AutoLane>
+        <Cycle>2</Cycle>
+        <CycleOffset>1</CycleOffset>
+        <FirstCycle>1</FirstCycle>
+        <LastCycle>50</LastCycle>
+        <PhasingRate>0</PhasingRate>
+        <PrephasingRate>0</PrephasingRate>
+        <Read>1</Read>
+      </Phasing>
+      <Phasing Path="">
+        <AutoFlag>2</AutoFlag>
+        <AutoLane>0</AutoLane>
+        <Cycle>52</Cycle>
+        <CycleOffset>1</CycleOffset>
+        <FirstCycle>51</FirstCycle>
+        <LastCycle>57</LastCycle>
+        <PhasingRate>0</PhasingRate>
+        <PrephasingRate>0</PrephasingRate>
+        <Read>2</Read>
+      </Phasing>
+      <PureBases>0</PureBases>
+      <SmtFilter>failed-chastity</SmtFilter>
+      <SmtRelation>le</SmtRelation>
+      <SmtThreshold>1.0</SmtThreshold>
+    </BaseCallParameters>
+    <Cycles First="1" Last="57" Number="57"/>
+    <RunParameters>
+      <AutoCycleFlag>0</AutoCycleFlag>
+      <Barcode>
+        <Cycle Use="true">51</Cycle>
+        <Cycle Use="true">52</Cycle>
+        <Cycle Use="true">53</Cycle>
+        <Cycle Use="true">54</Cycle>
+        <Cycle Use="true">55</Cycle>
+        <Cycle Use="true">56</Cycle>
+        <Cycle Use="true">57</Cycle>
+      </Barcode>
+      <BasecallFlag>0</BasecallFlag>
+      <Deblocked>0</Deblocked>
+      <DebugFlag>0</DebugFlag>
+      <FirstRunOnlyFlag>0</FirstRunOnlyFlag>
+      <ImagingReads Index="1">
+        <FirstCycle>1</FirstCycle>
+        <LastCycle>50</LastCycle>
+      </ImagingReads>
+      <ImagingReads Index="2">
+        <FirstCycle>51</FirstCycle>
+        <LastCycle>57</LastCycle>
+        <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>
+      </ImagingReads>
+      <Instrument>HWI-ST0787</Instrument>
+      <IterativeMatrixFlag>0</IterativeMatrixFlag>
+      <MakeFlag>0</MakeFlag>
+      <MaxCycle>0</MaxCycle>
+      <MinCycle>0</MinCycle>
+      <QTableVersion>New6</QTableVersion>
+      <RunFlowcellId>D07K6ACXX</RunFlowcellId>
+      <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>
+      <RunFolderDate>110815</RunFolderDate>
+      <RunFolderId>0101</RunFolderId>
+      <Reads Index="1">
+        <FirstCycle>1</FirstCycle>
+        <LastCycle>50</LastCycle>
+      </Reads>
+    </RunParameters>
+    <Software Name="RTA" Version="1.12.4.2"/>
+    <TileSelection>
+      <Lane Index="1">
+        <Sample>s</Sample>
+        <Tile>1102</Tile>
+        <Tile>1101</Tile>
+        <Tile>1103</Tile>
+        <Tile>1106</Tile>
+        <Tile>1104</Tile>
+        <Tile>1105</Tile>
+        <Tile>1108</Tile>
+        <Tile>1107</Tile>
+        <Tile>1202</Tile>
+        <Tile>1201</Tile>
+        <Tile>1206</Tile>
+        <Tile>1204</Tile>
+        <Tile>1203</Tile>
+        <Tile>1205</Tile>
+        <Tile>1302</Tile>
+        <Tile>1208</Tile>
+        <Tile>1207</Tile>
+        <Tile>1301</Tile>
+        <Tile>1306</Tile>
+        <Tile>1304</Tile>
+        <Tile>1305</Tile>
+        <Tile>2102</Tile>
+        <Tile>1303</Tile>
+        <Tile>1308</Tile>
+        <Tile>2101</Tile>
+        <Tile>1307</Tile>
+        <Tile>2106</Tile>
+        <Tile>2104</Tile>
+        <Tile>2105</Tile>
+        <Tile>2103</Tile>
+        <Tile>2202</Tile>
+        <Tile>2108</Tile>
+        <Tile>2201</Tile>
+        <Tile>2206</Tile>
+        <Tile>2107</Tile>
+        <Tile>2205</Tile>
+        <Tile>2204</Tile>
+        <Tile>2203</Tile>
+        <Tile>2302</Tile>
+        <Tile>2301</Tile>
+        <Tile>2208</Tile>
+        <Tile>2306</Tile>
+        <Tile>2207</Tile>
+        <Tile>2305</Tile>
+        <Tile>2303</Tile>
+        <Tile>2304</Tile>
+        <Tile>2308</Tile>
+        <Tile>2307</Tile>
+      </Lane>
+      <Lane Index="2">
+        <Sample>s</Sample>
+        <Tile>1101</Tile>
+        <Tile>1102</Tile>
+        <Tile>1105</Tile>
+        <Tile>1106</Tile>
+        <Tile>1104</Tile>
+        <Tile>1103</Tile>
+        <Tile>1201</Tile>
+        <Tile>1202</Tile>
+        <Tile>1108</Tile>
+        <Tile>1206</Tile>
+        <Tile>1107</Tile>
+        <Tile>1205</Tile>
+        <Tile>1302</Tile>
+        <Tile>1204</Tile>
+        <Tile>1301</Tile>
+        <Tile>1203</Tile>
+        <Tile>1208</Tile>
+        <Tile>1306</Tile>
+        <Tile>1305</Tile>
+        <Tile>1207</Tile>
+        <Tile>1304</Tile>
+        <Tile>2101</Tile>
+        <Tile>2102</Tile>
+        <Tile>1308</Tile>
+        <Tile>2105</Tile>
+        <Tile>1303</Tile>
+        <Tile>2201</Tile>
+        <Tile>2106</Tile>
+        <Tile>2104</Tile>
+        <Tile>1307</Tile>
+        <Tile>2205</Tile>
+        <Tile>2202</Tile>
+        <Tile>2108</Tile>
+        <Tile>2206</Tile>
+        <Tile>2103</Tile>
+        <Tile>2301</Tile>
+        <Tile>2204</Tile>
+        <Tile>2208</Tile>
+        <Tile>2107</Tile>
+        <Tile>2302</Tile>
+        <Tile>2305</Tile>
+        <Tile>2304</Tile>
+        <Tile>2203</Tile>
+        <Tile>2306</Tile>
+        <Tile>2308</Tile>
+        <Tile>2207</Tile>
+        <Tile>2303</Tile>
+        <Tile>2307</Tile>
+      </Lane>
+      <Lane Index="3">
+        <Sample>s</Sample>
+        <Tile>1101</Tile>
+        <Tile>1102</Tile>
+        <Tile>1105</Tile>
+        <Tile>1104</Tile>
+        <Tile>1108</Tile>
+        <Tile>1106</Tile>
+        <Tile>1201</Tile>
+        <Tile>1103</Tile>
+        <Tile>1204</Tile>
+        <Tile>1202</Tile>
+        <Tile>1205</Tile>
+        <Tile>1107</Tile>
+        <Tile>1208</Tile>
+        <Tile>1206</Tile>
+        <Tile>1301</Tile>
+        <Tile>1304</Tile>
+        <Tile>1203</Tile>
+        <Tile>1302</Tile>
+        <Tile>1308</Tile>
+        <Tile>1305</Tile>
+        <Tile>1207</Tile>
+        <Tile>2101</Tile>
+        <Tile>2104</Tile>
+        <Tile>1306</Tile>
+        <Tile>1303</Tile>
+        <Tile>2102</Tile>
+        <Tile>2105</Tile>
+        <Tile>2108</Tile>
+        <Tile>1307</Tile>
+        <Tile>2106</Tile>
+        <Tile>2204</Tile>
+        <Tile>2201</Tile>
+        <Tile>2103</Tile>
+        <Tile>2208</Tile>
+        <Tile>2202</Tile>
+        <Tile>2107</Tile>
+        <Tile>2205</Tile>
+        <Tile>2301</Tile>
+        <Tile>2304</Tile>
+        <Tile>2203</Tile>
+        <Tile>2206</Tile>
+        <Tile>2207</Tile>
+        <Tile>2305</Tile>
+        <Tile>2308</Tile>
+        <Tile>2302</Tile>
+        <Tile>2303</Tile>
+        <Tile>2307</Tile>
+        <Tile>2306</Tile>
+      </Lane>
+      <Lane Index="4">
+        <Sample>s</Sample>
+        <Tile>1101</Tile>
+        <Tile>1104</Tile>
+        <Tile>1103</Tile>
+        <Tile>1102</Tile>
+        <Tile>1108</Tile>
+        <Tile>1105</Tile>
+        <Tile>1107</Tile>
+        <Tile>1106</Tile>
+        <Tile>1204</Tile>
+        <Tile>1201</Tile>
+        <Tile>1203</Tile>
+        <Tile>1202</Tile>
+        <Tile>1208</Tile>
+        <Tile>1205</Tile>
+        <Tile>1207</Tile>
+        <Tile>1206</Tile>
+        <Tile>1304</Tile>
+        <Tile>1301</Tile>
+        <Tile>1302</Tile>
+        <Tile>1308</Tile>
+        <Tile>1303</Tile>
+        <Tile>1305</Tile>
+        <Tile>1306</Tile>
+        <Tile>1307</Tile>
+        <Tile>2104</Tile>
+        <Tile>2101</Tile>
+        <Tile>2108</Tile>
+        <Tile>2102</Tile>
+        <Tile>2103</Tile>
+        <Tile>2105</Tile>
+        <Tile>2204</Tile>
+        <Tile>2106</Tile>
+        <Tile>2107</Tile>
+        <Tile>2201</Tile>
+        <Tile>2208</Tile>
+        <Tile>2202</Tile>
+        <Tile>2203</Tile>
+        <Tile>2304</Tile>
+        <Tile>2205</Tile>
+        <Tile>2206</Tile>
+        <Tile>2207</Tile>
+        <Tile>2308</Tile>
+        <Tile>2301</Tile>
+        <Tile>2302</Tile>
+        <Tile>2303</Tile>
+        <Tile>2305</Tile>
+        <Tile>2307</Tile>
+        <Tile>2306</Tile>
+      </Lane>
+      <Lane Index="5">
+        <Sample>s</Sample>
+        <Tile>1104</Tile>
+        <Tile>1108</Tile>
+        <Tile>1101</Tile>
+        <Tile>1204</Tile>
+        <Tile>1102</Tile>
+        <Tile>1103</Tile>
+        <Tile>1106</Tile>
+        <Tile>1105</Tile>
+        <Tile>1107</Tile>
+        <Tile>1208</Tile>
+        <Tile>1201</Tile>
+        <Tile>1202</Tile>
+        <Tile>1203</Tile>
+        <Tile>1304</Tile>
+        <Tile>1205</Tile>
+        <Tile>1206</Tile>
+        <Tile>1301</Tile>
+        <Tile>1308</Tile>
+        <Tile>1207</Tile>
+        <Tile>1302</Tile>
+        <Tile>2104</Tile>
+        <Tile>1303</Tile>
+        <Tile>1305</Tile>
+        <Tile>1306</Tile>
+        <Tile>2101</Tile>
+        <Tile>2102</Tile>
+        <Tile>1307</Tile>
+        <Tile>2108</Tile>
+        <Tile>2204</Tile>
+        <Tile>2103</Tile>
+        <Tile>2105</Tile>
+        <Tile>2107</Tile>
+        <Tile>2106</Tile>
+        <Tile>2201</Tile>
+        <Tile>2208</Tile>
+        <Tile>2203</Tile>
+        <Tile>2202</Tile>
+        <Tile>2304</Tile>
+        <Tile>2206</Tile>
+        <Tile>2205</Tile>
+        <Tile>2207</Tile>
+        <Tile>2302</Tile>
+        <Tile>2301</Tile>
+        <Tile>2303</Tile>
+        <Tile>2308</Tile>
+        <Tile>2305</Tile>
+        <Tile>2307</Tile>
+        <Tile>2306</Tile>
+      </Lane>
+      <Lane Index="6">
+        <Sample>s</Sample>
+        <Tile>1104</Tile>
+        <Tile>1101</Tile>
+        <Tile>1103</Tile>
+        <Tile>1102</Tile>
+        <Tile>1108</Tile>
+        <Tile>1107</Tile>
+        <Tile>1105</Tile>
+        <Tile>1106</Tile>
+        <Tile>1204</Tile>
+        <Tile>1203</Tile>
+        <Tile>1201</Tile>
+        <Tile>1202</Tile>
+        <Tile>1208</Tile>
+        <Tile>1207</Tile>
+        <Tile>1205</Tile>
+        <Tile>1206</Tile>
+        <Tile>1304</Tile>
+        <Tile>1303</Tile>
+        <Tile>1301</Tile>
+        <Tile>1302</Tile>
+        <Tile>1308</Tile>
+        <Tile>1307</Tile>
+        <Tile>1305</Tile>
+        <Tile>2104</Tile>
+        <Tile>1306</Tile>
+        <Tile>2103</Tile>
+        <Tile>2101</Tile>
+        <Tile>2102</Tile>
+        <Tile>2108</Tile>
+        <Tile>2107</Tile>
+        <Tile>2105</Tile>
+        <Tile>2106</Tile>
+        <Tile>2204</Tile>
+        <Tile>2203</Tile>
+        <Tile>2202</Tile>
+        <Tile>2201</Tile>
+        <Tile>2208</Tile>
+        <Tile>2207</Tile>
+        <Tile>2206</Tile>
+        <Tile>2205</Tile>
+        <Tile>2304</Tile>
+        <Tile>2303</Tile>
+        <Tile>2302</Tile>
+        <Tile>2301</Tile>
+        <Tile>2307</Tile>
+        <Tile>2308</Tile>
+        <Tile>2306</Tile>
+        <Tile>2305</Tile>
+      </Lane>
+      <Lane Index="7">
+        <Sample>s</Sample>
+        <Tile>1103</Tile>
+        <Tile>1107</Tile>
+        <Tile>1104</Tile>
+        <Tile>1108</Tile>
+        <Tile>1203</Tile>
+        <Tile>1101</Tile>
+        <Tile>1102</Tile>
+        <Tile>1204</Tile>
+        <Tile>1105</Tile>
+        <Tile>1207</Tile>
+        <Tile>1106</Tile>
+        <Tile>1208</Tile>
+        <Tile>1201</Tile>
+        <Tile>1202</Tile>
+        <Tile>1303</Tile>
+        <Tile>1205</Tile>
+        <Tile>1206</Tile>
+        <Tile>1307</Tile>
+        <Tile>1304</Tile>
+        <Tile>1301</Tile>
+        <Tile>1302</Tile>
+        <Tile>1305</Tile>
+        <Tile>1308</Tile>
+        <Tile>2103</Tile>
+        <Tile>1306</Tile>
+        <Tile>2101</Tile>
+        <Tile>2107</Tile>
+        <Tile>2104</Tile>
+        <Tile>2105</Tile>
+        <Tile>2102</Tile>
+        <Tile>2108</Tile>
+        <Tile>2203</Tile>
+        <Tile>2201</Tile>
+        <Tile>2106</Tile>
+        <Tile>2205</Tile>
+        <Tile>2207</Tile>
+        <Tile>2202</Tile>
+        <Tile>2204</Tile>
+        <Tile>2301</Tile>
+        <Tile>2303</Tile>
+        <Tile>2206</Tile>
+        <Tile>2208</Tile>
+        <Tile>2305</Tile>
+        <Tile>2307</Tile>
+        <Tile>2302</Tile>
+        <Tile>2304</Tile>
+        <Tile>2306</Tile>
+        <Tile>2308</Tile>
+      </Lane>
+      <Lane Index="8">
+        <Sample>s</Sample>
+        <Tile>1101</Tile>
+        <Tile>1103</Tile>
+        <Tile>1102</Tile>
+        <Tile>1105</Tile>
+        <Tile>1107</Tile>
+        <Tile>1104</Tile>
+        <Tile>1106</Tile>
+        <Tile>1201</Tile>
+        <Tile>1108</Tile>
+        <Tile>1203</Tile>
+        <Tile>1202</Tile>
+        <Tile>1205</Tile>
+        <Tile>1207</Tile>
+        <Tile>1204</Tile>
+        <Tile>1206</Tile>
+        <Tile>1301</Tile>
+        <Tile>1208</Tile>
+        <Tile>1303</Tile>
+        <Tile>1302</Tile>
+        <Tile>1305</Tile>
+        <Tile>1307</Tile>
+        <Tile>1304</Tile>
+        <Tile>1306</Tile>
+        <Tile>2101</Tile>
+        <Tile>1308</Tile>
+        <Tile>2103</Tile>
+        <Tile>2105</Tile>
+        <Tile>2102</Tile>
+        <Tile>2107</Tile>
+        <Tile>2106</Tile>
+        <Tile>2104</Tile>
+        <Tile>2201</Tile>
+        <Tile>2205</Tile>
+        <Tile>2202</Tile>
+        <Tile>2203</Tile>
+        <Tile>2108</Tile>
+        <Tile>2206</Tile>
+        <Tile>2301</Tile>
+        <Tile>2207</Tile>
+        <Tile>2204</Tile>
+        <Tile>2305</Tile>
+        <Tile>2302</Tile>
+        <Tile>2303</Tile>
+        <Tile>2208</Tile>
+        <Tile>2306</Tile>
+        <Tile>2307</Tile>
+        <Tile>2304</Tile>
+        <Tile>2308</Tile>
+      </Lane>
+    </TileSelection>
+  </Run>
+</BaseCallAnalysis>
diff --git a/htsworkflow/pipelines/test/testdata/demultiplexed_summary_1.12.4.2.xml b/htsworkflow/pipelines/test/testdata/demultiplexed_summary_1.12.4.2.xml
new file mode 100644 (file)
index 0000000..ebc9f4a
--- /dev/null
@@ -0,0 +1,3669 @@
+<?xml version="1.0"?>
+<BustardSummary>
+  <ChipResultsSummary>
+    <clusterCountPF>454185731</clusterCountPF>
+    <clusterCountRaw>781064977</clusterCountRaw>
+    <yield>25888586667</yield>
+  </ChipResultsSummary>
+  <ChipSummary>
+    <ChipID>unknown</ChipID>
+    <Machine>HWI-ST0787</Machine>
+    <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>
+  </ChipSummary>
+  <Date>2011-08-18 20:18:19</Date>
+  <ExpandedLaneSummary>
+    <Read>
+      <Lane>
+        <clusterCountRaw>
+          <mean>3707807.14</mean>
+          <stdev>573671.11</stdev>
+          <sumsq>393825007132852.00</sumsq>
+        </clusterCountRaw>
+        <laneNumber>1</laneNumber>
+        <percentClustersPF>
+          <mean>47.64</mean>
+          <stdev>19.64</stdev>
+          <sumsq>73957.00</sumsq>
+        </percentClustersPF>
+        <phasingApplied>0.3810</phasingApplied>
+        <prephasingApplied>0.0844</prephasingApplied>
+        <signalAverage1to3>
+          <mean>677.00</mean>
+          <stdev>148.48</stdev>
+          <sumsq>13428576.43</sumsq>
+        </signalAverage1to3>
+        <signalAverage2to4>
+          <mean>908.15</mean>
+          <stdev>81.51</stdev>
+          <sumsq>23271897.61</sumsq>
+        </signalAverage2to4>
+        <signalLoss10to20>
+          <mean>-0.30</mean>
+          <stdev>0.38</stdev>
+          <sumsq>6.33</sumsq>
+        </signalLoss10to20>
+        <signalLoss2to10>
+          <mean>-34.61</mean>
+          <stdev>26.97</stdev>
+          <sumsq>53175.44</sumsq>
+        </signalLoss2to10>
+      </Lane>
+      <Lane>
+        <clusterCountRaw>
+          <mean>3329777.81</mean>
+          <stdev>1102200.81</stdev>
+          <sumsq>318644092316267.00</sumsq>
+        </clusterCountRaw>
+        <laneNumber>2</laneNumber>
+        <percentClustersPF>
+          <mean>24.71</mean>
+          <stdev>17.39</stdev>
+          <sumsq>23436.66</sumsq>
+        </percentClustersPF>
+        <phasingApplied>0.3694</phasingApplied>
+        <prephasingApplied>0.2507</prephasingApplied>
+        <signalAverage1to3>
+          <mean>820.85</mean>
+          <stdev>175.96</stdev>
+          <sumsq>18292849.43</sumsq>
+        </signalAverage1to3>
+        <signalAverage2to4>
+          <mean>864.16</mean>
+          <stdev>95.34</stdev>
+          <sumsq>19643349.08</sumsq>
+        </signalAverage2to4>
+        <signalLoss10to20>
+          <mean>-5.69</mean>
+          <stdev>12.59</stdev>
+          <sumsq>4807.74</sumsq>
+        </signalLoss10to20>
+        <signalLoss2to10>
+          <mean>-34.31</mean>
+          <stdev>22.59</stdev>
+          <sumsq>43354.50</sumsq>
+        </signalLoss2to10>
+      </Lane>
+      <Lane>
+        <clusterCountRaw>
+          <mean>6268934.50</mean>
+          <stdev>241767.87</stdev>
+          <sumsq>314805480030044.00</sumsq>
+        </clusterCountRaw>
+        <laneNumber>3</laneNumber>
+        <percentClustersPF>
+          <mean>36.04</mean>
+          <stdev>12.81</stdev>
+          <sumsq>11541.60</sumsq>
+        </percentClustersPF>
+        <phasingApplied>0.2469</phasingApplied>
+        <prephasingApplied>0.2002</prephasingApplied>
+        <signalAverage1to3>
+          <mean>1094.84</mean>
+          <stdev>135.96</stdev>
+          <sumsq>9718779.89</sumsq>
+        </signalAverage1to3>
+        <signalAverage2to4>
+          <mean>1114.24</mean>
+          <stdev>57.49</stdev>
+          <sumsq>9955389.55</sumsq>
+        </signalAverage2to4>
+        <signalLoss10to20>
+          <mean>-4.20</mean>
+          <stdev>13.18</stdev>
+          <sumsq>1357.57</sumsq>
+        </signalLoss10to20>
+        <signalLoss2to10>
+          <mean>-53.53</mean>
+          <stdev>38.21</stdev>
+          <sumsq>33143.61</sumsq>
+        </signalLoss2to10>
+      </Lane>
+      <Lane>
+        <clusterCountRaw>
+          <mean>6055508.12</mean>
+          <stdev>166741.39</stdev>
+          <sumsq>293548048051419.00</sumsq>
+        </clusterCountRaw>
+        <laneNumber>4</laneNumber>
+        <percentClustersPF>
+          <mean>32.69</mean>
+          <stdev>7.60</stdev>
+          <sumsq>8952.16</sumsq>
+        </percentClustersPF>
+        <phasingApplied>0.2104</phasingApplied>
+        <prephasingApplied>0.1803</prephasingApplied>
+        <signalAverage1to3>
+          <mean>1106.96</mean>
+          <stdev>62.20</stdev>
+          <sumsq>9829917.93</sumsq>
+        </signalAverage1to3>
+        <signalAverage2to4>
+          <mean>1036.31</mean>
+          <stdev>128.16</stdev>
+          <sumsq>8706439.16</sumsq>
+        </signalAverage2to4>
+        <signalLoss10to20>
+          <mean>-9.55</mean>
+          <stdev>18.68</stdev>
+          <sumsq>3171.25</sumsq>
+        </signalLoss10to20>
+        <signalLoss2to10>
+          <mean>-44.30</mean>
+          <stdev>34.27</stdev>
+          <sumsq>23924.49</sumsq>
+        </signalLoss2to10>
+      </Lane>
+      <Lane>
+        <clusterCountRaw>
+          <mean>5643648.67</mean>
+          <stdev>137235.86</stdev>
+          <sumsq>95589978179428.00</sumsq>
+        </clusterCountRaw>
+        <laneNumber>5</laneNumber>
+        <percentClustersPF>
+          <mean>14.96</mean>
+          <stdev>10.60</stdev>
+          <sumsq>895.87</sumsq>
+        </percentClustersPF>
+        <phasingApplied>0.0000</phasingApplied>
+        <prephasingApplied>0.0000</prephasingApplied>
+        <signalAverage1to3>
+          <mean>-593.62</mean>
+          <stdev>74.55</stdev>
+          <sumsq>1068254.69</sumsq>
+        </signalAverage1to3>
+        <signalAverage2to4>
+          <mean>-623.07</mean>
+          <stdev>71.93</stdev>
+          <sumsq>1174981.61</sumsq>
+        </signalAverage2to4>
+        <signalLoss10to20>
+          <mean>100.00</mean>
+          <stdev>0.00</stdev>
+          <sumsq>30000.00</sumsq>
+        </signalLoss10to20>
+        <signalLoss2to10>
+          <mean>100.00</mean>
+          <stdev>0.00</stdev>
+          <sumsq>30000.00</sumsq>
+        </signalLoss2to10>
+      </Lane>
+      <Lane>
+        <clusterCountRaw>
+          <mean>5707954.48</mean>
+          <stdev>553352.88</stdev>
+          <sumsq>953415170485172.00</sumsq>
+        </clusterCountRaw>
+        <laneNumber>6</laneNumber>
+        <percentClustersPF>
+          <mean>42.22</mean>
+          <stdev>22.39</stdev>
+          <sumsq>65737.40</sumsq>
+        </percentClustersPF>
+        <phasingApplied>0.2670</phasingApplied>
+        <prephasingApplied>0.2116</prephasingApplied>
+        <signalAverage1to3>
+          <mean>976.36</mean>
+          <stdev>216.47</stdev>
+          <sumsq>28956965.77</sumsq>
+        </signalAverage1to3>
+        <signalAverage2to4>
+          <mean>1054.88</mean>
+          <stdev>90.27</stdev>
+          <sumsq>32498684.57</sumsq>
+        </signalAverage2to4>
+        <signalLoss10to20>
+          <mean>0.20</mean>
+          <stdev>0.11</stdev>
+          <sumsq>1.47</sumsq>
+        </signalLoss10to20>
+        <signalLoss2to10>
+          <mean>-79.61</mean>
+          <stdev>16.62</stdev>
+          <sumsq>191509.02</sumsq>
+        </signalLoss2to10>
+      </Lane>
+      <Lane>
+        <clusterCountRaw>
+          <mean>1867305.95</mean>
+          <stdev>444617.44</stdev>
+          <sumsq>158236511701682.00</sumsq>
+        </clusterCountRaw>
+        <laneNumber>7</laneNumber>
+        <percentClustersPF>
+          <mean>94.84</mean>
+          <stdev>11.12</stdev>
+          <sumsq>391931.07</sumsq>
+        </percentClustersPF>
+        <phasingApplied>0.1329</phasingApplied>
+        <prephasingApplied>0.2410</prephasingApplied>
+        <signalAverage1to3>
+          <mean>1399.64</mean>
+          <stdev>129.00</stdev>
+          <sumsq>84935084.50</sumsq>
+        </signalAverage1to3>
+        <signalAverage2to4>
+          <mean>1377.83</mean>
+          <stdev>128.32</stdev>
+          <sumsq>82324018.13</sumsq>
+        </signalAverage2to4>
+        <signalLoss10to20>
+          <mean>0.28</mean>
+          <stdev>0.09</stdev>
+          <sumsq>3.65</sumsq>
+        </signalLoss10to20>
+        <signalLoss2to10>
+          <mean>-4.22</mean>
+          <stdev>14.27</stdev>
+          <sumsq>9317.43</sumsq>
+        </signalLoss2to10>
+      </Lane>
+      <Lane>
+        <clusterCountRaw>
+          <mean>4777517.31</mean>
+          <stdev>599178.35</stdev>
+          <sumsq>1112457930812391.00</sumsq>
+        </clusterCountRaw>
+        <laneNumber>8</laneNumber>
+        <percentClustersPF>
+          <mean>86.54</mean>
+          <stdev>7.43</stdev>
+          <sumsq>362059.12</sumsq>
+        </percentClustersPF>
+        <phasingApplied>0.2192</phasingApplied>
+        <prephasingApplied>0.2346</prephasingApplied>
+        <signalAverage1to3>
+          <mean>1256.98</mean>
+          <stdev>106.05</stdev>
+          <sumsq>76368309.15</sumsq>
+        </signalAverage1to3>
+        <signalAverage2to4>
+          <mean>1233.08</mean>
+          <stdev>110.91</stdev>
+          <sumsq>73561027.92</sumsq>
+        </signalAverage2to4>
+        <signalLoss10to20>
+          <mean>0.63</mean>
+          <stdev>0.08</stdev>
+          <sumsq>19.47</sumsq>
+        </signalLoss10to20>
+        <signalLoss2to10>
+          <mean>-3.98</mean>
+          <stdev>11.04</stdev>
+          <sumsq>6489.36</sumsq>
+        </signalLoss2to10>
+      </Lane>
+      <readNumber>1</readNumber>
+    </Read>
+    
+  </ExpandedLaneSummary>
+  <LaneResultsSummary>
+    <Read>
+      <Lane>
+        <clusterCountPF>
+          <mean>1783290</mean>
+          <stdev>789504</stdev>
+          <sumsq>105873063750160</sumsq>
+        </clusterCountPF>
+        <clusterCountRaw>
+          <mean>3707807</mean>
+          <stdev>573671</stdev>
+          <sumsq>393825007132852</sumsq>
+        </clusterCountRaw>
+        <laneNumber>1</laneNumber>
+        <laneYield>2496606</laneYield>
+        <oneSig>
+          <mean>164</mean>
+          <stdev>410</stdev>
+          <sumsq>5304965</sumsq>
+        </oneSig>
+        <percentClustersPF>
+          <mean>47.64</mean>
+          <stdev>19.64</stdev>
+          <sumsq>73957.00</sumsq>
+        </percentClustersPF>
+        <signal20AsPctOf1>
+          <mean>9.00</mean>
+          <stdev>22.48</stdev>
+          <sumsq>15909.69</sumsq>
+        </signal20AsPctOf1>
+      </Lane>
+      <Lane>
+        <clusterCountPF>
+          <mean>875778</mean>
+          <stdev>826947</stdev>
+          <sumsq>37037748584192</sumsq>
+        </clusterCountPF>
+        <clusterCountRaw>
+          <mean>3329777</mean>
+          <stdev>1102200</stdev>
+          <sumsq>318644092316267</sumsq>
+        </clusterCountRaw>
+        <laneNumber>2</laneNumber>
+        <laneYield>1138512</laneYield>
+        <oneSig>
+          <mean>702</mean>
+          <stdev>480</stdev>
+          <sumsq>18627652</sumsq>
+        </oneSig>
+        <percentClustersPF>
+          <mean>24.71</mean>
+          <stdev>17.39</stdev>
+          <sumsq>23436.66</sumsq>
+        </percentClustersPF>
+        <signal20AsPctOf1>
+          <mean>56.49</mean>
+          <stdev>38.83</stdev>
+          <sumsq>120674.01</sumsq>
+        </signal20AsPctOf1>
+      </Lane>
+      <Lane>
+        <clusterCountPF>
+          <mean>2259006</mean>
+          <stdev>798869</stdev>
+          <sumsq>45292218394019</sumsq>
+        </clusterCountPF>
+        <clusterCountRaw>
+          <mean>6268934</mean>
+          <stdev>241767</stdev>
+          <sumsq>314805480030044</sumsq>
+        </clusterCountRaw>
+        <laneNumber>3</laneNumber>
+        <laneYield>903602</laneYield>
+        <oneSig>
+          <mean>1031</mean>
+          <stdev>419</stdev>
+          <sumsq>9747483</sumsq>
+        </oneSig>
+        <percentClustersPF>
+          <mean>36.04</mean>
+          <stdev>12.81</stdev>
+          <sumsq>11541.60</sumsq>
+        </percentClustersPF>
+        <signal20AsPctOf1>
+          <mean>75.63</mean>
+          <stdev>30.73</stdev>
+          <sumsq>52366.46</sumsq>
+        </signal20AsPctOf1>
+      </Lane>
+      <Lane>
+        <clusterCountPF>
+          <mean>1978985</mean>
+          <stdev>462424</stdev>
+          <sumsq>32827917903219</sumsq>
+        </clusterCountPF>
+        <clusterCountRaw>
+          <mean>6055508</mean>
+          <stdev>166741</stdev>
+          <sumsq>293548048051419</sumsq>
+        </clusterCountRaw>
+        <laneNumber>4</laneNumber>
+        <laneYield>791594</laneYield>
+        <oneSig>
+          <mean>1161</mean>
+          <stdev>61</stdev>
+          <sumsq>10827946</sumsq>
+        </oneSig>
+        <percentClustersPF>
+          <mean>32.69</mean>
+          <stdev>7.60</stdev>
+          <sumsq>8952.16</sumsq>
+        </percentClustersPF>
+        <signal20AsPctOf1>
+          <mean>63.64</mean>
+          <stdev>39.29</stdev>
+          <sumsq>43206.11</sumsq>
+        </signal20AsPctOf1>
+      </Lane>
+      <Lane>
+        <clusterCountPF>
+          <mean>834976</mean>
+          <stdev>570615</stdev>
+          <sumsq>2742761639691</sumsq>
+        </clusterCountPF>
+        <clusterCountRaw>
+          <mean>5643648</mean>
+          <stdev>137235</stdev>
+          <sumsq>95589978179428</sumsq>
+        </clusterCountRaw>
+        <laneNumber>5</laneNumber>
+        <laneYield>125246</laneYield>
+        <oneSig>
+          <mean>-596</mean>
+          <stdev>79</stdev>
+          <sumsq>1080823</sumsq>
+        </oneSig>
+        <percentClustersPF>
+          <mean>14.96</mean>
+          <stdev>10.60</stdev>
+          <sumsq>895.87</sumsq>
+        </percentClustersPF>
+        <signal20AsPctOf1>
+          <mean>147.21</mean>
+          <stdev>7.83</stdev>
+          <sumsq>65137.15</sumsq>
+        </signal20AsPctOf1>
+      </Lane>
+      <Lane>
+        <clusterCountPF>
+          <mean>2467696</mean>
+          <stdev>1423659</stdev>
+          <sumsq>233346910460595</sumsq>
+        </clusterCountPF>
+        <clusterCountRaw>
+          <mean>5707954</mean>
+          <stdev>553352</stdev>
+          <sumsq>953415170485172</sumsq>
+        </clusterCountRaw>
+        <laneNumber>6</laneNumber>
+        <laneYield>3578160</laneYield>
+        <oneSig>
+          <mean>820</mean>
+          <stdev>521</stdev>
+          <sumsq>27135464</sumsq>
+        </oneSig>
+        <percentClustersPF>
+          <mean>42.22</mean>
+          <stdev>22.39</stdev>
+          <sumsq>65737.40</sumsq>
+        </percentClustersPF>
+        <signal20AsPctOf1>
+          <mean>64.69</mean>
+          <stdev>40.68</stdev>
+          <sumsq>167697.34</sumsq>
+        </signal20AsPctOf1>
+      </Lane>
+      <Lane>
+        <clusterCountPF>
+          <mean>1769448</mean>
+          <stdev>464939</stdev>
+          <sumsq>143709845032850</sumsq>
+        </clusterCountPF>
+        <clusterCountRaw>
+          <mean>1867305</mean>
+          <stdev>444617</stdev>
+          <sumsq>158236511701682</sumsq>
+        </clusterCountRaw>
+        <laneNumber>7</laneNumber>
+        <laneYield>3804314</laneYield>
+        <oneSig>
+          <mean>1442</mean>
+          <stdev>84</stdev>
+          <sumsq>89752104</sumsq>
+        </oneSig>
+        <percentClustersPF>
+          <mean>94.84</mean>
+          <stdev>11.12</stdev>
+          <sumsq>391931.07</sumsq>
+        </percentClustersPF>
+        <signal20AsPctOf1>
+          <mean>91.96</mean>
+          <stdev>1.75</stdev>
+          <sumsq>363782.22</sumsq>
+        </signal20AsPctOf1>
+      </Lane>
+      <Lane>
+        <clusterCountPF>
+          <mean>4113020</mean>
+          <stdev>444275</stdev>
+          <sumsq>821290075103817</sumsq>
+        </clusterCountPF>
+        <clusterCountRaw>
+          <mean>4777517</mean>
+          <stdev>599178</stdev>
+          <sumsq>1112457930812391</sumsq>
+        </clusterCountRaw>
+        <laneNumber>8</laneNumber>
+        <laneYield>9871250</laneYield>
+        <oneSig>
+          <mean>1334</mean>
+          <stdev>72</stdev>
+          <sumsq>85708238</sumsq>
+        </oneSig>
+        <percentClustersPF>
+          <mean>86.54</mean>
+          <stdev>7.43</stdev>
+          <sumsq>362059.12</sumsq>
+        </percentClustersPF>
+        <signal20AsPctOf1>
+          <mean>88.24</mean>
+          <stdev>1.70</stdev>
+          <sumsq>373841.88</sumsq>
+        </signal20AsPctOf1>
+      </Lane>
+      <readNumber>1</readNumber>
+    </Read>
+    
+  </LaneResultsSummary>
+  <Software>CASAVA-1.8.1</Software>
+  <TileResultsByLane>
+    <Lane>
+      <Read>
+        <Tile>
+          <clusterCountPF>2195814</clusterCountPF>
+          <clusterCountRaw>3782916</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>58.05</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2278273</clusterCountPF>
+          <clusterCountRaw>3732743</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>61.03</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4020211</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3895725</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4134124</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4304874</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4406771</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4057296</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2235184</clusterCountPF>
+          <clusterCountRaw>3576569</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>62.50</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2303817</clusterCountPF>
+          <clusterCountRaw>3670759</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>62.76</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2228868</clusterCountPF>
+          <clusterCountRaw>3917599</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>56.89</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4063543</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4018922</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2207175</clusterCountPF>
+          <clusterCountRaw>4204009</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>52.50</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4440729</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>768164</clusterCountPF>
+          <clusterCountRaw>3715012</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>20.68</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2261727</clusterCountPF>
+          <clusterCountRaw>3621480</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>62.45</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2347049</clusterCountPF>
+          <clusterCountRaw>3868987</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>60.66</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4029778</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4153522</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4253486</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>598571</clusterCountPF>
+          <clusterCountRaw>1511883</clusterCountRaw>
+          <oneSig>1096.02</oneSig>
+          <percentClustersPF>39.59</percentClustersPF>
+          <signal20AsPctOf1>63.03</signal20AsPctOf1>
+          <tileNumber>1306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4540851</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>762937</clusterCountPF>
+          <clusterCountRaw>3797909</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>20.09</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1308</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2212968</clusterCountPF>
+          <clusterCountRaw>3718396</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>59.51</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2340883</clusterCountPF>
+          <clusterCountRaw>3785970</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>61.83</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2181836</clusterCountPF>
+          <clusterCountRaw>3995288</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>54.61</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4140850</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>344088</clusterCountPF>
+          <clusterCountRaw>3742840</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>9.19</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4417907</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>633399</clusterCountPF>
+          <clusterCountRaw>3982483</clusterCountRaw>
+          <oneSig>1075.65</oneSig>
+          <percentClustersPF>15.90</percentClustersPF>
+          <signal20AsPctOf1>64.87</signal20AsPctOf1>
+          <tileNumber>2107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4249399</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2273067</clusterCountPF>
+          <clusterCountRaw>3616092</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>62.86</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2371559</clusterCountPF>
+          <clusterCountRaw>3725669</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>63.65</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2333375</clusterCountPF>
+          <clusterCountRaw>3836500</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>60.82</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2185419</clusterCountPF>
+          <clusterCountRaw>3910181</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>55.89</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2311644</clusterCountPF>
+          <clusterCountRaw>4017955</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>57.53</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4331923</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2238184</clusterCountPF>
+          <clusterCountRaw>4417665</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>50.66</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4514102</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2087282</clusterCountPF>
+          <clusterCountRaw>3641497</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>57.32</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2372969</clusterCountPF>
+          <clusterCountRaw>3752096</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>63.24</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2356197</clusterCountPF>
+          <clusterCountRaw>3904880</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>60.34</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>334562</clusterCountPF>
+          <clusterCountRaw>2147785</clusterCountRaw>
+          <oneSig>1289.76</oneSig>
+          <percentClustersPF>15.58</percentClustersPF>
+          <signal20AsPctOf1>59.07</signal20AsPctOf1>
+          <tileNumber>2304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2020376</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4367266</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>906827</clusterCountPF>
+          <clusterCountRaw>4298608</clusterCountRaw>
+          <oneSig>1132.79</oneSig>
+          <percentClustersPF>21.10</percentClustersPF>
+          <signal20AsPctOf1>65.11</signal20AsPctOf1>
+          <tileNumber>2307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>260294</clusterCountPF>
+          <clusterCountRaw>3924829</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>6.63</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2308</tileNumber>
+        </Tile>
+        <readNumber>1</readNumber>
+      </Read>
+      
+      <laneNumber>1</laneNumber>
+    </Lane>
+    <Lane>
+      <Read>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4448159</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2773172</clusterCountPF>
+          <clusterCountRaw>4366122</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>63.52</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4564670</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4585876</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4635377</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>669217</clusterCountPF>
+          <clusterCountRaw>4420397</clusterCountRaw>
+          <oneSig>930.85</oneSig>
+          <percentClustersPF>15.14</percentClustersPF>
+          <signal20AsPctOf1>76.28</signal20AsPctOf1>
+          <tileNumber>1106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4676917</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4535868</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4334415</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>640314</clusterCountPF>
+          <clusterCountRaw>2059919</clusterCountRaw>
+          <oneSig>1000.53</oneSig>
+          <percentClustersPF>31.08</percentClustersPF>
+          <signal20AsPctOf1>85.05</signal20AsPctOf1>
+          <tileNumber>1202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2607069</clusterCountPF>
+          <clusterCountRaw>4434379</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>58.79</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>775741</clusterCountPF>
+          <clusterCountRaw>3750712</clusterCountRaw>
+          <oneSig>996.69</oneSig>
+          <percentClustersPF>20.68</percentClustersPF>
+          <signal20AsPctOf1>74.98</signal20AsPctOf1>
+          <tileNumber>1204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>440909</clusterCountPF>
+          <clusterCountRaw>4058935</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>10.86</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>214300</clusterCountPF>
+          <clusterCountRaw>1790590</clusterCountRaw>
+          <oneSig>927.63</oneSig>
+          <percentClustersPF>11.97</percentClustersPF>
+          <signal20AsPctOf1>74.32</signal20AsPctOf1>
+          <tileNumber>1206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4699049</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4541983</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>504330</clusterCountPF>
+          <clusterCountRaw>1946513</clusterCountRaw>
+          <oneSig>1041.75</oneSig>
+          <percentClustersPF>25.91</percentClustersPF>
+          <signal20AsPctOf1>73.96</signal20AsPctOf1>
+          <tileNumber>1301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4553087</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1143910</clusterCountPF>
+          <clusterCountRaw>3886939</clusterCountRaw>
+          <oneSig>1001.45</oneSig>
+          <percentClustersPF>29.43</percentClustersPF>
+          <signal20AsPctOf1>79.86</signal20AsPctOf1>
+          <tileNumber>1303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>394814</clusterCountPF>
+          <clusterCountRaw>1620637</clusterCountRaw>
+          <oneSig>903.30</oneSig>
+          <percentClustersPF>24.36</percentClustersPF>
+          <signal20AsPctOf1>85.19</signal20AsPctOf1>
+          <tileNumber>1304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>751155</clusterCountPF>
+          <clusterCountRaw>3901741</clusterCountRaw>
+          <oneSig>924.69</oneSig>
+          <percentClustersPF>19.25</percentClustersPF>
+          <signal20AsPctOf1>82.04</signal20AsPctOf1>
+          <tileNumber>1305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>279109</clusterCountPF>
+          <clusterCountRaw>4312437</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>6.47</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4877078</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4716643</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1308</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>621210</clusterCountPF>
+          <clusterCountRaw>2055906</clusterCountRaw>
+          <oneSig>1083.69</oneSig>
+          <percentClustersPF>30.22</percentClustersPF>
+          <signal20AsPctOf1>80.10</signal20AsPctOf1>
+          <tileNumber>2101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4511240</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>967970</clusterCountPF>
+          <clusterCountRaw>4049067</clusterCountRaw>
+          <oneSig>1094.71</oneSig>
+          <percentClustersPF>23.91</percentClustersPF>
+          <signal20AsPctOf1>81.54</signal20AsPctOf1>
+          <tileNumber>2103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>610322</clusterCountPF>
+          <clusterCountRaw>4256141</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>14.34</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>945727</clusterCountPF>
+          <clusterCountRaw>4036212</clusterCountRaw>
+          <oneSig>1045.43</oneSig>
+          <percentClustersPF>23.43</percentClustersPF>
+          <signal20AsPctOf1>81.22</signal20AsPctOf1>
+          <tileNumber>2105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4826884</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4806977</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4634388</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>522871</clusterCountPF>
+          <clusterCountRaw>3978361</clusterCountRaw>
+          <oneSig>991.67</oneSig>
+          <percentClustersPF>13.14</percentClustersPF>
+          <signal20AsPctOf1>97.22</signal20AsPctOf1>
+          <tileNumber>2201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>699409</clusterCountPF>
+          <clusterCountRaw>4040193</clusterCountRaw>
+          <oneSig>1042.31</oneSig>
+          <percentClustersPF>17.31</percentClustersPF>
+          <signal20AsPctOf1>91.73</signal20AsPctOf1>
+          <tileNumber>2202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>234576</clusterCountPF>
+          <clusterCountRaw>1982322</clusterCountRaw>
+          <oneSig>1097.76</oneSig>
+          <percentClustersPF>11.83</percentClustersPF>
+          <signal20AsPctOf1>91.23</signal20AsPctOf1>
+          <tileNumber>2203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>312538</clusterCountPF>
+          <clusterCountRaw>1846815</clusterCountRaw>
+          <oneSig>1060.29</oneSig>
+          <percentClustersPF>16.92</percentClustersPF>
+          <signal20AsPctOf1>81.85</signal20AsPctOf1>
+          <tileNumber>2204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4877670</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4352080</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4565158</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4595892</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2688747</clusterCountPF>
+          <clusterCountRaw>4326152</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>62.15</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2702172</clusterCountPF>
+          <clusterCountRaw>4401275</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>61.40</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>375919</clusterCountPF>
+          <clusterCountRaw>1897193</clusterCountRaw>
+          <oneSig>1064.46</oneSig>
+          <percentClustersPF>19.81</percentClustersPF>
+          <signal20AsPctOf1>73.90</signal20AsPctOf1>
+          <tileNumber>2303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>170457</clusterCountPF>
+          <clusterCountRaw>1856395</clusterCountRaw>
+          <oneSig>970.76</oneSig>
+          <percentClustersPF>9.18</percentClustersPF>
+          <signal20AsPctOf1>86.28</signal20AsPctOf1>
+          <tileNumber>2304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>464174</clusterCountPF>
+          <clusterCountRaw>3035669</clusterCountRaw>
+          <oneSig>1098.56</oneSig>
+          <percentClustersPF>15.29</percentClustersPF>
+          <signal20AsPctOf1>72.01</signal20AsPctOf1>
+          <tileNumber>2305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4768558</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>260108</clusterCountPF>
+          <clusterCountRaw>4263201</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>6.10</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4508484</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2308</tileNumber>
+        </Tile>
+        <readNumber>1</readNumber>
+      </Read>
+      
+      <laneNumber>2</laneNumber>
+    </Lane>
+    <Lane>
+      <Read>
+        <Tile>
+          <clusterCountPF>2375385</clusterCountPF>
+          <clusterCountRaw>6313330</clusterCountRaw>
+          <oneSig>1139.10</oneSig>
+          <percentClustersPF>37.62</percentClustersPF>
+          <signal20AsPctOf1>85.17</signal20AsPctOf1>
+          <tileNumber>1101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6286613</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5994999</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3262679</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6237718</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6033743</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6120542</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5567004</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2986982</clusterCountPF>
+          <clusterCountRaw>6143687</clusterCountRaw>
+          <oneSig>1179.26</oneSig>
+          <percentClustersPF>48.62</percentClustersPF>
+          <signal20AsPctOf1>83.37</signal20AsPctOf1>
+          <tileNumber>1201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6160371</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6336417</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5941459</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6294748</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5833916</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5913050</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5886712</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3249310</clusterCountPF>
+          <clusterCountRaw>6355086</clusterCountRaw>
+          <oneSig>1175.05</oneSig>
+          <percentClustersPF>51.13</percentClustersPF>
+          <signal20AsPctOf1>86.62</signal20AsPctOf1>
+          <tileNumber>1301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2482602</clusterCountPF>
+          <clusterCountRaw>6345936</clusterCountRaw>
+          <oneSig>1114.27</oneSig>
+          <percentClustersPF>39.12</percentClustersPF>
+          <signal20AsPctOf1>86.48</signal20AsPctOf1>
+          <tileNumber>1302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6391130</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6306326</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3278126</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3954980</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4991640</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4731299</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1308</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2363698</clusterCountPF>
+          <clusterCountRaw>6670949</clusterCountRaw>
+          <oneSig>1261.88</oneSig>
+          <percentClustersPF>35.43</percentClustersPF>
+          <signal20AsPctOf1>82.59</signal20AsPctOf1>
+          <tileNumber>2101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1287696</clusterCountPF>
+          <clusterCountRaw>6380853</clusterCountRaw>
+          <oneSig>1205.05</oneSig>
+          <percentClustersPF>20.18</percentClustersPF>
+          <signal20AsPctOf1>87.75</signal20AsPctOf1>
+          <tileNumber>2102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3299242</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6024321</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6041139</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6065842</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5924388</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5810177</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6081345</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6434511</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4547035</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5924309</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5981859</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5706415</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6033825</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6078240</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2447011</clusterCountPF>
+          <clusterCountRaw>5856223</clusterCountRaw>
+          <oneSig>1180.01</oneSig>
+          <percentClustersPF>41.78</percentClustersPF>
+          <signal20AsPctOf1>93.05</signal20AsPctOf1>
+          <tileNumber>2301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>879365</clusterCountPF>
+          <clusterCountRaw>6085412</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>14.45</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3459940</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6354552</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5912596</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5914029</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5058019</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5899621</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2308</tileNumber>
+        </Tile>
+        <readNumber>1</readNumber>
+      </Read>
+      
+      <laneNumber>3</laneNumber>
+    </Lane>
+    <Lane>
+      <Read>
+        <Tile>
+          <clusterCountPF>2890389</clusterCountPF>
+          <clusterCountRaw>6154619</clusterCountRaw>
+          <oneSig>1106.26</oneSig>
+          <percentClustersPF>46.96</percentClustersPF>
+          <signal20AsPctOf1>84.42</signal20AsPctOf1>
+          <tileNumber>1101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3859115</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6150759</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6062610</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6041213</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6048818</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5891349</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5878432</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2392573</clusterCountPF>
+          <clusterCountRaw>5835186</clusterCountRaw>
+          <oneSig>1125.79</oneSig>
+          <percentClustersPF>41.00</percentClustersPF>
+          <signal20AsPctOf1>83.06</signal20AsPctOf1>
+          <tileNumber>1201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1735497</clusterCountPF>
+          <clusterCountRaw>5951872</clusterCountRaw>
+          <oneSig>1071.67</oneSig>
+          <percentClustersPF>29.16</percentClustersPF>
+          <signal20AsPctOf1>86.07</signal20AsPctOf1>
+          <tileNumber>1202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5968968</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5974093</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6089365</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5465613</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6034569</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4926479</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1813170</clusterCountPF>
+          <clusterCountRaw>6065205</clusterCountRaw>
+          <oneSig>1134.80</oneSig>
+          <percentClustersPF>29.89</percentClustersPF>
+          <signal20AsPctOf1>83.87</signal20AsPctOf1>
+          <tileNumber>1301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6072760</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6022433</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5914380</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6035108</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6110769</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5874705</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5932065</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1308</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1933417</clusterCountPF>
+          <clusterCountRaw>6057448</clusterCountRaw>
+          <oneSig>1230.29</oneSig>
+          <percentClustersPF>31.92</percentClustersPF>
+          <signal20AsPctOf1>85.88</signal20AsPctOf1>
+          <tileNumber>2101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5897444</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6389435</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3815684</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6071732</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5821758</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5873744</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6008801</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1611899</clusterCountPF>
+          <clusterCountRaw>5880262</clusterCountRaw>
+          <oneSig>1241.48</oneSig>
+          <percentClustersPF>27.41</percentClustersPF>
+          <signal20AsPctOf1>0.00</signal20AsPctOf1>
+          <tileNumber>2201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1996737</clusterCountPF>
+          <clusterCountRaw>6347857</clusterCountRaw>
+          <oneSig>1188.53</oneSig>
+          <percentClustersPF>31.46</percentClustersPF>
+          <signal20AsPctOf1>0.00</signal20AsPctOf1>
+          <tileNumber>2202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6362861</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5852976</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6177697</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6022917</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6123053</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4798958</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4627342</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1458201</clusterCountPF>
+          <clusterCountRaw>6151616</clusterCountRaw>
+          <oneSig>1197.06</oneSig>
+          <percentClustersPF>23.70</percentClustersPF>
+          <signal20AsPctOf1>85.80</signal20AsPctOf1>
+          <tileNumber>2302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6007566</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6300233</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5970238</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5954738</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6046864</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6017839</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2308</tileNumber>
+        </Tile>
+        <readNumber>1</readNumber>
+      </Read>
+      
+      <laneNumber>4</laneNumber>
+    </Lane>
+    <Lane>
+      <Read>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5631135</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2681269</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2607227</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5940868</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3300266</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3183165</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3168588</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3105604</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3054041</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4779051</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5324239</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5972215</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3287230</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2762623</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3156192</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2971658</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>496907</clusterCountPF>
+          <clusterCountRaw>5676984</clusterCountRaw>
+          <oneSig>-685.71</oneSig>
+          <percentClustersPF>8.75</percentClustersPF>
+          <signal20AsPctOf1>138.72</signal20AsPctOf1>
+          <tileNumber>1301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5350372</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5418521</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5941481</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3314554</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3168898</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3124790</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3116740</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1308</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1493791</clusterCountPF>
+          <clusterCountRaw>5492816</clusterCountRaw>
+          <oneSig>-532.02</oneSig>
+          <percentClustersPF>27.20</percentClustersPF>
+          <signal20AsPctOf1>148.77</signal20AsPctOf1>
+          <tileNumber>2101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>514231</clusterCountPF>
+          <clusterCountRaw>5761146</clusterCountRaw>
+          <oneSig>-572.34</oneSig>
+          <percentClustersPF>8.93</percentClustersPF>
+          <signal20AsPctOf1>154.15</signal20AsPctOf1>
+          <tileNumber>2102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3834974</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6041237</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3371454</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3271578</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3145886</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2812963</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5714487</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>4323735</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5689972</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5590891</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2565274</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3103834</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2775071</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2721788</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2808679</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5740118</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2710478</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6053923</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3311585</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3229925</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3052698</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>3161815</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2308</tileNumber>
+        </Tile>
+        <readNumber>1</readNumber>
+      </Read>
+      
+      <laneNumber>5</laneNumber>
+    </Lane>
+    <Lane>
+      <Read>
+        <Tile>
+          <clusterCountPF>4328250</clusterCountPF>
+          <clusterCountRaw>6108747</clusterCountRaw>
+          <oneSig>1170.17</oneSig>
+          <percentClustersPF>70.85</percentClustersPF>
+          <signal20AsPctOf1>85.98</signal20AsPctOf1>
+          <tileNumber>1101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3763550</clusterCountPF>
+          <clusterCountRaw>5974162</clusterCountRaw>
+          <oneSig>1171.51</oneSig>
+          <percentClustersPF>63.00</percentClustersPF>
+          <signal20AsPctOf1>85.49</signal20AsPctOf1>
+          <tileNumber>1102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3376849</clusterCountPF>
+          <clusterCountRaw>5986042</clusterCountRaw>
+          <oneSig>1127.66</oneSig>
+          <percentClustersPF>56.41</percentClustersPF>
+          <signal20AsPctOf1>86.28</signal20AsPctOf1>
+          <tileNumber>1103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1454678</clusterCountPF>
+          <clusterCountRaw>5553026</clusterCountRaw>
+          <oneSig>1038.63</oneSig>
+          <percentClustersPF>26.20</percentClustersPF>
+          <signal20AsPctOf1>90.35</signal20AsPctOf1>
+          <tileNumber>1104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>836786</clusterCountPF>
+          <clusterCountRaw>5751374</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>14.55</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1008081</clusterCountPF>
+          <clusterCountRaw>5436595</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>18.54</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1089073</clusterCountPF>
+          <clusterCountRaw>4720242</clusterCountRaw>
+          <oneSig>970.77</oneSig>
+          <percentClustersPF>23.07</percentClustersPF>
+          <signal20AsPctOf1>87.99</signal20AsPctOf1>
+          <tileNumber>1107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5628492</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4255350</clusterCountPF>
+          <clusterCountRaw>6074637</clusterCountRaw>
+          <oneSig>1111.85</oneSig>
+          <percentClustersPF>70.05</percentClustersPF>
+          <signal20AsPctOf1>90.15</signal20AsPctOf1>
+          <tileNumber>1201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3764335</clusterCountPF>
+          <clusterCountRaw>5992750</clusterCountRaw>
+          <oneSig>1122.60</oneSig>
+          <percentClustersPF>62.81</percentClustersPF>
+          <signal20AsPctOf1>87.23</signal20AsPctOf1>
+          <tileNumber>1202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2949541</clusterCountPF>
+          <clusterCountRaw>5863819</clusterCountRaw>
+          <oneSig>1041.75</oneSig>
+          <percentClustersPF>50.30</percentClustersPF>
+          <signal20AsPctOf1>91.25</signal20AsPctOf1>
+          <tileNumber>1203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1960969</clusterCountPF>
+          <clusterCountRaw>5759754</clusterCountRaw>
+          <oneSig>985.74</oneSig>
+          <percentClustersPF>34.05</percentClustersPF>
+          <signal20AsPctOf1>94.16</signal20AsPctOf1>
+          <tileNumber>1204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1458718</clusterCountPF>
+          <clusterCountRaw>5348340</clusterCountRaw>
+          <oneSig>973.95</oneSig>
+          <percentClustersPF>27.27</percentClustersPF>
+          <signal20AsPctOf1>92.07</signal20AsPctOf1>
+          <tileNumber>1205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6188127</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6029568</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5783284</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4164137</clusterCountPF>
+          <clusterCountRaw>6062113</clusterCountRaw>
+          <oneSig>1111.15</oneSig>
+          <percentClustersPF>68.69</percentClustersPF>
+          <signal20AsPctOf1>90.64</signal20AsPctOf1>
+          <tileNumber>1301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3807278</clusterCountPF>
+          <clusterCountRaw>6009706</clusterCountRaw>
+          <oneSig>1103.05</oneSig>
+          <percentClustersPF>63.35</percentClustersPF>
+          <signal20AsPctOf1>89.93</signal20AsPctOf1>
+          <tileNumber>1302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2646889</clusterCountPF>
+          <clusterCountRaw>5860357</clusterCountRaw>
+          <oneSig>1047.72</oneSig>
+          <percentClustersPF>45.17</percentClustersPF>
+          <signal20AsPctOf1>91.04</signal20AsPctOf1>
+          <tileNumber>1303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>618116</clusterCountPF>
+          <clusterCountRaw>5936009</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>10.41</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>966704</clusterCountPF>
+          <clusterCountRaw>5780730</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>16.72</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>985185</clusterCountPF>
+          <clusterCountRaw>5442490</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>18.10</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5865063</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5759999</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>1308</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4457818</clusterCountPF>
+          <clusterCountRaw>6178104</clusterCountRaw>
+          <oneSig>1290.91</oneSig>
+          <percentClustersPF>72.16</percentClustersPF>
+          <signal20AsPctOf1>87.89</signal20AsPctOf1>
+          <tileNumber>2101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4135701</clusterCountPF>
+          <clusterCountRaw>6067338</clusterCountRaw>
+          <oneSig>1270.47</oneSig>
+          <percentClustersPF>68.16</percentClustersPF>
+          <signal20AsPctOf1>87.91</signal20AsPctOf1>
+          <tileNumber>2102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3142805</clusterCountPF>
+          <clusterCountRaw>5915123</clusterCountRaw>
+          <oneSig>1190.65</oneSig>
+          <percentClustersPF>53.13</percentClustersPF>
+          <signal20AsPctOf1>91.67</signal20AsPctOf1>
+          <tileNumber>2103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2857800</clusterCountPF>
+          <clusterCountRaw>5959413</clusterCountRaw>
+          <oneSig>1192.35</oneSig>
+          <percentClustersPF>47.95</percentClustersPF>
+          <signal20AsPctOf1>88.82</signal20AsPctOf1>
+          <tileNumber>2104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1231733</clusterCountPF>
+          <clusterCountRaw>5733754</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>21.48</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2633715</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>719661</clusterCountPF>
+          <clusterCountRaw>5147810</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>13.98</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5662637</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5811788</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5919142</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5921326</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5683685</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5369472</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5594894</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5888075</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5533822</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4347658</clusterCountPF>
+          <clusterCountRaw>6149228</clusterCountRaw>
+          <oneSig>1270.97</oneSig>
+          <percentClustersPF>70.70</percentClustersPF>
+          <signal20AsPctOf1>87.57</signal20AsPctOf1>
+          <tileNumber>2301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3927517</clusterCountPF>
+          <clusterCountRaw>6038155</clusterCountRaw>
+          <oneSig>1260.11</oneSig>
+          <percentClustersPF>65.04</percentClustersPF>
+          <signal20AsPctOf1>88.09</signal20AsPctOf1>
+          <tileNumber>2302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1031548</clusterCountPF>
+          <clusterCountRaw>3463054</clusterCountRaw>
+          <oneSig>1223.05</oneSig>
+          <percentClustersPF>29.79</percentClustersPF>
+          <signal20AsPctOf1>88.74</signal20AsPctOf1>
+          <tileNumber>2303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>464073</clusterCountPF>
+          <clusterCountRaw>6006755</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>7.73</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1812404</clusterCountPF>
+          <clusterCountRaw>5211053</clusterCountRaw>
+          <oneSig>1109.48</oneSig>
+          <percentClustersPF>34.78</percentClustersPF>
+          <signal20AsPctOf1>92.72</signal20AsPctOf1>
+          <tileNumber>2305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>6128662</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5927816</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>5684780</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2308</tileNumber>
+        </Tile>
+        <readNumber>1</readNumber>
+      </Read>
+      
+      <laneNumber>6</laneNumber>
+    </Lane>
+    <Lane>
+      <Read>
+        <Tile>
+          <clusterCountPF>1290892</clusterCountPF>
+          <clusterCountRaw>1318384</clusterCountRaw>
+          <oneSig>1457.61</oneSig>
+          <percentClustersPF>97.91</percentClustersPF>
+          <signal20AsPctOf1>93.12</signal20AsPctOf1>
+          <tileNumber>1101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1405177</clusterCountPF>
+          <clusterCountRaw>1435753</clusterCountRaw>
+          <oneSig>1428.15</oneSig>
+          <percentClustersPF>97.87</percentClustersPF>
+          <signal20AsPctOf1>93.14</signal20AsPctOf1>
+          <tileNumber>1102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1518681</clusterCountPF>
+          <clusterCountRaw>1553867</clusterCountRaw>
+          <oneSig>1415.45</oneSig>
+          <percentClustersPF>97.74</percentClustersPF>
+          <signal20AsPctOf1>93.14</signal20AsPctOf1>
+          <tileNumber>1103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1674083</clusterCountPF>
+          <clusterCountRaw>1713366</clusterCountRaw>
+          <oneSig>1397.13</oneSig>
+          <percentClustersPF>97.71</percentClustersPF>
+          <signal20AsPctOf1>91.75</signal20AsPctOf1>
+          <tileNumber>1104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1848975</clusterCountPF>
+          <clusterCountRaw>1894031</clusterCountRaw>
+          <oneSig>1453.02</oneSig>
+          <percentClustersPF>97.62</percentClustersPF>
+          <signal20AsPctOf1>87.65</signal20AsPctOf1>
+          <tileNumber>1105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2036288</clusterCountPF>
+          <clusterCountRaw>2089577</clusterCountRaw>
+          <oneSig>1351.03</oneSig>
+          <percentClustersPF>97.45</percentClustersPF>
+          <signal20AsPctOf1>92.96</signal20AsPctOf1>
+          <tileNumber>1106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2235825</clusterCountPF>
+          <clusterCountRaw>2300996</clusterCountRaw>
+          <oneSig>1330.80</oneSig>
+          <percentClustersPF>97.17</percentClustersPF>
+          <signal20AsPctOf1>92.09</signal20AsPctOf1>
+          <tileNumber>1107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2451380</clusterCountPF>
+          <clusterCountRaw>2541307</clusterCountRaw>
+          <oneSig>1293.67</oneSig>
+          <percentClustersPF>96.46</percentClustersPF>
+          <signal20AsPctOf1>91.71</signal20AsPctOf1>
+          <tileNumber>1108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1248007</clusterCountPF>
+          <clusterCountRaw>1271398</clusterCountRaw>
+          <oneSig>1456.86</oneSig>
+          <percentClustersPF>98.16</percentClustersPF>
+          <signal20AsPctOf1>92.75</signal20AsPctOf1>
+          <tileNumber>1201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1353214</clusterCountPF>
+          <clusterCountRaw>1379519</clusterCountRaw>
+          <oneSig>1373.11</oneSig>
+          <percentClustersPF>98.09</percentClustersPF>
+          <signal20AsPctOf1>92.92</signal20AsPctOf1>
+          <tileNumber>1202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1476775</clusterCountPF>
+          <clusterCountRaw>1506069</clusterCountRaw>
+          <oneSig>1406.85</oneSig>
+          <percentClustersPF>98.05</percentClustersPF>
+          <signal20AsPctOf1>92.17</signal20AsPctOf1>
+          <tileNumber>1203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1596576</clusterCountPF>
+          <clusterCountRaw>1629689</clusterCountRaw>
+          <oneSig>1395.32</oneSig>
+          <percentClustersPF>97.97</percentClustersPF>
+          <signal20AsPctOf1>90.76</signal20AsPctOf1>
+          <tileNumber>1204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1802357</clusterCountPF>
+          <clusterCountRaw>1838238</clusterCountRaw>
+          <oneSig>1383.42</oneSig>
+          <percentClustersPF>98.05</percentClustersPF>
+          <signal20AsPctOf1>91.84</signal20AsPctOf1>
+          <tileNumber>1205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1985501</clusterCountPF>
+          <clusterCountRaw>2028373</clusterCountRaw>
+          <oneSig>1355.39</oneSig>
+          <percentClustersPF>97.89</percentClustersPF>
+          <signal20AsPctOf1>91.43</signal20AsPctOf1>
+          <tileNumber>1206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2182408</clusterCountPF>
+          <clusterCountRaw>2237640</clusterCountRaw>
+          <oneSig>1326.23</oneSig>
+          <percentClustersPF>97.53</percentClustersPF>
+          <signal20AsPctOf1>91.95</signal20AsPctOf1>
+          <tileNumber>1207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2412726</clusterCountPF>
+          <clusterCountRaw>2498414</clusterCountRaw>
+          <oneSig>1284.50</oneSig>
+          <percentClustersPF>96.57</percentClustersPF>
+          <signal20AsPctOf1>91.14</signal20AsPctOf1>
+          <tileNumber>1208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1329553</clusterCountPF>
+          <clusterCountRaw>1353194</clusterCountRaw>
+          <oneSig>1500.38</oneSig>
+          <percentClustersPF>98.25</percentClustersPF>
+          <signal20AsPctOf1>90.00</signal20AsPctOf1>
+          <tileNumber>1301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1448646</clusterCountPF>
+          <clusterCountRaw>1475015</clusterCountRaw>
+          <oneSig>1426.92</oneSig>
+          <percentClustersPF>98.21</percentClustersPF>
+          <signal20AsPctOf1>91.04</signal20AsPctOf1>
+          <tileNumber>1302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1584849</clusterCountPF>
+          <clusterCountRaw>1618578</clusterCountRaw>
+          <oneSig>1418.87</oneSig>
+          <percentClustersPF>97.92</percentClustersPF>
+          <signal20AsPctOf1>90.98</signal20AsPctOf1>
+          <tileNumber>1303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1703358</clusterCountPF>
+          <clusterCountRaw>1738426</clusterCountRaw>
+          <oneSig>1408.33</oneSig>
+          <percentClustersPF>97.98</percentClustersPF>
+          <signal20AsPctOf1>90.65</signal20AsPctOf1>
+          <tileNumber>1304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1962537</clusterCountPF>
+          <clusterCountRaw>2003605</clusterCountRaw>
+          <oneSig>1417.26</oneSig>
+          <percentClustersPF>97.95</percentClustersPF>
+          <signal20AsPctOf1>88.90</signal20AsPctOf1>
+          <tileNumber>1305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2155571</clusterCountPF>
+          <clusterCountRaw>2205956</clusterCountRaw>
+          <oneSig>1353.91</oneSig>
+          <percentClustersPF>97.72</percentClustersPF>
+          <signal20AsPctOf1>91.89</signal20AsPctOf1>
+          <tileNumber>1306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2371794</clusterCountPF>
+          <clusterCountRaw>2438582</clusterCountRaw>
+          <oneSig>1349.40</oneSig>
+          <percentClustersPF>97.26</percentClustersPF>
+          <signal20AsPctOf1>87.65</signal20AsPctOf1>
+          <tileNumber>1307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2609442</clusterCountPF>
+          <clusterCountRaw>2697578</clusterCountRaw>
+          <oneSig>1273.05</oneSig>
+          <percentClustersPF>96.73</percentClustersPF>
+          <signal20AsPctOf1>89.13</signal20AsPctOf1>
+          <tileNumber>1308</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1274462</clusterCountPF>
+          <clusterCountRaw>1301586</clusterCountRaw>
+          <oneSig>1601.86</oneSig>
+          <percentClustersPF>97.92</percentClustersPF>
+          <signal20AsPctOf1>92.97</signal20AsPctOf1>
+          <tileNumber>2101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1383611</clusterCountPF>
+          <clusterCountRaw>1413798</clusterCountRaw>
+          <oneSig>1567.26</oneSig>
+          <percentClustersPF>97.86</percentClustersPF>
+          <signal20AsPctOf1>92.72</signal20AsPctOf1>
+          <tileNumber>2102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1500886</clusterCountPF>
+          <clusterCountRaw>1538148</clusterCountRaw>
+          <oneSig>1575.16</oneSig>
+          <percentClustersPF>97.58</percentClustersPF>
+          <signal20AsPctOf1>91.30</signal20AsPctOf1>
+          <tileNumber>2103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1658029</clusterCountPF>
+          <clusterCountRaw>1695613</clusterCountRaw>
+          <oneSig>1551.84</oneSig>
+          <percentClustersPF>97.78</percentClustersPF>
+          <signal20AsPctOf1>92.03</signal20AsPctOf1>
+          <tileNumber>2104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1833421</clusterCountPF>
+          <clusterCountRaw>1876931</clusterCountRaw>
+          <oneSig>1525.11</oneSig>
+          <percentClustersPF>97.68</percentClustersPF>
+          <signal20AsPctOf1>92.43</signal20AsPctOf1>
+          <tileNumber>2105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2026973</clusterCountPF>
+          <clusterCountRaw>2078853</clusterCountRaw>
+          <oneSig>1509.17</oneSig>
+          <percentClustersPF>97.50</percentClustersPF>
+          <signal20AsPctOf1>91.91</signal20AsPctOf1>
+          <tileNumber>2106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2259381</clusterCountPF>
+          <clusterCountRaw>2325032</clusterCountRaw>
+          <oneSig>1467.69</oneSig>
+          <percentClustersPF>97.18</percentClustersPF>
+          <signal20AsPctOf1>92.25</signal20AsPctOf1>
+          <tileNumber>2107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2558255</clusterCountPF>
+          <clusterCountRaw>2655400</clusterCountRaw>
+          <oneSig>1444.06</oneSig>
+          <percentClustersPF>96.34</percentClustersPF>
+          <signal20AsPctOf1>91.44</signal20AsPctOf1>
+          <tileNumber>2108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>970653</clusterCountPF>
+          <clusterCountRaw>1235179</clusterCountRaw>
+          <oneSig>1584.09</oneSig>
+          <percentClustersPF>78.58</percentClustersPF>
+          <signal20AsPctOf1>93.93</signal20AsPctOf1>
+          <tileNumber>2201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>1342455</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>1465297</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>675140</clusterCountPF>
+          <clusterCountRaw>1582751</clusterCountRaw>
+          <oneSig>1505.46</oneSig>
+          <percentClustersPF>42.66</percentClustersPF>
+          <signal20AsPctOf1>94.13</signal20AsPctOf1>
+          <tileNumber>2204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>1775056</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>1957270</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>0</clusterCountPF>
+          <clusterCountRaw>2164043</clusterCountRaw>
+          <oneSig>0.00</oneSig>
+          <percentClustersPF>0.00</percentClustersPF>
+          <signal20AsPctOf1>N/A</signal20AsPctOf1>
+          <tileNumber>2207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1254733</clusterCountPF>
+          <clusterCountRaw>2441653</clusterCountRaw>
+          <oneSig>1444.53</oneSig>
+          <percentClustersPF>51.39</percentClustersPF>
+          <signal20AsPctOf1>93.17</signal20AsPctOf1>
+          <tileNumber>2208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1296622</clusterCountPF>
+          <clusterCountRaw>1325781</clusterCountRaw>
+          <oneSig>1494.17</oneSig>
+          <percentClustersPF>97.80</percentClustersPF>
+          <signal20AsPctOf1>98.31</signal20AsPctOf1>
+          <tileNumber>2301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1424658</clusterCountPF>
+          <clusterCountRaw>1452340</clusterCountRaw>
+          <oneSig>1528.87</oneSig>
+          <percentClustersPF>98.09</percentClustersPF>
+          <signal20AsPctOf1>93.49</signal20AsPctOf1>
+          <tileNumber>2302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1569437</clusterCountPF>
+          <clusterCountRaw>1602067</clusterCountRaw>
+          <oneSig>1539.36</oneSig>
+          <percentClustersPF>97.96</percentClustersPF>
+          <signal20AsPctOf1>93.10</signal20AsPctOf1>
+          <tileNumber>2303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1682427</clusterCountPF>
+          <clusterCountRaw>1720505</clusterCountRaw>
+          <oneSig>1521.03</oneSig>
+          <percentClustersPF>97.79</percentClustersPF>
+          <signal20AsPctOf1>92.61</signal20AsPctOf1>
+          <tileNumber>2304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>1939141</clusterCountPF>
+          <clusterCountRaw>1979800</clusterCountRaw>
+          <oneSig>1523.67</oneSig>
+          <percentClustersPF>97.95</percentClustersPF>
+          <signal20AsPctOf1>91.62</signal20AsPctOf1>
+          <tileNumber>2305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2134547</clusterCountPF>
+          <clusterCountRaw>2184095</clusterCountRaw>
+          <oneSig>1486.10</oneSig>
+          <percentClustersPF>97.73</percentClustersPF>
+          <signal20AsPctOf1>92.33</signal20AsPctOf1>
+          <tileNumber>2306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2356389</clusterCountPF>
+          <clusterCountRaw>2421537</clusterCountRaw>
+          <oneSig>1466.46</oneSig>
+          <percentClustersPF>97.31</percentClustersPF>
+          <signal20AsPctOf1>91.63</signal20AsPctOf1>
+          <tileNumber>2307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2602908</clusterCountPF>
+          <clusterCountRaw>2695532</clusterCountRaw>
+          <oneSig>1428.19</oneSig>
+          <percentClustersPF>96.56</percentClustersPF>
+          <signal20AsPctOf1>92.25</signal20AsPctOf1>
+          <tileNumber>2308</tileNumber>
+        </Tile>
+        <readNumber>1</readNumber>
+      </Read>
+      
+      <laneNumber>7</laneNumber>
+    </Lane>
+    <Lane>
+      <Read>
+        <Tile>
+          <clusterCountPF>3672425</clusterCountPF>
+          <clusterCountRaw>3999929</clusterCountRaw>
+          <oneSig>1359.39</oneSig>
+          <percentClustersPF>91.81</percentClustersPF>
+          <signal20AsPctOf1>88.45</signal20AsPctOf1>
+          <tileNumber>1101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3843360</clusterCountPF>
+          <clusterCountRaw>4214896</clusterCountRaw>
+          <oneSig>1338.54</oneSig>
+          <percentClustersPF>91.19</percentClustersPF>
+          <signal20AsPctOf1>88.01</signal20AsPctOf1>
+          <tileNumber>1102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3985275</clusterCountPF>
+          <clusterCountRaw>4432069</clusterCountRaw>
+          <oneSig>1321.41</oneSig>
+          <percentClustersPF>89.92</percentClustersPF>
+          <signal20AsPctOf1>88.40</signal20AsPctOf1>
+          <tileNumber>1103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4195701</clusterCountPF>
+          <clusterCountRaw>4688257</clusterCountRaw>
+          <oneSig>1298.99</oneSig>
+          <percentClustersPF>89.49</percentClustersPF>
+          <signal20AsPctOf1>87.97</signal20AsPctOf1>
+          <tileNumber>1104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4416383</clusterCountPF>
+          <clusterCountRaw>4972645</clusterCountRaw>
+          <oneSig>1283.87</oneSig>
+          <percentClustersPF>88.81</percentClustersPF>
+          <signal20AsPctOf1>88.72</signal20AsPctOf1>
+          <tileNumber>1105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4542437</clusterCountPF>
+          <clusterCountRaw>5209248</clusterCountRaw>
+          <oneSig>1258.05</oneSig>
+          <percentClustersPF>87.20</percentClustersPF>
+          <signal20AsPctOf1>87.14</signal20AsPctOf1>
+          <tileNumber>1106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4596548</clusterCountPF>
+          <clusterCountRaw>5399922</clusterCountRaw>
+          <oneSig>1230.54</oneSig>
+          <percentClustersPF>85.12</percentClustersPF>
+          <signal20AsPctOf1>87.31</signal20AsPctOf1>
+          <tileNumber>1107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4316902</clusterCountPF>
+          <clusterCountRaw>5826697</clusterCountRaw>
+          <oneSig>1182.73</oneSig>
+          <percentClustersPF>74.09</percentClustersPF>
+          <signal20AsPctOf1>87.01</signal20AsPctOf1>
+          <tileNumber>1108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3559633</clusterCountPF>
+          <clusterCountRaw>3873994</clusterCountRaw>
+          <oneSig>1365.15</oneSig>
+          <percentClustersPF>91.89</percentClustersPF>
+          <signal20AsPctOf1>87.07</signal20AsPctOf1>
+          <tileNumber>1201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3742085</clusterCountPF>
+          <clusterCountRaw>4103838</clusterCountRaw>
+          <oneSig>1345.87</oneSig>
+          <percentClustersPF>91.19</percentClustersPF>
+          <signal20AsPctOf1>87.69</signal20AsPctOf1>
+          <tileNumber>1202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3809926</clusterCountPF>
+          <clusterCountRaw>4219389</clusterCountRaw>
+          <oneSig>1314.55</oneSig>
+          <percentClustersPF>90.30</percentClustersPF>
+          <signal20AsPctOf1>88.34</signal20AsPctOf1>
+          <tileNumber>1203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4095946</clusterCountPF>
+          <clusterCountRaw>4572435</clusterCountRaw>
+          <oneSig>1296.18</oneSig>
+          <percentClustersPF>89.58</percentClustersPF>
+          <signal20AsPctOf1>88.12</signal20AsPctOf1>
+          <tileNumber>1204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4329806</clusterCountPF>
+          <clusterCountRaw>4852097</clusterCountRaw>
+          <oneSig>1291.90</oneSig>
+          <percentClustersPF>89.24</percentClustersPF>
+          <signal20AsPctOf1>87.70</signal20AsPctOf1>
+          <tileNumber>1205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4484284</clusterCountPF>
+          <clusterCountRaw>5103542</clusterCountRaw>
+          <oneSig>1271.54</oneSig>
+          <percentClustersPF>87.87</percentClustersPF>
+          <signal20AsPctOf1>86.33</signal20AsPctOf1>
+          <tileNumber>1206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4545978</clusterCountPF>
+          <clusterCountRaw>5322851</clusterCountRaw>
+          <oneSig>1240.07</oneSig>
+          <percentClustersPF>85.40</percentClustersPF>
+          <signal20AsPctOf1>86.60</signal20AsPctOf1>
+          <tileNumber>1207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4236437</clusterCountPF>
+          <clusterCountRaw>5399609</clusterCountRaw>
+          <oneSig>1200.52</oneSig>
+          <percentClustersPF>78.46</percentClustersPF>
+          <signal20AsPctOf1>82.29</signal20AsPctOf1>
+          <tileNumber>1208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3745093</clusterCountPF>
+          <clusterCountRaw>4091803</clusterCountRaw>
+          <oneSig>1377.26</oneSig>
+          <percentClustersPF>91.53</percentClustersPF>
+          <signal20AsPctOf1>85.86</signal20AsPctOf1>
+          <tileNumber>1301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3938377</clusterCountPF>
+          <clusterCountRaw>4338397</clusterCountRaw>
+          <oneSig>1338.33</oneSig>
+          <percentClustersPF>90.78</percentClustersPF>
+          <signal20AsPctOf1>87.63</signal20AsPctOf1>
+          <tileNumber>1302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3963514</clusterCountPF>
+          <clusterCountRaw>4395406</clusterCountRaw>
+          <oneSig>1308.84</oneSig>
+          <percentClustersPF>90.17</percentClustersPF>
+          <signal20AsPctOf1>88.08</signal20AsPctOf1>
+          <tileNumber>1303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4282045</clusterCountPF>
+          <clusterCountRaw>4835601</clusterCountRaw>
+          <oneSig>1287.81</oneSig>
+          <percentClustersPF>88.55</percentClustersPF>
+          <signal20AsPctOf1>87.58</signal20AsPctOf1>
+          <tileNumber>1304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4498474</clusterCountPF>
+          <clusterCountRaw>5114668</clusterCountRaw>
+          <oneSig>1282.81</oneSig>
+          <percentClustersPF>87.95</percentClustersPF>
+          <signal20AsPctOf1>87.46</signal20AsPctOf1>
+          <tileNumber>1305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4602295</clusterCountPF>
+          <clusterCountRaw>5337911</clusterCountRaw>
+          <oneSig>1257.03</oneSig>
+          <percentClustersPF>86.22</percentClustersPF>
+          <signal20AsPctOf1>86.97</signal20AsPctOf1>
+          <tileNumber>1306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4600782</clusterCountPF>
+          <clusterCountRaw>5501477</clusterCountRaw>
+          <oneSig>1225.51</oneSig>
+          <percentClustersPF>83.63</percentClustersPF>
+          <signal20AsPctOf1>86.53</signal20AsPctOf1>
+          <tileNumber>1307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4145380</clusterCountPF>
+          <clusterCountRaw>5872929</clusterCountRaw>
+          <oneSig>1175.25</oneSig>
+          <percentClustersPF>70.58</percentClustersPF>
+          <signal20AsPctOf1>83.85</signal20AsPctOf1>
+          <tileNumber>1308</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3654318</clusterCountPF>
+          <clusterCountRaw>3969110</clusterCountRaw>
+          <oneSig>1467.08</oneSig>
+          <percentClustersPF>92.07</percentClustersPF>
+          <signal20AsPctOf1>90.01</signal20AsPctOf1>
+          <tileNumber>2101</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3839864</clusterCountPF>
+          <clusterCountRaw>4184268</clusterCountRaw>
+          <oneSig>1439.99</oneSig>
+          <percentClustersPF>91.77</percentClustersPF>
+          <signal20AsPctOf1>90.66</signal20AsPctOf1>
+          <tileNumber>2102</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3969051</clusterCountPF>
+          <clusterCountRaw>4413583</clusterCountRaw>
+          <oneSig>1422.63</oneSig>
+          <percentClustersPF>89.93</percentClustersPF>
+          <signal20AsPctOf1>90.66</signal20AsPctOf1>
+          <tileNumber>2103</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4219627</clusterCountPF>
+          <clusterCountRaw>4681613</clusterCountRaw>
+          <oneSig>1403.97</oneSig>
+          <percentClustersPF>90.13</percentClustersPF>
+          <signal20AsPctOf1>90.49</signal20AsPctOf1>
+          <tileNumber>2104</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4414065</clusterCountPF>
+          <clusterCountRaw>4956383</clusterCountRaw>
+          <oneSig>1386.15</oneSig>
+          <percentClustersPF>89.06</percentClustersPF>
+          <signal20AsPctOf1>89.95</signal20AsPctOf1>
+          <tileNumber>2105</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4579204</clusterCountPF>
+          <clusterCountRaw>5232590</clusterCountRaw>
+          <oneSig>1365.53</oneSig>
+          <percentClustersPF>87.51</percentClustersPF>
+          <signal20AsPctOf1>89.26</signal20AsPctOf1>
+          <tileNumber>2106</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4682961</clusterCountPF>
+          <clusterCountRaw>5469205</clusterCountRaw>
+          <oneSig>1333.32</oneSig>
+          <percentClustersPF>85.62</percentClustersPF>
+          <signal20AsPctOf1>89.03</signal20AsPctOf1>
+          <tileNumber>2107</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3928926</clusterCountPF>
+          <clusterCountRaw>5870004</clusterCountRaw>
+          <oneSig>1286.80</oneSig>
+          <percentClustersPF>66.93</percentClustersPF>
+          <signal20AsPctOf1>87.34</signal20AsPctOf1>
+          <tileNumber>2108</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3556282</clusterCountPF>
+          <clusterCountRaw>3852699</clusterCountRaw>
+          <oneSig>1457.50</oneSig>
+          <percentClustersPF>92.31</percentClustersPF>
+          <signal20AsPctOf1>88.49</signal20AsPctOf1>
+          <tileNumber>2201</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3741136</clusterCountPF>
+          <clusterCountRaw>4072130</clusterCountRaw>
+          <oneSig>1441.42</oneSig>
+          <percentClustersPF>91.87</percentClustersPF>
+          <signal20AsPctOf1>89.42</signal20AsPctOf1>
+          <tileNumber>2202</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3842742</clusterCountPF>
+          <clusterCountRaw>4212391</clusterCountRaw>
+          <oneSig>1415.97</oneSig>
+          <percentClustersPF>91.22</percentClustersPF>
+          <signal20AsPctOf1>89.95</signal20AsPctOf1>
+          <tileNumber>2203</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4140127</clusterCountPF>
+          <clusterCountRaw>4577001</clusterCountRaw>
+          <oneSig>1387.43</oneSig>
+          <percentClustersPF>90.46</percentClustersPF>
+          <signal20AsPctOf1>89.88</signal20AsPctOf1>
+          <tileNumber>2204</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4372303</clusterCountPF>
+          <clusterCountRaw>4862284</clusterCountRaw>
+          <oneSig>1384.77</oneSig>
+          <percentClustersPF>89.92</percentClustersPF>
+          <signal20AsPctOf1>88.76</signal20AsPctOf1>
+          <tileNumber>2205</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4531801</clusterCountPF>
+          <clusterCountRaw>5119662</clusterCountRaw>
+          <oneSig>1367.26</oneSig>
+          <percentClustersPF>88.52</percentClustersPF>
+          <signal20AsPctOf1>88.81</signal20AsPctOf1>
+          <tileNumber>2206</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4148375</clusterCountPF>
+          <clusterCountRaw>5301292</clusterCountRaw>
+          <oneSig>1326.28</oneSig>
+          <percentClustersPF>78.25</percentClustersPF>
+          <signal20AsPctOf1>89.46</signal20AsPctOf1>
+          <tileNumber>2207</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3747919</clusterCountPF>
+          <clusterCountRaw>5523881</clusterCountRaw>
+          <oneSig>1328.04</oneSig>
+          <percentClustersPF>67.85</percentClustersPF>
+          <signal20AsPctOf1>85.54</signal20AsPctOf1>
+          <tileNumber>2208</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3685991</clusterCountPF>
+          <clusterCountRaw>4034260</clusterCountRaw>
+          <oneSig>1437.04</oneSig>
+          <percentClustersPF>91.37</percentClustersPF>
+          <signal20AsPctOf1>88.87</signal20AsPctOf1>
+          <tileNumber>2301</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3894450</clusterCountPF>
+          <clusterCountRaw>4285846</clusterCountRaw>
+          <oneSig>1425.73</oneSig>
+          <percentClustersPF>90.87</percentClustersPF>
+          <signal20AsPctOf1>89.86</signal20AsPctOf1>
+          <tileNumber>2302</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>3941822</clusterCountPF>
+          <clusterCountRaw>4382141</clusterCountRaw>
+          <oneSig>1397.98</oneSig>
+          <percentClustersPF>89.95</percentClustersPF>
+          <signal20AsPctOf1>90.41</signal20AsPctOf1>
+          <tileNumber>2303</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4299760</clusterCountPF>
+          <clusterCountRaw>4825173</clusterCountRaw>
+          <oneSig>1380.92</oneSig>
+          <percentClustersPF>89.11</percentClustersPF>
+          <signal20AsPctOf1>89.99</signal20AsPctOf1>
+          <tileNumber>2304</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4523197</clusterCountPF>
+          <clusterCountRaw>5101827</clusterCountRaw>
+          <oneSig>1374.81</oneSig>
+          <percentClustersPF>88.66</percentClustersPF>
+          <signal20AsPctOf1>89.72</signal20AsPctOf1>
+          <tileNumber>2305</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4658536</clusterCountPF>
+          <clusterCountRaw>5357124</clusterCountRaw>
+          <oneSig>1362.66</oneSig>
+          <percentClustersPF>86.96</percentClustersPF>
+          <signal20AsPctOf1>88.93</signal20AsPctOf1>
+          <tileNumber>2306</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>4706753</clusterCountPF>
+          <clusterCountRaw>5569616</clusterCountRaw>
+          <oneSig>1336.27</oneSig>
+          <percentClustersPF>84.51</percentClustersPF>
+          <signal20AsPctOf1>89.15</signal20AsPctOf1>
+          <tileNumber>2307</tileNumber>
+        </Tile>
+        <Tile>
+          <clusterCountPF>2196707</clusterCountPF>
+          <clusterCountRaw>3787138</clusterCountRaw>
+          <oneSig>1265.29</oneSig>
+          <percentClustersPF>58.00</percentClustersPF>
+          <signal20AsPctOf1>89.55</signal20AsPctOf1>
+          <tileNumber>2308</tileNumber>
+        </Tile>
+        <readNumber>1</readNumber>
+      </Read>
+      
+      <laneNumber>8</laneNumber>
+    </Lane>
+  </TileResultsByLane>
+</BustardSummary>
diff --git a/htsworkflow/pipelines/test/testdata/rta_basecalls_config_1.12.4.2.xml b/htsworkflow/pipelines/test/testdata/rta_basecalls_config_1.12.4.2.xml
new file mode 100755 (executable)
index 0000000..9da5d01
--- /dev/null
@@ -0,0 +1,511 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<BaseCallAnalysis xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">\r
+  <Run Name="BaseCalls">\r
+    <BaseCallParameters>\r
+      <ChastityThreshold>0.6</ChastityThreshold>\r
+      <Matrix Path="">\r
+        <AutoFlag>2</AutoFlag>\r
+        <AutoLane>0</AutoLane>\r
+        <Cycle>1</Cycle>\r
+        <CycleOffset>0</CycleOffset>\r
+        <FirstCycle>1</FirstCycle>\r
+        <LastCycle>50</LastCycle>\r
+        <Read>1</Read>\r
+      </Matrix>\r
+      <Matrix Path="">\r
+        <AutoFlag>2</AutoFlag>\r
+        <AutoLane>0</AutoLane>\r
+        <Cycle>51</Cycle>\r
+        <CycleOffset>0</CycleOffset>\r
+        <FirstCycle>51</FirstCycle>\r
+        <LastCycle>57</LastCycle>\r
+        <Read>2</Read>\r
+      </Matrix>\r
+      <Phasing Path="">\r
+        <AutoFlag>2</AutoFlag>\r
+        <AutoLane>0</AutoLane>\r
+        <Cycle>2</Cycle>\r
+        <CycleOffset>1</CycleOffset>\r
+        <FirstCycle>1</FirstCycle>\r
+        <LastCycle>50</LastCycle>\r
+        <Read>1</Read>\r
+        <PhasingRate>0</PhasingRate>\r
+        <PrephasingRate>0</PrephasingRate>\r
+      </Phasing>\r
+      <Phasing Path="">\r
+        <AutoFlag>2</AutoFlag>\r
+        <AutoLane>0</AutoLane>\r
+        <Cycle>52</Cycle>\r
+        <CycleOffset>1</CycleOffset>\r
+        <FirstCycle>51</FirstCycle>\r
+        <LastCycle>57</LastCycle>\r
+        <Read>2</Read>\r
+        <PhasingRate>0</PhasingRate>\r
+        <PrephasingRate>0</PrephasingRate>\r
+      </Phasing>\r
+      <PureBases>0</PureBases>\r
+      <SmtFilter>failed-chastity</SmtFilter>\r
+      <SmtRelation>le</SmtRelation>\r
+      <SmtThreshold>1.0</SmtThreshold>\r
+    </BaseCallParameters>\r
+    <Cycles First="1" Last="57" Number="57" />\r
+    <Input />\r
+    <RunParameters>\r
+      <AutoCycleFlag>0</AutoCycleFlag>\r
+      <BasecallFlag>0</BasecallFlag>\r
+      <Deblocked>0</Deblocked>\r
+      <DebugFlag>0</DebugFlag>\r
+      <FirstRunOnlyFlag>0</FirstRunOnlyFlag>\r
+      <ImagingReads Index="1">\r
+        <FirstCycle>1</FirstCycle>\r
+        <LastCycle>50</LastCycle>\r
+      </ImagingReads>\r
+      <ImagingReads Index="2">\r
+        <FirstCycle>51</FirstCycle>\r
+        <LastCycle>57</LastCycle>\r
+        <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>\r
+      </ImagingReads>\r
+      <Instrument>HWI-ST0787</Instrument>\r
+      <IterativeMatrixFlag>0</IterativeMatrixFlag>\r
+      <MakeFlag>0</MakeFlag>\r
+      <MaxCycle>0</MaxCycle>\r
+      <MinCycle>0</MinCycle>\r
+      <Reads Index="1">\r
+        <FirstCycle>1</FirstCycle>\r
+        <LastCycle>50</LastCycle>\r
+      </Reads>\r
+      <Reads Index="2">\r
+        <FirstCycle>51</FirstCycle>\r
+        <LastCycle>57</LastCycle>\r
+        <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>\r
+      </Reads>\r
+      <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>\r
+      <RunFolderDate>110815</RunFolderDate>\r
+      <RunFolderId>0101</RunFolderId>\r
+      <RunFlowcellId>D07K6ACXX</RunFlowcellId>\r
+      <Barcode>\r
+        <Cycle Use="true">51</Cycle>\r
+        <Cycle Use="true">52</Cycle>\r
+        <Cycle Use="true">53</Cycle>\r
+        <Cycle Use="true">54</Cycle>\r
+        <Cycle Use="true">55</Cycle>\r
+        <Cycle Use="true">56</Cycle>\r
+        <Cycle Use="true">57</Cycle>\r
+      </Barcode>\r
+      <QTableVersion>New6</QTableVersion>\r
+    </RunParameters>\r
+    <Software Name="RTA" Version="1.12.4.2" />\r
+    <TileSelection>\r
+      <Lane Index="1">\r
+        <Sample>s</Sample>\r
+        <Tile>1102</Tile>\r
+        <Tile>1101</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2307</Tile>\r
+      </Lane>\r
+      <Lane Index="2">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2307</Tile>\r
+      </Lane>\r
+      <Lane Index="3">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2306</Tile>\r
+      </Lane>\r
+      <Lane Index="4">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2306</Tile>\r
+      </Lane>\r
+      <Lane Index="5">\r
+        <Sample>s</Sample>\r
+        <Tile>1104</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1101</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2306</Tile>\r
+      </Lane>\r
+      <Lane Index="6">\r
+        <Sample>s</Sample>\r
+        <Tile>1104</Tile>\r
+        <Tile>1101</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2305</Tile>\r
+      </Lane>\r
+      <Lane Index="7">\r
+        <Sample>s</Sample>\r
+        <Tile>1103</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1101</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2308</Tile>\r
+      </Lane>\r
+      <Lane Index="8">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2308</Tile>\r
+      </Lane>\r
+    </TileSelection>\r
+    <Time />\r
+    <User />\r
+  </Run>\r
+</BaseCallAnalysis>
\ No newline at end of file
diff --git a/htsworkflow/pipelines/test/testdata/rta_intensities_config_1.12.4.2.xml b/htsworkflow/pipelines/test/testdata/rta_intensities_config_1.12.4.2.xml
new file mode 100755 (executable)
index 0000000..6d43157
--- /dev/null
@@ -0,0 +1,472 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<ImageAnalysis xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">\r
+  <Run Name="Intensities">\r
+    <Cycles First="1" Last="57" Number="57" />\r
+    <ImageParameters>\r
+      <AutoOffsetFlag>0</AutoOffsetFlag>\r
+      <AutoSizeFlag>0</AutoSizeFlag>\r
+      <Fwhm>0</Fwhm>\r
+      <RemappingDistance>0</RemappingDistance>\r
+      <Threshold>0</Threshold>\r
+    </ImageParameters>\r
+    <RunParameters>\r
+      <AutoCycleFlag>0</AutoCycleFlag>\r
+      <BasecallFlag>0</BasecallFlag>\r
+      <Deblocked>0</Deblocked>\r
+      <DebugFlag>0</DebugFlag>\r
+      <FirstRunOnlyFlag>0</FirstRunOnlyFlag>\r
+      <ImagingReads Index="1">\r
+        <FirstCycle>1</FirstCycle>\r
+        <LastCycle>50</LastCycle>\r
+        <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>\r
+      </ImagingReads>\r
+      <ImagingReads Index="2">\r
+        <FirstCycle>51</FirstCycle>\r
+        <LastCycle>57</LastCycle>\r
+        <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>\r
+      </ImagingReads>\r
+      <Instrument>HWI-ST0787</Instrument>\r
+      <IterativeMatrixFlag>0</IterativeMatrixFlag>\r
+      <MakeFlag>0</MakeFlag>\r
+      <MaxCycle>0</MaxCycle>\r
+      <MinCycle>0</MinCycle>\r
+      <Reads Index="1">\r
+        <FirstCycle>1</FirstCycle>\r
+        <LastCycle>50</LastCycle>\r
+        <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>\r
+      </Reads>\r
+      <Reads Index="2">\r
+        <FirstCycle>51</FirstCycle>\r
+        <LastCycle>57</LastCycle>\r
+        <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>\r
+      </Reads>\r
+      <RunFolder>110815_SN787_0101_AD07K6ACXX</RunFolder>\r
+      <RunFolderDate>110815</RunFolderDate>\r
+      <RunFolderId>0101</RunFolderId>\r
+      <RunFlowcellId>D07K6ACXX</RunFlowcellId>\r
+      <Barcode>\r
+        <Cycle Use="true">51</Cycle>\r
+        <Cycle Use="true">52</Cycle>\r
+        <Cycle Use="true">53</Cycle>\r
+        <Cycle Use="true">54</Cycle>\r
+        <Cycle Use="true">55</Cycle>\r
+        <Cycle Use="true">56</Cycle>\r
+        <Cycle Use="true">57</Cycle>\r
+      </Barcode>\r
+      <QTableVersion>New6</QTableVersion>\r
+    </RunParameters>\r
+    <Software Name="RTA" Version="1.12.4.2" />\r
+    <TileSelection>\r
+      <Lane Index="1">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2307</Tile>\r
+      </Lane>\r
+      <Lane Index="2">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2308</Tile>\r
+      </Lane>\r
+      <Lane Index="3">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2307</Tile>\r
+      </Lane>\r
+      <Lane Index="4">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2308</Tile>\r
+        <Tile>2307</Tile>\r
+      </Lane>\r
+      <Lane Index="5">\r
+        <Sample>s</Sample>\r
+        <Tile>1102</Tile>\r
+        <Tile>1101</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2308</Tile>\r
+      </Lane>\r
+      <Lane Index="6">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2308</Tile>\r
+      </Lane>\r
+      <Lane Index="7">\r
+        <Sample>s</Sample>\r
+        <Tile>1102</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1101</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2308</Tile>\r
+      </Lane>\r
+      <Lane Index="8">\r
+        <Sample>s</Sample>\r
+        <Tile>1101</Tile>\r
+        <Tile>1102</Tile>\r
+        <Tile>1105</Tile>\r
+        <Tile>1106</Tile>\r
+        <Tile>1201</Tile>\r
+        <Tile>1202</Tile>\r
+        <Tile>1103</Tile>\r
+        <Tile>1205</Tile>\r
+        <Tile>1206</Tile>\r
+        <Tile>1107</Tile>\r
+        <Tile>1301</Tile>\r
+        <Tile>1302</Tile>\r
+        <Tile>1203</Tile>\r
+        <Tile>1306</Tile>\r
+        <Tile>1305</Tile>\r
+        <Tile>1207</Tile>\r
+        <Tile>2101</Tile>\r
+        <Tile>1303</Tile>\r
+        <Tile>2102</Tile>\r
+        <Tile>1307</Tile>\r
+        <Tile>2105</Tile>\r
+        <Tile>2103</Tile>\r
+        <Tile>2106</Tile>\r
+        <Tile>2201</Tile>\r
+        <Tile>2107</Tile>\r
+        <Tile>2205</Tile>\r
+        <Tile>2202</Tile>\r
+        <Tile>2206</Tile>\r
+        <Tile>2203</Tile>\r
+        <Tile>2301</Tile>\r
+        <Tile>2305</Tile>\r
+        <Tile>2302</Tile>\r
+        <Tile>2306</Tile>\r
+        <Tile>1104</Tile>\r
+        <Tile>2207</Tile>\r
+        <Tile>1108</Tile>\r
+        <Tile>1204</Tile>\r
+        <Tile>2303</Tile>\r
+        <Tile>2307</Tile>\r
+        <Tile>1208</Tile>\r
+        <Tile>1304</Tile>\r
+        <Tile>1308</Tile>\r
+        <Tile>2104</Tile>\r
+        <Tile>2108</Tile>\r
+        <Tile>2204</Tile>\r
+        <Tile>2208</Tile>\r
+        <Tile>2304</Tile>\r
+        <Tile>2308</Tile>\r
+      </Lane>\r
+    </TileSelection>\r
+    <Time />\r
+    <User />\r
+  </Run>\r
+</ImageAnalysis>
\ No newline at end of file
diff --git a/htsworkflow/pipelines/test/testdata/sample_summary_1_12.htm b/htsworkflow/pipelines/test/testdata/sample_summary_1_12.htm
new file mode 100644 (file)
index 0000000..468f72d
--- /dev/null
@@ -0,0 +1,434 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html xmlns:casava="http://www.illumina.com/casava/alignment">
+<link rel="stylesheet" href="../../css/Reports.css" type="text/css">
+<body>
+<p>Sample Summary Information For Experiment (12564_index6)</p>
+<p>Project Summary</p>
+<table border="1" cellpadding="5">
+<tr>
+<td>Project Name</td>
+<td>12564_index6</td>
+</tr>
+<tr>
+<td>Machine</td>
+<td>HWI-ST0787</td>
+</tr>
+<tr>
+<td>Run Folder</td>
+<td>111221_SN787_0107_AD0CV5ACXX</td>
+</tr>
+<tr>
+<td>Flow Cell ID</td>
+<td>D0CV5ACXX</td>
+</tr>
+<tr>
+<td>Platform</td>
+<td></td>
+</tr>
+<tr>
+<td>Control Software</td>
+<td>HiSeq Control Software 1.4.8</td>
+</tr>
+<tr>
+<td>Primary Analysis</td>
+<td>RTA 1.12.4.2</td>
+</tr>
+<tr>
+<td>Secondary Analysis</td>
+<td>CASAVA-1.8.1</td>
+</tr>
+</table>
+<p>Project Results Summary</p>
+<table border="1" cellpadding="5">
+<tr>
+<th>Clusters (Raw)</th>
+<th>Clusters(PF)</th>
+<th>Yield (MBases)</th>
+</tr>
+<tr>
+<td>658,174</td>
+<td>475,618</td>
+<td>23</td>
+</tr>
+</table>
+<p>Barcode-Lane summary</p>
+<div ID="ScrollableTableHeaderDiv"><table width="100%">
+<col>
+<col width="8%">
+<col width="10%">
+<col width="4%">
+<col width="20%">
+<col width="6%">
+<col width="6%">
+<col width="4%">
+<col width="30%">
+<tr>
+<th>Barcode-Lane</th>
+<th>Sample</th>
+<th>Barcode</th>
+<th>Lane</th>
+<th>Species</th>
+<th>Analysis Type</th>
+<th>Length</th>
+<th>Num Tiles</th>
+<th>Genome Directory</th>
+</tr>
+</table></div>
+<div ID="ScrollableTableBodyDiv"><table width="100%">
+<col>
+<col width="8%">
+<col width="10%">
+<col width="4%">
+<col width="20%">
+<col width="6%">
+<col width="6%">
+<col width="4%">
+<col width="30%">
+<tr>
+<td>12564_GCCAAT_L5</td>
+<td>12564</td>
+<td>GCCAAT</td>
+<td>5</td>
+<td>Homo_sapiens</td>
+<td>eland extended</td>
+<td>49 </td>
+<td>48</td>
+<td>/mmjggl/nicodemus/data01/genomes/hg18/chromosomes//*.fa</td>
+</tr>
+</table></div>
+<p>Sample Results Summary : Read 1</p>
+<div ID="ScrollableTableHeaderDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="8%">
+<col width="8%">
+<col width="12%">
+<col width="12%">
+<col width="8%">
+<col width="7%">
+<col width="9%">
+<col width="8%">
+<col width="6%">
+<col width="6%">
+<tr><th colspan="12">Sample Info</th></tr>
+<tr>
+<th>Sample</th>
+<th>Sample Yield (Mbases)</th>
+<th>Clusters (raw)</th>
+<th>Clusters (PF)</th>
+<th>1st Cycle Int (PF)</th>
+<th>% intensity after 20 cycles (PF)</th>
+<th>% PF Clusters</th>
+<th>% Align (PF)</th>
+<th>Alignment Score (PF)</th>
+<th>% Mismatch Rate (PF)</th>
+<th>% &gt;=Q30 bases (PF)</th>
+<th>Mean Quality SCore (PF)</th>
+</tr>
+</table></div>
+<div ID="ScrollableTableBodyDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="8%">
+<col width="8%">
+<col width="12%">
+<col width="12%">
+<col width="8%">
+<col width="7%">
+<col width="9%">
+<col width="8%">
+<col width="6%">
+<col width="6%">
+<tr>
+<td>12564</td>
+<td>23</td>
+<td>658,174</td>
+<td>475,618</td>
+<td>1100</td>
+<td>89.39</td>
+<td>72.26</td>
+<td>76.89</td>
+<td>128.73</td>
+<td>0.40</td>
+<td>88.79</td>
+<td>35.13</td>
+</tr>
+</table></div>
+<p>Sample Results Summary : Read 2</p>
+<div ID="ScrollableTableHeaderDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="8%">
+<col width="8%">
+<col width="12%">
+<col width="12%">
+<col width="8%">
+<col width="7%">
+<col width="9%">
+<col width="8%">
+<col width="6%">
+<col width="6%">
+<tr><th colspan="12">Sample Info</th></tr>
+<tr>
+<th>Sample</th>
+<th>Sample Yield (Mbases)</th>
+<th>Clusters (raw)</th>
+<th>Clusters (PF)</th>
+<th>1st Cycle Int (PF)</th>
+<th>% intensity after 20 cycles (PF)</th>
+<th>% PF Clusters</th>
+<th>% Align (PF)</th>
+<th>Alignment Score (PF)</th>
+<th>% Mismatch Rate (PF)</th>
+<th>% &gt;=Q30 bases (PF)</th>
+<th>Mean Quality SCore (PF)</th>
+</tr>
+</table></div>
+<div ID="ScrollableTableBodyDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="8%">
+<col width="8%">
+<col width="12%">
+<col width="12%">
+<col width="8%">
+<col width="7%">
+<col width="9%">
+<col width="8%">
+<col width="6%">
+<col width="6%">
+<tr>
+<td>12564</td>
+<td>0</td>
+<td>0</td>
+<td>0</td>
+<td>0</td>
+<td>0</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+</table></div>
+<p>Expanded Sample Summary : Read 1</p>
+<div ID="ScrollableTableHeaderDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="8%">
+<col width="8%">
+<col width="8%">
+<col width="6%">
+<col width="10%">
+<col width="10%">
+<col width="9%">
+<col width="5%">
+<col width="8%">
+<col width="6%">
+<col width="6%">
+<tr>
+<th colspan="2">Sample Info</th>
+<th colspan="2">Phasing Info</th>
+<th colspan="1">Raw data</th>
+<th colspan="8">Filtered data</th>
+</tr>
+<tr>
+<th>Sample</th>
+<th>Clusters (raw)</th>
+<th>% Phasing</th>
+<th>% Prephasing</th>
+<th>% Mismatch Rate (raw)</th>
+<th>% PF Clusters</th>
+<th>Cycle 2-4 Av Int (PF)</th>
+<th>Cycle 2-10 Av % Loss (PF)</th>
+<th>Cycle 10-20 Av % Loss (PF)</th>
+<th>% Align (PF)</th>
+<th>% Mismatch Rate (PF)</th>
+<th>% &gt;=Q30 bases (PF)</th>
+<th>Mean Quality SCore (PF)</th>
+</tr>
+</table></div>
+<div ID="ScrollableTableBodyDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="8%">
+<col width="8%">
+<col width="8%">
+<col width="6%">
+<col width="10%">
+<col width="10%">
+<col width="9%">
+<col width="5%">
+<col width="8%">
+<col width="6%">
+<col width="6%">
+<tr>
+<td>12564</td>
+<td>658,174</td>
+<td>0.19</td>
+<td>0.31</td>
+<td>0.77</td>
+<td>72.26</td>
+<td>1083.00</td>
+<td>-84.76</td>
+<td>0.48</td>
+<td>76.89</td>
+<td>0.40</td>
+<td>88.79</td>
+<td>35.13</td>
+</tr>
+</table></div>
+<p>Expanded Sample Summary : Read 2</p>
+<div ID="ScrollableTableHeaderDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="8%">
+<col width="8%">
+<col width="8%">
+<col width="6%">
+<col width="10%">
+<col width="10%">
+<col width="9%">
+<col width="5%">
+<col width="8%">
+<col width="6%">
+<col width="6%">
+<tr>
+<th colspan="2">Sample Info</th>
+<th colspan="2">Phasing Info</th>
+<th colspan="1">Raw data</th>
+<th colspan="8">Filtered data</th>
+</tr>
+<tr>
+<th>Sample</th>
+<th>Clusters (raw)</th>
+<th>% Phasing</th>
+<th>% Prephasing</th>
+<th>% Mismatch Rate (raw)</th>
+<th>% PF Clusters</th>
+<th>Cycle 2-4 Av Int (PF)</th>
+<th>Cycle 2-10 Av % Loss (PF)</th>
+<th>Cycle 10-20 Av % Loss (PF)</th>
+<th>% Align (PF)</th>
+<th>% Mismatch Rate (PF)</th>
+<th>% &gt;=Q30 bases (PF)</th>
+<th>Mean Quality SCore (PF)</th>
+</tr>
+</table></div>
+<div ID="ScrollableTableBodyDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="8%">
+<col width="8%">
+<col width="8%">
+<col width="6%">
+<col width="10%">
+<col width="10%">
+<col width="9%">
+<col width="5%">
+<col width="8%">
+<col width="6%">
+<col width="6%">
+<tr>
+<td>12564</td>
+<td>0</td>
+<td>0</td>
+<td>0</td>
+<td></td>
+<td></td>
+<td>0</td>
+<td>0</td>
+<td>0</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+</table></div>
+<p>IVC Plots</p>
+<a href="/mmjggl/nicodemus/data01/sequencer/111221_SN787_0107_AD0CV5ACXX/Unaligned/Basecall_Stats_D0CV5ACXX/IVC.htm">
+click here
+</a><p>All Intensity Plots</p>
+<a href="/mmjggl/nicodemus/data01/sequencer/111221_SN787_0107_AD0CV5ACXX/Unaligned/Basecall_Stats_D0CV5ACXX/All.htm">
+click here
+</a><p>Mismatch Graphs</p>
+<a href="FullMismatch.htm">
+click here
+</a><p>Mismatch Curves</p>
+<a href="FullPerfect.htm">
+click here
+</a><p>Additional Paired Statistics</p>
+<div ID="ScrollableTableHeaderDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="7%">
+<col width="7%">
+<col width="7%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="9%">
+<tr>
+<th colspan="1">Sample Info</th>
+<th colspan="5">Relative Orientation Statistics</th>
+<th colspan="5">Insert Size Statistics (for relative orientation R+)</th>
+<th colspan="3">Insert Statistics (% of individually uniquely alignable pairs)</th>
+</tr>
+<tr>
+<th>Sample</th>
+<th>F-:<br>&gt;R2 R1&gt;</th>
+<th>F+:<br>&gt;R1 R2&gt;</th>
+<th>R-:<br>&lt;R2 R1&gt;</th>
+<th>R+:<br>&gt;R1 R2&lt;</th>
+<th>Total</th>
+<th>Median</th>
+<th>Below-median SD</th>
+<th>Above-median SD</th>
+<th>Low thresh.</th>
+<th>High thresh.</th>
+<th>Too small</th>
+<th>Too large</th>
+<th>Orientation and size OK</th>
+</tr>
+</table></div>
+<div ID="ScrollableTableBodyDiv"><table width="100%">
+<col>
+<col width="7%">
+<col width="7%">
+<col width="7%">
+<col width="7%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="6%">
+<col width="9%">
+<tr>
+<td>12564</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td>0</td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+<td></td>
+</tr>
+</table></div>
+<p>CASAVA-1.8.1</p>
+</body>
+</html>
index d3cabf912bceea92db355f2f436f577ffca119ae..dce9b2b36418863cf35327153992c9d16419be44 100644 (file)
@@ -192,7 +192,8 @@ TEMPLATE_DIRS = (
     # Don't forget to use absolute paths, not relative paths.
     '/usr/share/python-support/python-django/django/contrib/admin/templates',
     #'/usr/lib/pymodules/python2.6/django/contrib/admin/templates/',
-    os.path.join(HTSWORKFLOW_ROOT, 'frontend','templates'),
+    os.path.join(HTSWORKFLOW_ROOT, 'frontend', 'templates'),
+    os.path.join(HTSWORKFLOW_ROOT, 'templates'),
 )
 
 INSTALLED_APPS = (
index 20afdfd0ca16f5353f3ee6ffeacd90158931b7e9..8513f7b2da2b266803f12ec32acf650242fb165e 100644 (file)
@@ -2,15 +2,20 @@
 """
 import logging
 import os
+from pprint import pformat
 import sys
 import types
 
 from htsworkflow.pipelines.sequences import scan_for_sequences
 from htsworkflow.pipelines import qseq2fastq
 from htsworkflow.pipelines import srf2fastq
+from htsworkflow.pipelines import desplit_fastq
 from htsworkflow.util.api import HtswApi
 from htsworkflow.util.conversion import parse_flowcell_id
 
+from django.conf import settings
+from django.template import Context, loader
+
 LOGGER = logging.getLogger(__name__)
 
 class CondorFastqExtract(object):
@@ -31,79 +36,64 @@ class CondorFastqExtract(object):
         self.log_path = log_path
         self.force = force
 
-    def build_fastqs(self, library_result_map ):
+    def create_scripts(self, result_map ):
         """
         Generate condor scripts to build any needed fastq files
 
         Args:
-          library_result_map (list):  [(library_id, destination directory), ...]
+          result_map: htsworkflow.submission.results.ResultMap()
         """
-        qseq_condor_header = self.get_qseq_condor_header()
-        qseq_condor_entries = []
-        srf_condor_header = self.get_srf_condor_header()
-        srf_condor_entries = []
-        lib_db = self.find_archive_sequence_files(library_result_map)
-
-        needed_targets = self.find_missing_targets(library_result_map, lib_db)
+        template_map = {'srf': 'srf.condor',
+                        'qseq': 'qseq.condor',
+                        'split_fastq': 'split_fastq.condor'}
+
+        condor_entries = self.build_condor_arguments(result_map)
+        for script_type in template_map.keys():
+            template = loader.get_template(template_map[script_type])
+            variables = {'python': sys.executable,
+                         'logdir': self.log_path,
+                         'env': os.environ.get('PYTHONPATH', None),
+                         'args': condor_entries[script_type],
+                         }
+
+            context = Context(variables)
+
+            with open(script_type + '.condor','w+') as outstream:
+                outstream.write(template.render(context))
+
+    def build_condor_arguments(self, result_map):
+        condor_entries = {'srf': [],
+                          'qseq': [],
+                          'split_fastq': []}
+        conversion_funcs = {'srf': self.condor_srf_to_fastq,
+                            'qseq': self.condor_qseq_to_fastq,
+                            'split_fastq': self.condor_desplit_fastq
+                            }
+
+        lib_db = self.find_archive_sequence_files(result_map)
+        needed_targets = self.find_missing_targets(result_map, lib_db)
 
         for target_pathname, available_sources in needed_targets.items():
             LOGGER.debug(' target : %s' % (target_pathname,))
             LOGGER.debug(' candidate sources: %s' % (available_sources,))
-            if available_sources.has_key('qseq'):
-                source = available_sources['qseq']
-                qseq_condor_entries.append(
-                    self.condor_qseq_to_fastq(source.path,
-                                              target_pathname,
-                                              source.flowcell)
-                )
-            elif available_sources.has_key('srf'):
-                source = available_sources['srf']
-                mid = getattr(source, 'mid_point', None)
-                srf_condor_entries.append(
-                    self.condor_srf_to_fastq(source.path,
-                                             target_pathname,
-                                             source.paired,
-                                             source.flowcell,
-                                             mid)
-                )
+            for condor_type in available_sources.keys():
+                conversion = conversion_funcs.get(condor_type, None)
+                if conversion is None:
+                    errmsg = "Unrecognized type: {0} for {1}"
+                    print errmsg.format(condor_type,
+                                        pformat(available_sources))
+                    continue
+                sources = available_sources.get(condor_type, None)
+
+                if sources is not None:
+                    condor_entries.setdefault(condor_type, []).append(
+                        conversion(sources, target_pathname))
             else:
                 print " need file", target_pathname
 
-        if len(srf_condor_entries) > 0:
-            make_submit_script('srf.fastq.condor',
-                               srf_condor_header,
-                               srf_condor_entries)
-
-        if len(qseq_condor_entries) > 0:
-            make_submit_script('qseq.fastq.condor',
-                               qseq_condor_header,
-                               qseq_condor_entries)
-
-
-    def get_qseq_condor_header(self):
-        return """Universe=vanilla
-executable=%(exe)s
-error=%(log)s/qseq2fastq.$(process).out
-output=%(log)s/qseq2fastq.$(process).out
-log=%(log)s/qseq2fastq.log
-
-""" % {'exe': sys.executable,
-       'log': self.log_path }
-
-    def get_srf_condor_header(self):
-        return """Universe=vanilla
-executable=%(exe)s
-output=%(log)s/srf_pair_fastq.$(process).out
-error=%(log)s/srf_pair_fastq.$(process).out
-log=%(log)s/srf_pair_fastq.log
-environment="PYTHONPATH=%(env)s"
-
-""" % {'exe': sys.executable,
-           'log': self.log_path,
-           'env': os.environ.get('PYTHONPATH', '')
-      }
-
-    def find_archive_sequence_files(self,  library_result_map):
+        return condor_entries
+
+    def find_archive_sequence_files(self,  result_map):
         """
         Find archived sequence files associated with our results.
         """
@@ -112,7 +102,7 @@ environment="PYTHONPATH=%(env)s"
         lib_db = {}
         seq_dirs = set()
         candidate_lanes = {}
-        for lib_id, result_dir in library_result_map:
+        for lib_id in result_map.keys():
             lib_info = self.api.get_library(lib_id)
             lib_info['lanes'] = {}
             lib_db[lib_id] = lib_info
@@ -139,7 +129,7 @@ environment="PYTHONPATH=%(env)s"
 
         return lib_db
 
-    def find_missing_targets(self, library_result_map, lib_db):
+    def find_missing_targets(self, result_map, lib_db):
         """
         Check if the sequence file exists.
         This requires computing what the sequence name is and checking
@@ -151,7 +141,8 @@ environment="PYTHONPATH=%(env)s"
         fastq_single_template = '%(lib_id)s_%(flowcell)s_c%(cycle)s_l%(lane)s.fastq'
         # find what targets we're missing
         needed_targets = {}
-        for lib_id, result_dir in library_result_map:
+        for lib_id in result_map.keys():
+            result_dir = result_map[lib_id]
             lib = lib_db[lib_id]
             lane_dict = make_lane_dict(lib_db, lib_id)
 
@@ -179,92 +170,60 @@ environment="PYTHONPATH=%(env)s"
 
                     # end filters
                     if seq.paired:
-                        target_name = fastq_paired_template % filename_attributes
+                        target_name = fastq_paired_template % \
+                                      filename_attributes
                     else:
-                        target_name = fastq_single_template % filename_attributes
+                        target_name = fastq_single_template % \
+                                      filename_attributes
 
                     target_pathname = os.path.join(result_dir, target_name)
                     if self.force or not os.path.exists(target_pathname):
                         t = needed_targets.setdefault(target_pathname, {})
-                        t[seq.filetype] = seq
+                        t.setdefault(seq.filetype, []).append(seq)
 
         return needed_targets
 
 
-    def condor_srf_to_fastq(self,
-                            srf_file,
-                            target_pathname,
-                            paired,
-                            flowcell=None,
-                            mid=None):
-        py = srf2fastq.__file__
-        args = [ py, srf_file, '--verbose']
-        if paired:
-            args.extend(['--left', target_pathname])
-            # this is ugly. I did it because I was pregenerating the target
-            # names before I tried to figure out what sources could generate
-            # those targets, and everything up to this point had been
-            # one-to-one. So I couldn't figure out how to pair the
-            # target names.
-            # With this at least the command will run correctly.
-            # however if we rename the default targets, this'll break
-            # also I think it'll generate it twice.
-            args.extend(['--right',
-                         target_pathname.replace('_r1.fastq', '_r2.fastq')])
-        else:
-            args.extend(['--single', target_pathname ])
-        if flowcell is not None:
-            args.extend(['--flowcell', flowcell])
-
-        if mid is not None:
-            args.extend(['-m', str(mid)])
-
-        if self.force:
-            args.extend(['--force'])
-
-        script = """arguments="%s"
-queue
-""" % (" ".join(args),)
-
-        return  script
-
-
-    def condor_qseq_to_fastq(self, qseq_file, target_pathname, flowcell=None):
-        py = qseq2fastq.__file__
-        args = [py, '-i', qseq_file, '-o', target_pathname ]
-        if flowcell is not None:
-            args.extend(['-f', flowcell])
-        script = """arguments="%s"
-queue
-""" % (" ".join(args))
-
-        return script
-
-def make_submit_script(target, header, body_list):
-    """
-    write out a text file
-
-    this was intended for condor submit scripts
-
-    Args:
-      target (str or stream):
-        if target is a string, we will open and close the file
-        if target is a stream, the caller is responsible.
-
-      header (str);
-        header to write at the beginning of the file
-      body_list (list of strs):
-        a list of blocks to add to the file.
-    """
-    if type(target) in types.StringTypes:
-        f = open(target,"w")
-    else:
-        f = target
-    f.write(header)
-    for entry in body_list:
-        f.write(entry)
-    if type(target) in types.StringTypes:
-        f.close()
+    def condor_srf_to_fastq(self, sources, target_pathname):
+        if len(sources) > 1:
+            raise ValueError("srf to fastq can only handle one file")
+
+        return {
+            'sources': [os.path.abspath(sources[0].path)],
+            'pyscript': srf2fastq.__file__,
+            'flowcell': sources[0].flowcell,
+            'ispaired': sources[0].paired,
+            'target': target_pathname,
+            'target_right': target_pathname.replace('_r1.fastq', '_r2.fastq'),
+            'mid': getattr(sources[0], 'mid_point', None),
+            'force': self.force,
+        }
+
+    def condor_qseq_to_fastq(self, sources, target_pathname):
+        paths = []
+        for source in sources:
+            paths.append(source.path)
+        paths.sort()
+        return {
+            'pyscript': qseq2fastq.__file__,
+            'flowcell': sources[0].flowcell,
+            'target': target_pathname,
+            'sources': paths,
+            'ispaired': sources[0].paired,
+            'istar': len(sources) == 1,
+        }
+
+    def condor_desplit_fastq(self, sources, target_pathname):
+        paths = []
+        for source in sources:
+            paths.append(source.path)
+        paths.sort()
+        return {
+            'pyscript': desplit_fastq.__file__,
+            'target': target_pathname,
+            'sources': paths,
+            'ispaired': sources[0].paired,
+        }
 
 def make_lane_dict(lib_db, lib_id):
     """
index e477629bb88372307e216d9248a3885968932d13..96037b9647c93146a9887334c3ec1ebdf9266b0d 100644 (file)
@@ -2,6 +2,7 @@
 """
 import logging
 import os
+from pprint import pformat
 import re
 import string
 from StringIO import StringIO
@@ -12,6 +13,7 @@ import RDF
 from htsworkflow.util.rdfhelp import \
      blankOrUri, \
      dafTermOntology, \
+     dump_model, \
      get_model, \
      libraryOntology, \
      owlNS, \
@@ -128,6 +130,7 @@ def parse_stream(stream):
     if view_name is not None:
         attributes['views'][view_name] = view_attributes
 
+    logger.debug("DAF Attributes" + pformat(attributes))
     return attributes
 
 
@@ -234,8 +237,8 @@ def get_view_namespace(submission_uri):
     return viewNS
 
 
-class DAFMapper(object):
-    """Convert filenames to views in the UCSC Daf
+class UCSCSubmission(object):
+    """Build a submission by examining the DAF for what we need to submit
     """
     def __init__(self, name, daf_file=None, model=None):
         """Construct a RDF backed model of a UCSC DAF
@@ -264,15 +267,23 @@ class DAFMapper(object):
 
         if hasattr(daf_file, 'next'):
             # its some kind of stream
-            fromstream_into_model(self.model, self.submissionSet, daf_file)
+            self.daf = daf_file.read()
         else:
             # file
-            parse_into_model(self.model, self.submissionSet, daf_file)
+            stream = open(daf_file, 'r')
+            self.daf = stream.read()
+            stream.close()
+
+        fromstring_into_model(self.model, self.submissionSet, self.daf)
 
         self.libraryNS = RDF.NS('http://jumpgate.caltech.edu/library/')
         self.submissionSetNS = RDF.NS(str(self.submissionSet) + '/')
         self.__view_map = None
 
+    def _get_daf_name(self):
+        return self.name + '.daf'
+    daf_name = property(_get_daf_name,doc="construct name for DAF file")
+
     def add_pattern(self, view_name, filename_pattern):
         """Map a filename regular expression to a view name
         """
@@ -282,6 +293,16 @@ class DAFMapper(object):
                           dafTermOntology['filename_re'],
                           obj))
 
+    def scan_submission_dirs(self, result_map):
+        """Examine files in our result directory
+        """
+        for lib_id, result_dir in result_map.items():
+            logger.info("Importing %s from %s" % (lib_id, result_dir))
+            try:
+                self.import_submission_dir(result_dir, lib_id)
+            except MetadataLookupException, e:
+                logger.error("Skipping %s: %s" % (lib_id, str(e)))
+
     def import_submission_dir(self, submission_dir, library_id):
         """Import a submission directories and update our model as needed
         """
@@ -558,3 +579,57 @@ class DAFMapper(object):
                 return True
 
         return False
+
+
+    def link_daf(self, result_map):
+        if self.daf is None or len(self.daf) == 0:
+            raise RuntimeError(
+                "DAF data does not exist, how can I link to it?")
+
+        base_daf = self.daf_name
+
+        for result_dir in result_map.values():
+            if not os.path.exists(result_dir):
+                raise RuntimeError(
+                    "Couldn't find target directory %s" %(result_dir,))
+            submission_daf = os.path.join(result_dir, base_daf)
+            if os.path.exists(submission_daf):
+                previous_daf = open(submission_daf, 'r').read()
+                if self.daf != previous_daf:
+                    LOGGER.info("Old daf is different, overwriting it.")
+            stream = open(submission_daf, 'w')
+            stream.write(self.daf)
+            stream.close()
+
+
+if __name__ == "__main__":
+    example_daf = """# Lab and general info
+grant             Hardison
+lab               Caltech-m
+dataType          ChipSeq
+variables         cell, antibody,sex,age,strain,control
+compositeSuffix   CaltechHistone
+assembly          mm9
+dafVersion        2.0
+validationSettings validateFiles.bam:mismatches=2,bamPercent=99.9;validateFiles.fastq:quick=1000
+
+# Track/view definition
+view             FastqRd1
+longLabelPrefix  Caltech Fastq Read 1
+type             fastq
+hasReplicates    yes
+required         no
+
+view             Signal
+longLabelPrefix  Caltech Histone Signal
+type             bigWig
+hasReplicates    yes
+required         no
+"""
+    model = get_model()
+    example_daf_stream = StringIO(example_daf)
+    name = "test_rep"
+    mapper = DAFMapper(name, daf_file = example_daf_stream, model=model)
+    dump_model(model)
+
+
diff --git a/htsworkflow/submission/geo.py b/htsworkflow/submission/geo.py
new file mode 100644 (file)
index 0000000..737b1bb
--- /dev/null
@@ -0,0 +1,57 @@
+import logging
+
+import RDF
+
+from htsworkflow.submission.submission import Submission
+
+from htsworkflow.util.rdfhelp import \
+     fromTypedNode, \
+     submissionOntology
+
+from django.conf import settings
+from django.template import Context, loader
+
+LOGGER = logging.getLogger(__name__)
+
+class GEOSubmission(Submission):
+    def __init__(self, name, model):
+        super(GEOSubmission, self).__init__(name, model)
+
+    def make_soft(self, result_map):
+        samples = []
+        for lib_id, result_dir in result_map.items():
+            an_analysis = self.get_submission_node(result_dir)
+            samples.append(self.get_sample_metadata(an_analysis))
+
+        soft_template = loader.get_template('geo_submission.soft')
+        context = Context({
+            'samples': samples
+        })
+        print str(soft_template.render(context))
+
+    def check_for_name(self, analysis_node):
+        name = fromTypedNode(
+            self.model.get_target(analysis_node,
+                                  submissionOntology['name']))
+        if name is None:
+            logger.error("Need name for %s" % (str(analysis_node)))
+            return False
+        else:
+            return True
+
+    def get_sample_metadata(self, analysis_node):
+        """Gather information for filling out sample section of a SOFT file
+        """
+        query_template = loader.get_template('geo_submission.sparql')
+
+        context = Context({
+            'submission': str(analysis_node.uri),
+            })
+
+        formatted_query = query_template.render(context)
+        query = RDF.SPARQLQuery(str(formatted_query))
+        rdfstream = query.execute(self.model)
+        results = []
+        for r in rdfstream:
+            results.append(r)
+        return results
diff --git a/htsworkflow/submission/results.py b/htsworkflow/submission/results.py
new file mode 100644 (file)
index 0000000..daeb7d1
--- /dev/null
@@ -0,0 +1,94 @@
+"""Help collect and process results for submission
+"""
+import os
+import logging
+
+from collections import namedtuple
+
+LOGGER = logging.getLogger(__name__)
+
+class ResultMap(object):
+    """Store list of results
+    """
+    def __init__(self):
+        self.results_order = []
+        self.results = {}
+
+    def keys(self):
+        return self.results_order
+
+    def values(self):
+        return ( self.results[r] for r in self.results_order )
+
+    def items(self):
+        return ( (r, self.results[r]) for r in self.results_order )
+
+    def __getitem__(self, key):
+        return self.results[key]
+
+    def add_results_from_file(self, filename):
+        pathname = os.path.abspath(filename)
+        basepath, name = os.path.split(pathname)
+        results = read_result_list(filename)
+        for lib_id, lib_path in results:
+            if not os.path.isabs(lib_path):
+                lib_path = os.path.join(basepath, lib_path)
+            self.add_result(lib_id, lib_path)
+
+    def add_result(self, lib_id, lib_path):
+        self.results_order.append(lib_id)
+        self.results[lib_id] = lib_path
+
+    def make_tree_from(self, source_path, destpath = None):
+        """Create a tree using data files from source path.
+        """
+        print source_path, destpath
+        if destpath is None:
+            destpath = os.getcwd()
+
+        for lib_id in self.results_order:
+            lib_path = self.results[lib_id]
+            lib_destination = os.path.join(destpath, lib_path)
+            if not os.path.exists(lib_destination):
+                LOGGER.info("Making dir {0}".format(lib_destination))
+                os.mkdir(lib_destination)
+
+            source_rel_dir = os.path.join(source_path, lib_path)
+            source_lib_dir = os.path.abspath(source_rel_dir)
+
+            print "source_lib_dir", source_lib_dir
+            for filename in os.listdir(source_lib_dir):
+                source_pathname = os.path.join(source_lib_dir, filename)
+                target_pathname = os.path.join(lib_destination, filename)
+                if not os.path.exists(source_pathname):
+                    raise IOError(
+                        "{0} does not exist".format(source_pathname))
+                print target_pathname
+                if not os.path.exists(target_pathname):
+                    os.symlink(source_pathname, target_pathname)
+                    LOGGER.info(
+                        'LINK {0} to {1}'.format(source_pathname,
+                                                 target_pathname))
+
+def read_result_list(filename):
+    """
+    Read a file that maps library id to result directory.
+    Does not support spaces in filenames.
+
+    For example:
+      10000 result/foo/bar
+    """
+    stream = open(filename, 'r')
+    results = parse_result_list(stream)
+    stream.close()
+    return results
+
+
+def parse_result_list(stream):
+    results = []
+    for line in stream:
+        line = line.rstrip()
+        if not line.startswith('#') and len(line) > 0:
+            library_id, result_dir = line.split()
+            results.append((library_id, result_dir))
+    return results
diff --git a/htsworkflow/submission/submission.py b/htsworkflow/submission/submission.py
new file mode 100644 (file)
index 0000000..98c25d5
--- /dev/null
@@ -0,0 +1,256 @@
+"""Common submission elements
+"""
+import logging
+import os
+import re
+
+import RDF
+
+from htsworkflow.util.rdfhelp import \
+     blankOrUri, \
+     dafTermOntology, \
+     dump_model, \
+     get_model, \
+     libraryOntology, \
+     owlNS, \
+     rdfNS, \
+     submissionLog, \
+     submissionOntology, \
+     toTypedNode, \
+     fromTypedNode
+from htsworkflow.util.hashfile import make_md5sum
+
+from htsworkflow.submission.daf import \
+     MetadataLookupException, \
+     get_submission_uri
+
+logger = logging.getLogger(__name__)
+
+class Submission(object):
+    def __init__(self, name, model):
+        self.name = name
+        self.model = model
+
+        self.submissionSet = get_submission_uri(self.name)
+        self.submissionSetNS = RDF.NS(str(self.submissionSet) + '/')
+        self.libraryNS = RDF.NS('http://jumpgate.caltech.edu/library/')
+
+        self.__view_map = None
+
+    def scan_submission_dirs(self, result_map):
+        """Examine files in our result directory
+        """
+        for lib_id, result_dir in result_map.items():
+            logger.info("Importing %s from %s" % (lib_id, result_dir))
+            try:
+                self.import_analysis_dir(result_dir, lib_id)
+            except MetadataLookupException, e:
+                logger.error("Skipping %s: %s" % (lib_id, str(e)))
+
+    def import_analysis_dir(self, analysis_dir, library_id):
+        """Import a submission directories and update our model as needed
+        """
+        #attributes = get_filename_attribute_map(paired)
+        libNode = self.libraryNS[library_id + "/"]
+
+        self._add_library_details_to_model(libNode)
+
+        submission_files = os.listdir(analysis_dir)
+        for filename in submission_files:
+            self.construct_file_attributes(analysis_dir, libNode, filename)
+
+    def construct_file_attributes(self, analysis_dir, libNode, pathname):
+        """Looking for the best extension
+        The 'best' is the longest match
+
+        :Args:
+        filename (str): the filename whose extention we are about to examine
+        """
+        path, filename = os.path.split(pathname)
+
+        logger.debug("Searching for view")
+        file_classification = self.find_best_match(filename)
+        if file_classification is None:
+            logger.warn("Unrecognized file: {0}".format(pathname))
+            return None
+        if str(file_classification) == str(libraryOntology['ignore']):
+            return None
+
+        an_analysis_name = self.make_submission_name(analysis_dir)
+        an_analysis = self.get_submission_node(analysis_dir)
+        an_analysis_uri = str(an_analysis.uri)
+
+        self.model.add_statement(RDF.Statement(an_analysis,
+                                               submissionOntology['name'],
+                                               toTypedNode(an_analysis_name)))
+        self.model.add_statement(
+            RDF.Statement(an_analysis,
+                          rdfNS['type'],
+                          submissionOntology['submission']))
+        self.model.add_statement(RDF.Statement(an_analysis,
+                                               submissionOntology['library'],
+                                               libNode))
+
+        logger.debug("Adding statements to {0}".format(str(an_analysis)))
+        # add track specific information
+        self.model.add_statement(
+            RDF.Statement(an_analysis,
+                          dafTermOntology['paired'],
+                          toTypedNode(self._is_paired(libNode))))
+        self.model.add_statement(
+            RDF.Statement(an_analysis,
+                          dafTermOntology['submission'],
+                          an_analysis))
+
+        # add file specific information
+        fileNode = self.link_file_to_classes(filename,
+                                             an_analysis,
+                                             an_analysis_uri,
+                                             analysis_dir)
+        self.add_md5s(filename, fileNode, analysis_dir)
+
+        logger.debug("Done.")
+
+    def link_file_to_classes(self, filename, submissionNode, submission_uri, analysis_dir):
+        # add file specific information
+        fileNode = RDF.Node(RDF.Uri(submission_uri + '/' + filename))
+        self.model.add_statement(
+            RDF.Statement(submissionNode,
+                          dafTermOntology['has_file'],
+                          fileNode))
+        self.model.add_statement(
+            RDF.Statement(fileNode,
+                          dafTermOntology['filename'],
+                          filename))
+        return fileNode
+
+    def add_md5s(self, filename, fileNode, analysis_dir):
+        logger.debug("Updating file md5sum")
+        submission_pathname = os.path.join(analysis_dir, filename)
+        md5 = make_md5sum(submission_pathname)
+        if md5 is None:
+            errmsg = "Unable to produce md5sum for {0}"
+            logger.warning(errmsg.format(submission_pathname))
+        else:
+            self.model.add_statement(
+                RDF.Statement(fileNode, dafTermOntology['md5sum'], md5))
+
+    def _add_library_details_to_model(self, libNode):
+        parser = RDF.Parser(name='rdfa')
+        new_statements = parser.parse_as_stream(libNode.uri)
+        for s in new_statements:
+            # don't override things we already have in the model
+            targets = list(self.model.get_targets(s.subject, s.predicate))
+            if len(targets) == 0:
+                self.model.append(s)
+
+
+    def find_best_match(self, filename):
+        """Search through potential filename matching patterns
+        """
+        if self.__view_map is None:
+            self.__view_map = self._get_filename_view_map()
+
+        results = []
+        for pattern, view in self.__view_map.items():
+            if re.match(pattern, filename):
+                results.append(view)
+
+        if len(results) > 1:
+            msg = "%s matched multiple views %s" % (
+                filename,
+                [str(x) for x in results])
+            raise ModelException(msg)
+        elif len(results) == 1:
+            return results[0]
+        else:
+            return None
+
+    def _get_filename_view_map(self):
+        """Query our model for filename patterns
+
+        return a dictionary of compiled regular expressions to view names
+        """
+        filename_query = RDF.Statement(
+            None, dafTermOntology['filename_re'], None)
+
+        patterns = {}
+        for s in self.model.find_statements(filename_query):
+            view_name = s.subject
+            literal_re = s.object.literal_value['string']
+            logger.debug("Found: %s" % (literal_re,))
+            try:
+                filename_re = re.compile(literal_re)
+            except re.error, e:
+                logger.error("Unable to compile: %s" % (literal_re,))
+            patterns[literal_re] = view_name
+        return patterns
+
+    def make_submission_name(self, analysis_dir):
+        analysis_dir = os.path.normpath(analysis_dir)
+        analysis_dir_name = os.path.split(analysis_dir)[1]
+        if len(analysis_dir_name) == 0:
+            raise RuntimeError(
+                "Submission dir name too short: {0}".format(analysis_dir))
+        return analysis_dir_name
+
+    def get_submission_node(self, analysis_dir):
+        """Convert a submission directory name to a submission node
+        """
+        submission_name = self.make_submission_name(analysis_dir)
+        return self.submissionSetNS[submission_name]
+
+    def _get_library_attribute(self, libNode, attribute):
+        if not isinstance(attribute, RDF.Node):
+            attribute = libraryOntology[attribute]
+
+        targets = list(self.model.get_targets(libNode, attribute))
+        if len(targets) > 0:
+            return self._format_library_attribute(targets)
+        else:
+            return None
+
+        #targets = self._search_same_as(libNode, attribute)
+        #if targets is not None:
+        #    return self._format_library_attribute(targets)
+
+        # we don't know anything about this attribute
+        self._add_library_details_to_model(libNode)
+
+        targets = list(self.model.get_targets(libNode, attribute))
+        if len(targets) > 0:
+            return self._format_library_attribute(targets)
+
+        return None
+
+    def _format_library_attribute(self, targets):
+        if len(targets) == 0:
+            return None
+        elif len(targets) == 1:
+            return fromTypedNode(targets[0])
+        elif len(targets) > 1:
+            return [fromTypedNode(t) for t in targets]
+
+    def _is_paired(self, libNode):
+        """Determine if a library is paired end"""
+        library_type = self._get_library_attribute(libNode, 'library_type')
+        if library_type is None:
+            errmsg = "%s doesn't have a library type"
+            raise ModelException(errmsg % (str(libNode),))
+
+        single = ['CSHL (lacking last nt)',
+                  'Single End (non-multiplexed)',
+                  'Small RNA (non-multiplexed)',]
+        paired = ['Barcoded Illumina',
+                  'Multiplexing',
+                  'Nextera',
+                  'Paired End (non-multiplexed)',]
+        if library_type in single:
+            return False
+        elif library_type in paired:
+            return True
+        else:
+            raise MetadataLookupException(
+                "Unrecognized library type %s for %s" % \
+                (library_type, str(libNode)))
+
diff --git a/htsworkflow/submission/test/__init__.py b/htsworkflow/submission/test/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/htsworkflow/submission/test/test_condorfastq.py b/htsworkflow/submission/test/test_condorfastq.py
new file mode 100644 (file)
index 0000000..27b9997
--- /dev/null
@@ -0,0 +1,388 @@
+#!/usr/bin/env python
+
+import copy
+import os
+from pprint import pprint
+import shutil
+import tempfile
+import unittest
+
+from htsworkflow.submission import condorfastq
+from htsworkflow.submission.results import ResultMap
+
+FCDIRS = [
+    'C02F9ACXX',
+    'C02F9ACXX/C1-202',
+    'C02F9ACXX/C1-202/Project_11154',
+    'C02F9ACXX/C1-202/Project_12342_Index1',
+    'C02F9ACXX/C1-202/Project_12342_Index2',
+    '42JUYAAXX',
+    '42JUYAAXX/C1-76',
+    '30221AAXX',
+    '30221AAXX/C1-33',
+    '30DY0AAXX',
+    '30DY0AAXX/C1-151',
+    '61MJTAAXX',
+    '61MJTAAXX/C1-76',
+]
+
+DATAFILES = [
+    'C02F9ACXX/C1-202/Project_11154/11154_NoIndex_L003_R1_001.fastq.gz',
+    'C02F9ACXX/C1-202/Project_11154/11154_NoIndex_L003_R1_002.fastq.gz',
+    'C02F9ACXX/C1-202/Project_11154/11154_NoIndex_L003_R2_001.fastq.gz',
+    'C02F9ACXX/C1-202/Project_11154/11154_NoIndex_L003_R2_002.fastq.gz',
+    'C02F9ACXX/C1-202/Project_12342_Index1/11114_GCCAAT_L004_R1_001.fastq.gz',
+    'C02F9ACXX/C1-202/Project_12342_Index2/11119_CGATGT_L007_R1_001.fastq.gz',
+    'C02F9ACXX/C1-202/Project_12342_Index2/11119_CGATGT_L005_R1_001.fastq.gz',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l1_r1.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l2_r1.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l3_r1.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l4_r1.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l5_r1.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l6_r1.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l7_r1.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l8_r1.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l1_r2.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l1_r2.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l2_r2.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l3_r2.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l4_r2.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l5_r2.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l6_r2.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l7_r2.tar.bz2',
+    '42JUYAAXX/C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l8_r2.tar.bz2',
+    '30221AAXX/C1-33/woldlab_090425_HWI-EAS229_0110_30221AAXX_1.srf',
+    '30221AAXX/C1-33/woldlab_090425_HWI-EAS229_0110_30221AAXX_2.srf',
+    '30221AAXX/C1-33/woldlab_090425_HWI-EAS229_0110_30221AAXX_3.srf',
+    '30221AAXX/C1-33/woldlab_090425_HWI-EAS229_0110_30221AAXX_4.srf',
+    '30221AAXX/C1-33/woldlab_090425_HWI-EAS229_0110_30221AAXX_5.srf',
+    '30221AAXX/C1-33/woldlab_090425_HWI-EAS229_0110_30221AAXX_6.srf',
+    '30221AAXX/C1-33/woldlab_090425_HWI-EAS229_0110_30221AAXX_7.srf',
+    '30221AAXX/C1-33/woldlab_090425_HWI-EAS229_0110_30221AAXX_8.srf',
+    '30DY0AAXX/C1-151/woldlab_090725_HWI-EAS229_0110_30DY0AAXX_1.srf',
+    '30DY0AAXX/C1-151/woldlab_090725_HWI-EAS229_0110_30DY0AAXX_2.srf',
+    '30DY0AAXX/C1-151/woldlab_090725_HWI-EAS229_0110_30DY0AAXX_3.srf',
+    '30DY0AAXX/C1-151/woldlab_090725_HWI-EAS229_0110_30DY0AAXX_4.srf',
+    '30DY0AAXX/C1-151/woldlab_090725_HWI-EAS229_0110_30DY0AAXX_5.srf',
+    '30DY0AAXX/C1-151/woldlab_090725_HWI-EAS229_0110_30DY0AAXX_6.srf',
+    '30DY0AAXX/C1-151/woldlab_090725_HWI-EAS229_0110_30DY0AAXX_7.srf',
+    '30DY0AAXX/C1-151/woldlab_090725_HWI-EAS229_0110_30DY0AAXX_8.srf',
+    '61MJTAAXX/C1-76/woldlab_100826_HSI-123_0001_61MJTAAXX_l1_r1.tar.bz2',
+    '61MJTAAXX/C1-76/woldlab_100826_HSI-123_0001_61MJTAAXX_l2_r1.tar.bz2',
+    '61MJTAAXX/C1-76/woldlab_100826_HSI-123_0001_61MJTAAXX_l3_r1.tar.bz2',
+    '61MJTAAXX/C1-76/woldlab_100826_HSI-123_0001_61MJTAAXX_l4_r1.tar.bz2',
+    '61MJTAAXX/C1-76/woldlab_100826_HSI-123_0001_61MJTAAXX_l5_r1.tar.bz2',
+    '61MJTAAXX/C1-76/woldlab_100826_HSI-123_0001_61MJTAAXX_l6_r1.tar.bz2',
+    '61MJTAAXX/C1-76/woldlab_100826_HSI-123_0001_61MJTAAXX_l7_r1.tar.bz2',
+    '61MJTAAXX/C1-76/woldlab_100826_HSI-123_0001_61MJTAAXX_l8_r1.tar.bz2',
+]
+
+LIBDATA = {
+    '11154':{u'antibody_id': None,
+             u'cell_line': u'Unknown',
+             u'cell_line_id': 1,
+             u'experiment_type': u'RNA-seq',
+             u'experiment_type_id': 4,
+             u'gel_cut_size': 300,
+             u'hidden': False,
+             u'id': u'11154',
+             u'insert_size': 200,
+             u'lane_set': [{u'flowcell': u'30221AAXX',
+                            u'lane_number': 4,
+                            u'paired_end': False,
+                            u'read_length': 33,
+                            u'status': u'Unknown',
+                            u'status_code': None},
+                           {u'flowcell': u'42JUYAAXX',
+                            u'lane_number': 5,
+                            u'paired_end': True,
+                            u'read_length': 76,
+                            u'status': u'Unknown',
+                            u'status_code': None},
+                           {u'flowcell': u'61MJTAAXX',
+                            u'lane_number': 6,
+                            u'paired_end': False,
+                            u'read_length': 76,
+                            u'status': u'Unknown',
+                            u'status_code': None},
+                           {u'flowcell': u'30DY0AAXX',
+                            u'lane_number': 8,
+                            u'paired_end': True,
+                            u'read_length': 76,
+                            u'status': u'Unknown',
+                            u'status_code': None},
+                           {u'flowcell': u'C02F9ACXX',
+                            u'lane_number': 3,
+                            u'paired_end': True,
+                            u'read_length': 101,
+                            u'status': u'Unknown',
+                            u'status_code': None}],
+             u'library_id': u'11154',
+             u'library_name': u'Paired ends ASDF ',
+             u'library_species': u'Mus musculus',
+             u'library_species_id': 9,
+             u'library_type': u'Paired End (non-multiplexed)',
+             u'library_type_id': 2,
+             u'made_by': u'Gary Gygax',
+             u'made_for': u'TSR',
+             u'notes': u'300 bp gel fragment',
+             u'replicate': 1,
+             u'stopping_point': u'1Aa',
+             u'successful_pM': None,
+             u'undiluted_concentration': u'29.7'}
+    }
+
+FAKE_APIDATA = {'apiid':0, 'apikey': 'foo'}
+
+class FakeApi(object):
+    def __init__(self, *args, **kwargs):
+        pass
+
+    def get_library(self, libid):
+        lib_data = LIBDATA[libid]
+        return copy.deepcopy(lib_data)
+
+class TestCondorFastq(unittest.TestCase):
+    def setUp(self):
+        self.cwd = os.getcwd()
+
+        self.tempdir = tempfile.mkdtemp(prefix='condorfastq_test')
+        self.flowcelldir = os.path.join(self.tempdir, 'flowcells')
+        os.mkdir(self.flowcelldir)
+
+        self.logdir = os.path.join(self.tempdir, 'log')
+        os.mkdir(self.logdir)
+
+        for d in FCDIRS:
+            os.mkdir(os.path.join(self.flowcelldir, d))
+
+        for f in DATAFILES:
+            filename = os.path.join(self.flowcelldir, f)
+            with open(filename, 'w') as stream:
+                stream.write('testfile')
+
+        self.subname = unicode('sub-11154')
+        self.subdir = os.path.join(self.tempdir, self.subname)
+        os.mkdir(self.subdir)
+
+        self.result_map = ResultMap()
+        self.result_map.add_result('11154', self.subname)
+
+    def tearDown(self):
+        shutil.rmtree(self.tempdir)
+        os.chdir(self.cwd)
+
+    def test_find_archive_sequence(self):
+        extract = condorfastq.CondorFastqExtract('host',
+                                                 FAKE_APIDATA,
+                                                 self.tempdir,
+                                                 self.logdir)
+        extract.api = FakeApi()
+
+        lib_db = extract.find_archive_sequence_files(self.result_map)
+
+        self.failUnlessEqual(len(lib_db['11154']['lanes']), 5)
+        lanes = [
+            lib_db['11154']['lanes'][(u'30221AAXX', 4)],
+            lib_db['11154']['lanes'][(u'42JUYAAXX', 5)],
+            lib_db['11154']['lanes'][(u'61MJTAAXX', 6)],
+            lib_db['11154']['lanes'][(u'30DY0AAXX', 8)],
+            lib_db['11154']['lanes'][(u'C02F9ACXX', 3)],
+        ]
+        self.failUnlessEqual(len(lanes[0]), 1)
+        self.failUnlessEqual(len(lanes[1]), 2)
+        self.failUnlessEqual(len(lanes[2]), 1)
+        self.failUnlessEqual(len(lanes[3]), 1)
+        self.failUnlessEqual(len(lanes[4]), 4)
+
+    def test_find_needed_targets(self):
+
+        extract = condorfastq.CondorFastqExtract('host',
+                                                 FAKE_APIDATA,
+                                                 self.tempdir,
+                                                 self.logdir)
+        extract.api = FakeApi()
+        lib_db = extract.find_archive_sequence_files(self.result_map)
+
+        needed_targets = extract.find_missing_targets(self.result_map,
+                                                      lib_db)
+        self.failUnlessEqual(len(needed_targets), 7)
+        srf_30221 = needed_targets[
+            self.subname + u'/11154_30221AAXX_c33_l4.fastq']
+        qseq_42JUY_r1 = needed_targets[
+            self.subname + u'/11154_42JUYAAXX_c76_l5_r1.fastq']
+        qseq_42JUY_r2 = needed_targets[
+            self.subname + u'/11154_42JUYAAXX_c76_l5_r2.fastq']
+        qseq_61MJT = needed_targets[
+            self.subname + u'/11154_61MJTAAXX_c76_l6.fastq']
+        split_C02F9_r1 = needed_targets[
+            self.subname + u'/11154_C02F9ACXX_c202_l3_r1.fastq']
+        split_C02F9_r2 = needed_targets[
+            self.subname + u'/11154_C02F9ACXX_c202_l3_r2.fastq']
+
+        self.failUnlessEqual(len(srf_30221['srf']), 1)
+        self.failUnlessEqual(len(qseq_42JUY_r1['qseq']), 1)
+        self.failUnlessEqual(len(qseq_42JUY_r2['qseq']), 1)
+        self.failUnlessEqual(len(qseq_61MJT['qseq']), 1)
+        self.failUnlessEqual(len(split_C02F9_r1['split_fastq']), 2)
+        self.failUnlessEqual(len(split_C02F9_r2['split_fastq']), 2)
+
+        #print '-------needed targets---------'
+        #pprint(needed_targets)
+
+    def test_generate_fastqs(self):
+        extract = condorfastq.CondorFastqExtract('host',
+                                                 FAKE_APIDATA,
+                                                 self.tempdir,
+                                                 self.logdir)
+        extract.api = FakeApi()
+        commands = extract.build_condor_arguments(self.result_map)
+
+        srf = commands['srf']
+        qseq = commands['qseq']
+        split = commands['split_fastq']
+
+        self.failUnlessEqual(len(srf), 2)
+        self.failUnlessEqual(len(qseq), 3)
+        self.failUnlessEqual(len(split), 2)
+
+        srf_data = {
+            os.path.join(self.subname, '11154_30221AAXX_c33_l4.fastq'): {
+                'mid': None,
+                'ispaired': False,
+                'sources': [u'woldlab_090425_HWI-EAS229_0110_30221AAXX_4.srf'],
+                'flowcell': u'30221AAXX',
+                'target': os.path.join(self.subname,
+                                       u'11154_30221AAXX_c33_l4.fastq'),
+            },
+            os.path.join(self.subname, '11154_30DY0AAXX_c151_l8_r1.fastq'): {
+                'mid': None,
+                'ispaired': True,
+                'flowcell': u'30DY0AAXX',
+                'sources': [u'woldlab_090725_HWI-EAS229_0110_30DY0AAXX_8.srf'],
+                'mid': 76,
+                'target':
+                    os.path.join(self.subname,
+                                 u'11154_30DY0AAXX_c151_l8_r1.fastq'),
+                'target_right':
+                    os.path.join(self.subname,
+                                 u'11154_30DY0AAXX_c151_l8_r2.fastq'),
+            }
+        }
+        for args in srf:
+            expected = srf_data[args['target']]
+            self.failUnlessEqual(args['ispaired'], expected['ispaired'])
+            self.failUnlessEqual(len(args['sources']), 1)
+            _, source_filename = os.path.split(args['sources'][0])
+            self.failUnlessEqual(source_filename, expected['sources'][0])
+            self.failUnlessEqual(args['target'], expected['target'])
+            if args['ispaired']:
+                self.failUnlessEqual(args['target_right'],
+                                     expected['target_right'])
+            if 'mid' in expected:
+                self.failUnlessEqual(args['mid'], expected['mid'])
+
+        qseq_data = {
+            os.path.join(self.subname, '11154_42JUYAAXX_c76_l5_r1.fastq'): {
+                'istar': True,
+                'ispaired': True,
+                'sources': [
+                    u'woldlab_100826_HSI-123_0001_42JUYAAXX_l5_r1.tar.bz2']
+            },
+            os.path.join(self.subname, '11154_42JUYAAXX_c76_l5_r2.fastq'): {
+                'istar': True,
+                'ispaired': True,
+                'sources': [
+                    u'woldlab_100826_HSI-123_0001_42JUYAAXX_l5_r2.tar.bz2']
+            },
+            os.path.join(self.subname, '11154_61MJTAAXX_c76_l6.fastq'): {
+                'istar': True,
+                'ispaired': False,
+                'sources': [
+                    u'woldlab_100826_HSI-123_0001_61MJTAAXX_l6_r1.tar.bz2'],
+            },
+        }
+        for args in qseq:
+            expected = qseq_data[args['target']]
+            self.failUnlessEqual(args['istar'], expected['istar'])
+            self.failUnlessEqual(args['ispaired'], expected['ispaired'])
+            for i in range(len(expected['sources'])):
+                _, filename = os.path.split(args['sources'][i])
+                self.failUnlessEqual(filename, expected['sources'][i])
+
+
+        split_test = { x['target']: x for x in
+            [{'sources': [u'11154_NoIndex_L003_R1_001.fastq.gz',
+                         u'11154_NoIndex_L003_R1_002.fastq.gz'],
+             'pyscript': 'desplit_fastq.pyc',
+             'target': u'11154_C02F9ACXX_c202_l3_r1.fastq'},
+            {'sources': [u'11154_NoIndex_L003_R2_001.fastq.gz',
+                         u'11154_NoIndex_L003_R2_002.fastq.gz'],
+             'pyscript': 'desplit_fastq.pyc',
+             'target': u'11154_C02F9ACXX_c202_l3_r2.fastq'}]
+         }
+        for arg in split:
+            _, target = os.path.split(arg['target'])
+            pyscript = split_test[target]['pyscript']
+            self.failUnless(arg['pyscript'].endswith(pyscript))
+            filename = split_test[target]['target']
+            self.failUnless(arg['target'].endswith(filename))
+            for s_index in range(len(arg['sources'])):
+                s1 = arg['sources'][s_index]
+                s2 = split_test[target]['sources'][s_index]
+                self.failUnless(s1.endswith(s2))
+
+        #print '-------commands---------'
+        #pprint (commands)
+
+    def test_create_scripts(self):
+        os.chdir(self.tempdir)
+        extract = condorfastq.CondorFastqExtract('host',
+                                                 FAKE_APIDATA,
+                                                 self.tempdir,
+                                                 self.logdir)
+        extract.api = FakeApi()
+        extract.create_scripts(self.result_map)
+
+        self.failUnless(os.path.exists('srf.condor'))
+        with open('srf.condor', 'r') as srf:
+            arguments = [ l for l in srf if l.startswith('argument') ]
+            arguments.sort()
+            self.failUnlessEqual(len(arguments), 2)
+            self.failUnless('--single sub-11154/11154_30221AAXX_c33_l4.fastq'
+                            in arguments[0])
+            self.failUnless(
+                '--right sub-11154/11154_30DY0AAXX_c151_l8_r2.fastq' in
+                arguments[1])
+
+        self.failUnless(os.path.exists('qseq.condor'))
+        with open('qseq.condor', 'r') as srf:
+            arguments = [ l for l in srf if l.startswith('argument') ]
+            arguments.sort()
+            self.failUnlessEqual(len(arguments), 3)
+            self.failUnless('-o sub-11154/11154_42JUYAAXX_c76_l5_r1.fastq ' in
+                            arguments[0])
+            self.failUnless(
+                'C1-76/woldlab_100826_HSI-123_0001_42JUYAAXX_l5_r2.tar.bz2' in
+                arguments[1])
+            self.failUnless('61MJTAAXX_c76_l6.fastq -f 61MJTAAXX' in
+                            arguments[2])
+
+        self.failUnless(os.path.exists('split_fastq.condor'))
+        with open('split_fastq.condor', 'r') as split:
+            arguments = [ l for l in split if l.startswith('argument') ]
+            arguments.sort()
+            self.failUnlessEqual(len(arguments), 2)
+            self.failUnless('11154_NoIndex_L003_R1_001.fastq.gz' in \
+                            arguments[0])
+            self.failUnless('11154_NoIndex_L003_R2_002.fastq.gz' in \
+                            arguments[1])
+
+
+def suite():
+    suite = unittest.makeSuite(TestCondorFastq, 'test')
+    return suite
+
+if __name__ == "__main__":
+    unittest.main(defaultTest='suite')
+
index b730144d227af3a1bf7fc6b73783ede6a7f3a1ff..334a71a9203e7ca5d621b634a62bfc9b5fd299a6 100644 (file)
@@ -5,7 +5,7 @@ import shutil
 import tempfile
 import unittest
 
-from htsworkflow.submission import daf
+from htsworkflow.submission import daf, results
 from htsworkflow.util.rdfhelp import \
      dafTermOntology, \
      fromTypedNode, \
@@ -15,6 +15,7 @@ from htsworkflow.util.rdfhelp import \
      get_model, \
      get_serializer
 
+from htsworkflow.submission.test import test_results
 import RDF
 
 test_daf = """# Lab and general info
@@ -155,7 +156,7 @@ def load_daf_mapper(name, extra_statements=None, ns=None, test_daf=test_daf):
                                        ns)
 
     test_daf_stream = StringIO(test_daf)
-    mapper = daf.DAFMapper(name, daf_file = test_daf_stream, model=model)
+    mapper = daf.UCSCSubmission(name, daf_file = test_daf_stream, model=model)
     return mapper
 
 def dump_model(model):
@@ -164,7 +165,14 @@ def dump_model(model):
     print turtle
 
 
-class TestDAFMapper(unittest.TestCase):
+class TestUCSCSubmission(unittest.TestCase):
+    def setUp(self):
+        test_results.generate_sample_results_tree(self)
+
+    def tearDown(self):
+        # see things created by temp_results.generate_sample_results_tree
+        shutil.rmtree(self.tempdir)
+
     def test_create_mapper_add_pattern(self):
         name = 'testsub'
         mapper = load_daf_mapper(name)
@@ -287,6 +295,26 @@ thisView:FastqRd1 dafTerm:filename_re ".*\\\\.fastq" ;
         self.failUnless('controlId' in variables)
 
 
+    def test_link_daf(self):
+        name = 'testsub'
+        submission = load_daf_mapper(name, test_daf=test_daf)
+        result_map = results.ResultMap()
+        result_dir = os.path.join(self.sourcedir,
+                                  test_results.S1_NAME)
+        result_map.add_result('1000', result_dir)
+
+        submission.link_daf(result_map)
+
+        # make sure daf gets linked
+        created_daf = os.path.join(result_dir, name+'.daf')
+        self.failUnless(os.path.exists(created_daf))
+        stream = open(created_daf,'r')
+        daf_body = stream.read()
+        stream.close()
+
+        self.failUnlessEqual(test_daf, daf_body)
+
+
 @contextmanager
 def mktempdir(prefix='tmp'):
     d = tempfile.mkdtemp(prefix=prefix)
@@ -304,7 +332,7 @@ def mktempfile(suffix='', prefix='tmp', dir=None):
 
 def suite():
     suite = unittest.makeSuite(TestDAF, 'test')
-    suite.addTest(unittest.makeSuite(TestDAFMapper, 'test'))
+    suite.addTest(unittest.makeSuite(TestUCSCSubmission, 'test'))
     return suite
 
 if __name__ == "__main__":
diff --git a/htsworkflow/submission/test/test_results.py b/htsworkflow/submission/test/test_results.py
new file mode 100644 (file)
index 0000000..8579c58
--- /dev/null
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+import copy
+import os
+from pprint import pprint
+import shutil
+import tempfile
+import unittest
+
+from htsworkflow.submission.results import ResultMap
+
+S1_NAME = '1000-sample'
+S2_NAME = '2000-sample'
+
+S1_FILES = [
+    os.path.join(S1_NAME, 'file1_l8_r1.fastq'),
+    os.path.join(S1_NAME, 'file1_l8_r2.fastq'),
+]
+
+S2_FILES = [
+    os.path.join(S2_NAME, 'file1.bam'),
+    os.path.join(S2_NAME, 'file1_l5.fastq'),
+]
+
+def generate_sample_results_tree(obj):
+    obj.tempdir = tempfile.mkdtemp(prefix="results_test")
+    obj.sourcedir = os.path.join(obj.tempdir, 'source')
+    obj.resultdir = os.path.join(obj.tempdir, 'results')
+
+    for d in [obj.sourcedir,
+              os.path.join(obj.sourcedir, S1_NAME),
+              os.path.join(obj.sourcedir, S2_NAME),
+              obj.resultdir]:
+        os.mkdir(os.path.join(obj.tempdir, d))
+
+    tomake = []
+    tomake.extend(S1_FILES)
+    tomake.extend(S2_FILES)
+    for f in tomake:
+        stream = open(os.path.join(obj.sourcedir, f), 'w')
+        stream.write(f)
+        stream.close()
+
+class TestResultMap(unittest.TestCase):
+    def setUp(self):
+        generate_sample_results_tree(self)
+
+    def tearDown(self):
+        shutil.rmtree(self.tempdir)
+
+
+    def test_dict_like(self):
+        """Make sure the result map works like an ordered dictionary
+        """
+        results = ResultMap()
+        results.add_result('1000', 'dir1000')
+        results.add_result('2000', 'dir2000')
+        results.add_result('1500', 'dir1500')
+
+        self.failUnlessEqual(results.keys(), ['1000', '2000', '1500'])
+        self.failUnlessEqual(list(results.values()),
+                             ['dir1000', 'dir2000', 'dir1500'])
+        self.failUnlessEqual(list(results.items()),
+                             [('1000', 'dir1000'),
+                              ('2000', 'dir2000'),
+                              ('1500', 'dir1500')])
+
+        self.failUnlessEqual(results['1000'], 'dir1000')
+        self.failUnlessEqual(results['1500'], 'dir1500')
+        self.failUnlessEqual(results['2000'], 'dir2000')
+
+    def test_make_from(self):
+        results = ResultMap()
+        results.add_result('1000', S1_NAME)
+        results.add_result('2000', S2_NAME)
+
+        results.make_tree_from(self.sourcedir, self.resultdir)
+
+        sample1_dir = os.path.join(self.resultdir, S1_NAME)
+        sample2_dir = os.path.join(self.resultdir, S2_NAME)
+        self.failUnless(os.path.isdir(sample1_dir))
+        self.failUnless(os.path.isdir(sample2_dir))
+
+        for f in S1_FILES + S2_FILES:
+            self.failUnless(
+                os.path.islink(
+                    os.path.join(self.resultdir, f)))
+
+
+
+
+def suite():
+    suite = unittest.makeSuite(TestResultMap, 'test')
+    return suite
+
+if __name__ == "__main__":
+    unittest.main(defaultTest='suite')
+
index a003594310069b5108073890abe1d99ec409f2bf..53ac287a5f0b876eb18df0638277493e7e106604 100644 (file)
@@ -12,7 +12,7 @@ wgEncodeCaltechRnaSeqGm12878R2x75Il200FastqRd2Rep1.fastq.tgz  project=wgEncode; g
 class TestUCSCInfo(unittest.TestCase):
     def test_parse_encodedcc_file(self):
         stream = StringIO(ENCODE_FILES)
-        file_index = ucsc.parse_ucsc_file_index(stream)
+        file_index = ucsc.parse_ucsc_file_index(stream, 'http://example.com/files')
         self.assertEquals(len(file_index), 2)
 
         for attributes in file_index.values():
index 9181830e34983724e586a906a7194d96fc9507eb..f7734adbd972b26db9150b155a7cdeb39818e0c1 100644 (file)
@@ -1,10 +1,18 @@
 """Utilities for extracting information from the ENCODE DCC
 """
+import logging
 import urlparse
 import urllib2
 
+LOGGER = logging.getLogger(__name__)
+
 UCSCEncodePipeline = "http://encodesubmit.ucsc.edu/pipeline/"
 
+GOLDEN_PATHS = ["http://hgdownload-test.cse.ucsc.edu/goldenPath/"\
+                "{genome}/encodeDCC/{composite}/",
+                "http://hgdownload.cse.ucsc.edu/goldenPath/"\
+                "{genome}/encodeDCC/{composite}/"]
+
 
 def ddf_download_url(submission_id):
     """Return url to download a DDF for a submission
@@ -36,21 +44,41 @@ def submission_view_url(submission_id):
     return urlparse.urljoin(UCSCEncodePipeline, fragment)
 
 
-def get_ucsc_file_index(base_url):
+def get_encodedcc_file_index(genome, composite):
     """Get index of files for a ENCODE collection
+
+    returns None on error
     """
-    if base_url[-1] != '/': base_url += '/'
-    request = urllib2.urlopen(base_url + 'files.txt')
-    file_index = parse_ucsc_file_index(request)
-    return file_index
+    err = None
+    params = {'genome': genome,
+              'composite': composite}
+
+    for path in GOLDEN_PATHS:
+        base_url = path.format(**params)
+        request_url = base_url + 'files.txt'
+
+        try:
+            request = urllib2.urlopen(request_url)
+            file_index = parse_ucsc_file_index(request, base_url)
+            return file_index
+        except urllib2.HTTPError, e:
+            err = e
+            pass
+
+    if err is not None:
+        errmsg = "get_ucsc_file_index <{0}>: {1}"
+        LOGGER.error(errmsg.format(request_url, str(e)))
+
+    return None
 
 
-def parse_ucsc_file_index(stream):
+def parse_ucsc_file_index(stream, base_url):
     """Turn a UCSC DCC files.txt index into a dictionary of name-value pairs
     """
     file_index = {}
     for line in stream:
         filename, attribute_line = line.split('\t')
+        filename = base_url + filename
         attributes = {}
         for assignment in  attribute_line.split(';'):
             name, value = assignment.split('=')
diff --git a/htsworkflow/templates/__init__.py b/htsworkflow/templates/__init__.py
new file mode 100644 (file)
index 0000000..4ae7b90
--- /dev/null
@@ -0,0 +1,5 @@
+"""Directory for not web templates.
+"""
+# Since my dependency on Django is pretty strong I thought
+# maybe I should use the django templating language for 
+# generating my condor scripts.
diff --git a/htsworkflow/templates/geo_submission.soft b/htsworkflow/templates/geo_submission.soft
new file mode 100644 (file)
index 0000000..ae2ac57
--- /dev/null
@@ -0,0 +1,11 @@
+Soft template
+!Platform_title = Illumina Genome Analyzer (Homo sapiens)
+!Platform_geo_accession = GPL9052
+{% for sample in samples %}{% for row in sample %}{%if forloop.first %}
+^SAMPLE={{row.name}}
+!Sample_title={{row.name}}
+!Sample_organism_ch1 = {{ row.species_name }}
+!Sample_taxid_ch1 = {{ row.taxon_id }}
+{% spaceless %}{% if row.cell %}!Sample_characteristics_ch1 = cell: {{ row.cell }}
+{% endif %}{% endspaceless %}{% endif %}
+!Sample_supplementary_file_{{forloop.counter}}={{row.filename}}{% endfor %}{% endfor %}
\ No newline at end of file
diff --git a/htsworkflow/templates/geo_submission.sparql b/htsworkflow/templates/geo_submission.sparql
new file mode 100644 (file)
index 0000000..1d7cbb1
--- /dev/null
@@ -0,0 +1,33 @@
+PREFIX libraryOntology: <http://jumpgate.caltech.edu/wiki/LibraryOntology#>
+PREFIX submissionOntology: <http://jumpgate.caltech.edu/wiki/UcscSubmissionOntology#>
+PREFIX ucscDaf: <http://jumpgate.caltech.edu/wiki/UcscDaf#>
+PREFIX ncbiTaxon: <http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id=>
+
+select distinct ?name ?filename ?md5sum ?cell ?antibody ?sex ?control ?strain ?controlId ?labExpId ?labVersion ?treatment ?protocol ?readType ?insertLength ?replicate, ?mapAlgorithm ?species_name ?taxon_id
+WHERE {
+  <{{submission}}> a submissionOntology:submission .
+
+  OPTIONAL { ?submission ucscDaf:control ?control }
+  #OPTIONAL { ?submission ucscDaf:controlId ?controlId }
+  #OPTIONAL { ?library libraryOntology:antibody ?antibody }
+  OPTIONAL { ?library libraryOntology:cell_line ?cell } .
+  #OPTIONAL { ?library ucscDaf:sex ?sex }
+  OPTIONAL { ?library libraryOntology:library_id ?labExpId }
+  OPTIONAL { ?library libraryOntology:library_id ?labVersion }
+  OPTIONAL { ?library libraryOntology:replicate ?replicate }
+  OPTIONAL { ?library libraryOntology:species ?species_name }
+  
+  #OPTIONAL { ?library libraryOntology:condition_term ?treatment }
+  #OPTIONAL { ?library ucscDaf:protocol ?protocol }
+  #OPTIONAL { ?library ucscDaf:readType ?readType }
+  #OPTIONAL { ?library ucscDaf:strain ?strain }
+  #OPTIONAL { ?library libraryOntology:insert_size ?insertLength }
+  #OPTIONAL { ?library ucscDaf:mapAlgorithm ?mapAlgorithm }
+
+  <{{submission}}> submissionOntology:library ?library ;
+                   ucscDaf:has_file ?file ;
+                   submissionOntology:name ?name .
+  ?species libraryOntology:species ?species_name ;
+           libraryOntology:taxon_id ?taxon_id .
+  ?file ucscDaf:filename ?filename .
+}
diff --git a/htsworkflow/templates/qseq.condor b/htsworkflow/templates/qseq.condor
new file mode 100644 (file)
index 0000000..fcdac83
--- /dev/null
@@ -0,0 +1,11 @@
+Universe=vanilla
+executable={{ exe }}
+error={{ logdir }}/fastq.$(process).out
+output={{ logdir }}/fastq.$(process).out
+log={{ logdir }}/fastq.log
+{% if env %}environment={{ env }}{% endif %}
+
+{% for arg in args %}
+arguments="{{ arg.pyscript }} -o {{ arg.target }} {% if arg.flowcell %}-f {{ arg.flowcell }}{% endif %} {% if arg.istar %}-i{% endif %} {% for s in arg.sources %}{{ s }} {% endfor %}"
+queue
+{% endfor %}
diff --git a/htsworkflow/templates/split_fastq.condor b/htsworkflow/templates/split_fastq.condor
new file mode 100644 (file)
index 0000000..3ea0350
--- /dev/null
@@ -0,0 +1,11 @@
+Universe=vanilla
+executable={{ exe }}
+error={{ logdir }}/fastq.$(process).out
+output={{ logdir }}/fastq.$(process).out
+log={{ logdir }}/fastq.log
+{% if env %}environment={{ env }}{% endif %}
+
+{% for arg in args %}
+arguments="{{ arg.pyscript }} -o {{ arg.target }} {% for s in arg.sources %}{{ s }} {% endfor %}
+queue
+{% endfor %}
diff --git a/htsworkflow/templates/srf.condor b/htsworkflow/templates/srf.condor
new file mode 100644 (file)
index 0000000..21d5232
--- /dev/null
@@ -0,0 +1,11 @@
+Universe=vanilla
+executable={{ exe }}
+error={{ logdir }}/fastq.$(process).out
+output={{ logdir }}/fastq.$(process).out
+log={{ logdir }}/fastq.log
+{% if env %}environment={{ env }}{% endif %}
+
+{% for arg in args %}
+arguments="{{ arg.pyscript }}  {{ arg.sources.0 }} --verbose {% if arg.flowcell %}-f {{ arg.flowcell }}{% endif %} {% if arg.ispaired %}--left {{ arg.target }} --right {{ arg.target_right }}{% else %}--single {{ arg.target }}{% endif %}"
+queue
+{% endfor %}
index 4c4a6e5c3dc156b49dea72e751e390d8a8435249..6ac2bb28c4f57b9732426a88bcd76a4564276d21 100644 (file)
@@ -47,12 +47,16 @@ def add_auth_options(parser):
     group.add_option('--sequence', default=sequence_archive,
                      help="sequence repository")
     parser.add_option_group(group)
+    return parser
 
-def make_auth_from_opts(opts, parser):
+def make_auth_from_opts(opts, parser=None):
     """Create htsw auth info dictionary from optparse info
     """
     if opts.host is None or opts.apiid is None or opts.apikey is None:
-        parser.error("Please specify host url, apiid, apikey")
+        if parser is not None:
+            parser.error("Please specify host url, apiid, apikey")
+        else:
+            raise RuntimeError("Need host, api id api key")
 
     return {'apiid': opts.apiid, 'apikey': opts.apikey }
 
@@ -158,3 +162,21 @@ class HtswApi(object):
   def get_url(self, url):
     return retrieve_info(url, self.authdata)
 
+if __name__ == "__main__":
+    from optparse import OptionParser
+    from pprint import pprint
+    parser = OptionParser()
+    parser = add_auth_options(parser)
+    parser.add_option('--flowcell', default=None)
+    parser.add_option('--library', default=None)
+
+    opts, args = parser.parse_args()
+    apidata =  make_auth_from_opts(opts)
+
+    api = HtswApi(opts.host, apidata)
+
+    if opts.flowcell is not None:
+        pprint(api.get_flowcell(opts.flowcell))
+    if opts.library is not None:
+        pprint(api.get_library(opts.library))
+
index 18cabef485aaedeafc7f0f1d16761c7c5937b6ea..d3eb4f6cc5dad43f619ca8db662ed6abbcc402a2 100644 (file)
@@ -14,7 +14,7 @@ def unicode_or_none(value):
 def parse_flowcell_id(flowcell_id):
     """
     Return flowcell id and any status encoded in the id
-  
+
     We stored the status information in the flowcell id name.
     this was dumb, but database schemas are hard to update.
     """
@@ -26,4 +26,19 @@ def parse_flowcell_id(flowcell_id):
     if len(fields) > 1:
         status = fields[1]
     return fcid, status
-    
+
+def parse_slice(slice_text):
+    if slice_text is None or len(slice_text) == 0:
+        return slice(None)
+
+    slice_data = []
+    for element in slice_text.split(':'):
+        if len(element) == 0:
+            element = None
+        else:
+            element = int(element)
+        slice_data.append(element)
+
+    return slice(*slice_data)
+
+
index 3b2bfe0ce3ccafacde089eabf34b2d03c5844356..1f9ec6179f2f933d1b52a1afefd7cdbe2e873537 100644 (file)
@@ -33,6 +33,9 @@ def sparql_query(model, query_filename):
     query_body = open(query_filename,'r').read()
     query = RDF.SPARQLQuery(query_body)
     results = query.execute(model)
+    display_query_results(results)
+
+def display_query_results(results):
     for row in results:
         output = []
         for k,v in row.items()[::-1]:
@@ -98,6 +101,8 @@ def fromTypedNode(node):
             return False
         else:
             raise ValueError("Unrecognized boolean %s" % (literal,))
+    elif value_type == 'integer':
+        return int(literal)
     elif value_type == 'decimal' and literal.find('.') == -1:
         return int(literal)
     elif value_type in ('decimal', 'float', 'double'):
diff --git a/htsworkflow/util/test/test_conversion.py b/htsworkflow/util/test/test_conversion.py
new file mode 100644 (file)
index 0000000..9100625
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+
+import unittest
+
+from htsworkflow.util import conversion
+
+class TestConversion(unittest.TestCase):
+    def test_parse_slice(self):
+        s = conversion.parse_slice("1:")
+        self.failUnlessEqual(s.start, 1)
+        self.failUnlessEqual(s.stop, None)
+
+        s = conversion.parse_slice("0:2")
+        self.failUnlessEqual(s.start, 0)
+        self.failUnlessEqual(s.stop, 2)
+
+def suite():
+    return unittest.makeSuite(TestConversion, 'test')
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="suite")
+
index 53bceeff47e920b5e9ddf2696272f7a17d2ec139..e0b993776e7f52d4f0d0ebc9aa1a7f5feceb2dbe 100755 (executable)
@@ -174,9 +174,9 @@ def make_parser():
                       help='create srf files tagged with the provided '\
                       'site name')
     parser.add_option('--raw-format', dest="raw_format", default='qseq',
-                      choices=['qseq', 'srf'],
+                      choices=['qseq', 'srf', 'fastq'],
                       help='Specify which type of raw format to use. '
-                           'Currently supported options: qseq, srf')
+                           'Currently supported options: qseq, srf, fastq')
     parser.add_option('-u', '--use-run', dest='use_run', default=None,
                       help='Specify which run to use instead of autoscanning '
                            'the runfolder. You do this by providing the final '
index 0cf33f3c0d886d84efc26cd0592ed2d1a4b0441b..aeabc57ff20189d716746de5f1afa7d8494f51eb 100755 (executable)
@@ -36,8 +36,12 @@ def build_flowcell_db(fcdb_filename, sequences, baseurl, apiid, apikey):
 
         # make library id db
         if flowcell_info is not None:
-            seq_library_id = flowcell_info['lane_set'][unicode(seq.lane)]['library_id']
-            libdb.setdefault(seq_library_id, []).append(seq)
+            lane_collection = flowcell_info['lane_set'][unicode(seq.lane)]
+            if type(lane_collection) != type([]):
+                lane_collection = [lane_collection]
+            for sample in lane_collection:
+                seq_library_id = sample['library_id']
+                libdb.setdefault(seq_library_id, []).append(seq)
 
     fcdb.sync()
     return fcdb, libdb
diff --git a/templates/config_form.html b/templates/config_form.html
deleted file mode 100644 (file)
index 3fbbbee..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<html>
-  <head>
-    <title>Test Config Form</title>
-    <!--
-    <link rel="stylesheet" type="text/css" href="ext-all.css"/>
-    <script type="text/javascript" src="ext.js"></script>
-    <script type="text/javascript" src="elandifier.js"></script>
-    -->
-  </head>
-  <body>
-    <form method="post" action="">
-     <table>{{ form.as_custom }}</table>
-     <input type="submit" />
-   </form>    
-  </body>
-</html>
-  
\ No newline at end of file