extensions/net.sf.basedb.reggie/trunk/src/net/sf/basedb/reggie/grid/ImportFastqJobCreator.java

Code
Comments
Other
Rev Date Author Line
6182 25 Mar 21 nicklas 1 package net.sf.basedb.reggie.grid;
6182 25 Mar 21 nicklas 2
7051 17 Feb 23 nicklas 3 import java.net.URI;
6182 25 Mar 21 nicklas 4 import java.util.ArrayList;
6182 25 Mar 21 nicklas 5 import java.util.List;
6182 25 Mar 21 nicklas 6 import java.util.regex.Matcher;
6182 25 Mar 21 nicklas 7 import java.util.regex.Pattern;
6182 25 Mar 21 nicklas 8
6182 25 Mar 21 nicklas 9 import net.sf.basedb.core.DataFileType;
6182 25 Mar 21 nicklas 10 import net.sf.basedb.core.DbControl;
6182 25 Mar 21 nicklas 11 import net.sf.basedb.core.DerivedBioAssay;
6182 25 Mar 21 nicklas 12 import net.sf.basedb.core.Directory;
6182 25 Mar 21 nicklas 13 import net.sf.basedb.core.File;
6182 25 Mar 21 nicklas 14 import net.sf.basedb.core.FileServer;
6182 25 Mar 21 nicklas 15 import net.sf.basedb.core.FileSetMember;
6209 13 Apr 21 nicklas 16 import net.sf.basedb.core.InvalidDataException;
6182 25 Mar 21 nicklas 17 import net.sf.basedb.core.ItemList;
6182 25 Mar 21 nicklas 18 import net.sf.basedb.core.ItemNotFoundException;
6182 25 Mar 21 nicklas 19 import net.sf.basedb.core.ItemSubtype;
6182 25 Mar 21 nicklas 20 import net.sf.basedb.core.Job;
6182 25 Mar 21 nicklas 21 import net.sf.basedb.core.Path;
6182 25 Mar 21 nicklas 22 import net.sf.basedb.core.Protocol;
6182 25 Mar 21 nicklas 23 import net.sf.basedb.core.SessionControl;
6182 25 Mar 21 nicklas 24 import net.sf.basedb.core.Software;
6182 25 Mar 21 nicklas 25 import net.sf.basedb.core.StringParameterType;
6182 25 Mar 21 nicklas 26 import net.sf.basedb.opengrid.JobDefinition;
6182 25 Mar 21 nicklas 27 import net.sf.basedb.opengrid.JobStatus;
6182 25 Mar 21 nicklas 28 import net.sf.basedb.opengrid.OpenGridCluster;
6182 25 Mar 21 nicklas 29 import net.sf.basedb.opengrid.OpenGridSession;
6182 25 Mar 21 nicklas 30 import net.sf.basedb.opengrid.ScriptBuilder;
6182 25 Mar 21 nicklas 31 import net.sf.basedb.opengrid.config.ClusterConfig;
6182 25 Mar 21 nicklas 32 import net.sf.basedb.opengrid.config.JobConfig;
6182 25 Mar 21 nicklas 33 import net.sf.basedb.opengrid.service.JobCompletionHandler;
6182 25 Mar 21 nicklas 34 import net.sf.basedb.reggie.Reggie;
6182 25 Mar 21 nicklas 35 import net.sf.basedb.reggie.XmlConfig;
6182 25 Mar 21 nicklas 36 import net.sf.basedb.reggie.dao.Annotationtype;
6182 25 Mar 21 nicklas 37 import net.sf.basedb.reggie.dao.BiomaterialList;
6182 25 Mar 21 nicklas 38 import net.sf.basedb.reggie.dao.Datafiletype;
6209 13 Apr 21 nicklas 39 import net.sf.basedb.reggie.dao.DemuxedSequences;
6215 16 Apr 21 nicklas 40 import net.sf.basedb.reggie.dao.DoNotUse;
6182 25 Mar 21 nicklas 41 import net.sf.basedb.reggie.dao.Fileserver;
6182 25 Mar 21 nicklas 42 import net.sf.basedb.reggie.dao.Library;
6182 25 Mar 21 nicklas 43 import net.sf.basedb.reggie.dao.MergedSequences;
6182 25 Mar 21 nicklas 44 import net.sf.basedb.reggie.dao.Pipeline;
6182 25 Mar 21 nicklas 45 import net.sf.basedb.reggie.dao.Subtype;
6182 25 Mar 21 nicklas 46 import net.sf.basedb.util.Values;
7051 17 Feb 23 nicklas 47 import net.sf.basedb.util.uri.UriMetadata;
6182 25 Mar 21 nicklas 48
6182 25 Mar 21 nicklas 49 /**
6182 25 Mar 21 nicklas 50   Helper class for creating items needed for importing
6182 25 Mar 21 nicklas 51   FASTQ files as well as generating the script and send it to the cluster for
6182 25 Mar 21 nicklas 52   execution.
6182 25 Mar 21 nicklas 53   
6182 25 Mar 21 nicklas 54   @author nicklas
6182 25 Mar 21 nicklas 55   @since 4.32
6182 25 Mar 21 nicklas 56 */
6182 25 Mar 21 nicklas 57 public class ImportFastqJobCreator 
6674 11 Apr 22 nicklas 58   extends AbstractJobCreator
6182 25 Mar 21 nicklas 59 {
6182 25 Mar 21 nicklas 60   private Software mergeSoftware;
6182 25 Mar 21 nicklas 61   private Protocol mergeProtocol;
6182 25 Mar 21 nicklas 62
6182 25 Mar 21 nicklas 63   public ImportFastqJobCreator()
6182 25 Mar 21 nicklas 64   {}
6182 25 Mar 21 nicklas 65
6182 25 Mar 21 nicklas 66   /**
6182 25 Mar 21 nicklas 67     Set the software item to set on created MergedSequences.
6182 25 Mar 21 nicklas 68     @see DerivedBioAssay#setSoftware(Software)
6182 25 Mar 21 nicklas 69   */
6182 25 Mar 21 nicklas 70   public void setMergeSoftware(Software software)
6182 25 Mar 21 nicklas 71   {
6182 25 Mar 21 nicklas 72     this.mergeSoftware = software;
6182 25 Mar 21 nicklas 73   }
6182 25 Mar 21 nicklas 74   
6182 25 Mar 21 nicklas 75   /**
6182 25 Mar 21 nicklas 76     Set the protocol item to set on created MergedSequences.
6182 25 Mar 21 nicklas 77     @see DerivedBioAssay#setProtocol(Protocol)
6182 25 Mar 21 nicklas 78   */
6182 25 Mar 21 nicklas 79   public void setMergeProtocol(Protocol protocol)
6182 25 Mar 21 nicklas 80   {
6182 25 Mar 21 nicklas 81     this.mergeProtocol = protocol;
6182 25 Mar 21 nicklas 82   }
6182 25 Mar 21 nicklas 83
6182 25 Mar 21 nicklas 84   /**
6215 16 Apr 21 nicklas 85     Create a child bioassays for all given demuxed sequences and schedule
6215 16 Apr 21 nicklas 86     jobs on the given cluster for importing FASTQ files.
6182 25 Mar 21 nicklas 87     @return A list with the corresponding jobs in BASE
6182 25 Mar 21 nicklas 88   */
6209 13 Apr 21 nicklas 89   @SuppressWarnings("unchecked")
6215 16 Apr 21 nicklas 90   public List<JobDefinition> createFastqImportJobs(DbControl dc, OpenGridCluster cluster, List<DemuxedSequences> demuxedSequences)
6182 25 Mar 21 nicklas 91   {
6182 25 Mar 21 nicklas 92     SessionControl sc = dc.getSessionControl();
6182 25 Mar 21 nicklas 93
6182 25 Mar 21 nicklas 94     String mergeParameterSet = (String)Annotationtype.PARAMETER_SET.getAnnotationValue(dc, mergeSoftware);
6182 25 Mar 21 nicklas 95
6182 25 Mar 21 nicklas 96     ClusterConfig clusterCfg = cluster.getConfig();
6182 25 Mar 21 nicklas 97     XmlConfig cfg = Reggie.getConfig(cluster.getId());
6182 25 Mar 21 nicklas 98     if (cfg == null)
6182 25 Mar 21 nicklas 99     {
6182 25 Mar 21 nicklas 100       throw new ItemNotFoundException("No configuration in reggie-config.xml for cluster: " + cluster.getId());
6182 25 Mar 21 nicklas 101     }
6182 25 Mar 21 nicklas 102     
6182 25 Mar 21 nicklas 103     // Get global options
6693 22 Apr 22 nicklas 104     String global_env = ScriptUtil.multilineIndent(cfg.getConfig("global-env"));
6658 31 Mar 22 nicklas 105     String projectArchive = cfg.getRequiredConfig("project-archive", null);
6658 31 Mar 22 nicklas 106     String externalArchive = cfg.getConfig("external-archive", null, projectArchive);
6182 25 Mar 21 nicklas 107
6182 25 Mar 21 nicklas 108     // Options for the programs
7372 06 Oct 23 nicklas 109     String import_submit = cfg.getConfig("ascat/submit-import", mergeParameterSet, null);
7372 06 Oct 23 nicklas 110     String import_submit_debug = cfg.getConfig("ascat/submit-import-debug", mergeParameterSet, null);
6658 31 Mar 22 nicklas 111     String demux_env = ScriptUtil.multilineIndent(cfg.getRequiredConfig("demux/env", mergeParameterSet));
6658 31 Mar 22 nicklas 112     String import_env = ScriptUtil.multilineIndent(cfg.getRequiredConfig("demux/env-import", mergeParameterSet));
6658 31 Mar 22 nicklas 113     String import_envdebug = ScriptUtil.multilineIndent(cfg.getConfig("demux/env-import-debug", mergeParameterSet, null));
6658 31 Mar 22 nicklas 114     String import_execute = ScriptUtil.multilineIndent(cfg.getConfig("demux/execute-import", mergeParameterSet, "./import-fastq.sh"));
6658 31 Mar 22 nicklas 115   
6182 25 Mar 21 nicklas 116     // Load common items
6182 25 Mar 21 nicklas 117     ItemSubtype fastqImportJobType = Subtype.FASTQ_IMPORT_JOB.get(dc);
6215 16 Apr 21 nicklas 118     ItemSubtype mergedType = Subtype.MERGED_SEQUENCES.get(dc);
6182 25 Mar 21 nicklas 119     
6182 25 Mar 21 nicklas 120     // Selected items must be removed from this list
6182 25 Mar 21 nicklas 121     ItemList importPipeline = BiomaterialList.FASTQ_IMPORT_PIPELINE.load(dc);
6182 25 Mar 21 nicklas 122
6182 25 Mar 21 nicklas 123     // Options common for all jobs
6182 25 Mar 21 nicklas 124     JobConfig jobConfig = new JobConfig();
6182 25 Mar 21 nicklas 125     if (priority != null) jobConfig.setPriority(priority);
7372 06 Oct 23 nicklas 126     if (partition != null) jobConfig.setSbatchOption("partition", ScriptUtil.checkValidScriptParameter(partition));
7372 06 Oct 23 nicklas 127     jobConfig.convertOptionsTo(clusterCfg.getType());
7372 06 Oct 23 nicklas 128     if (submitOptionsOverride != null)
7372 06 Oct 23 nicklas 129     {
7372 06 Oct 23 nicklas 130       ScriptUtil.addSubmitOptions(jobConfig, submitOptionsOverride, clusterCfg.getType());
7372 06 Oct 23 nicklas 131     }
7372 06 Oct 23 nicklas 132     else
7372 06 Oct 23 nicklas 133     {
7372 06 Oct 23 nicklas 134       ScriptUtil.addSubmitOptions(jobConfig, import_submit, clusterCfg.getType());
7372 06 Oct 23 nicklas 135       if (debug) ScriptUtil.addSubmitOptions(jobConfig, import_submit_debug, clusterCfg.getType());
7372 06 Oct 23 nicklas 136     }
6182 25 Mar 21 nicklas 137     
6182 25 Mar 21 nicklas 138     // We submit one job for each item to the cluster
6215 16 Apr 21 nicklas 139     List<JobDefinition> jobDefs = new ArrayList<JobDefinition>(demuxedSequences.size());
6182 25 Mar 21 nicklas 140
6215 16 Apr 21 nicklas 141     for (DemuxedSequences ds : demuxedSequences)
6182 25 Mar 21 nicklas 142     {
6215 16 Apr 21 nicklas 143       ds = DemuxedSequences.getById(dc, ds.getId()); // Ensure item is loaded in this transaction
6215 16 Apr 21 nicklas 144       DerivedBioAssay demuxed = ds.getDerivedBioAssay();
6215 16 Apr 21 nicklas 145       String demuxName = ScriptUtil.checkValidFilename(demuxed.getName());
6182 25 Mar 21 nicklas 146       
6215 16 Apr 21 nicklas 147       List<String> rawFastqNames = (List<String>)Annotationtype.RAW_FASTQ.getAnnotationValues(dc, demuxed);
6209 13 Apr 21 nicklas 148       if (rawFastqNames == null || rawFastqNames.size() != 2)
6209 13 Apr 21 nicklas 149       {
6209 13 Apr 21 nicklas 150         throw new InvalidDataException("Annotation RawFASTQ on " + 
6215 16 Apr 21 nicklas 151             demuxName + " must have two values: " + rawFastqNames);
6209 13 Apr 21 nicklas 152       }
6474 04 Nov 21 nicklas 153       String fastqNameR1 = null;
6474 04 Nov 21 nicklas 154       String fastqNameR2 = null;
6474 04 Nov 21 nicklas 155       // NOTE! Order in the list is not specified so we don't know which is R1 and R2
6474 04 Nov 21 nicklas 156       // Search for _R1 and _R2
6474 04 Nov 21 nicklas 157       for (String fqName : rawFastqNames)
6474 04 Nov 21 nicklas 158       {
6474 04 Nov 21 nicklas 159         if (fqName.contains("_R1")) fastqNameR1 = fqName;
6474 04 Nov 21 nicklas 160         if (fqName.contains("_R2")) fastqNameR2 = fqName;
6474 04 Nov 21 nicklas 161       }
6474 04 Nov 21 nicklas 162       if (fastqNameR1 == null)
6474 04 Nov 21 nicklas 163       {
6474 04 Nov 21 nicklas 164         throw new InvalidDataException("Annotation RawFASTQ on " + 
6474 04 Nov 21 nicklas 165             demuxName + " is missing an R1 fastq file: " + rawFastqNames);
6474 04 Nov 21 nicklas 166       }
6474 04 Nov 21 nicklas 167       if (fastqNameR2 == null)
6474 04 Nov 21 nicklas 168       {
6474 04 Nov 21 nicklas 169         throw new InvalidDataException("Annotation RawFASTQ on " + 
6474 04 Nov 21 nicklas 170             demuxName + " is missing an R2 fastq file: " + rawFastqNames);
6474 04 Nov 21 nicklas 171       }
6209 13 Apr 21 nicklas 172       
6209 13 Apr 21 nicklas 173       // Get SequencingRun so that we can get the path to the FASTQ folder.
6215 16 Apr 21 nicklas 174       String rawFastqFolder = ScriptUtil.checkValidPath((String)Annotationtype.DATA_FILES_FOLDER.getAnnotationValue(dc, demuxed), true, true);
6209 13 Apr 21 nicklas 175       
6215 16 Apr 21 nicklas 176       importPipeline.removeItem(demuxed);
6215 16 Apr 21 nicklas 177       Library lib = Library.get(demuxed.getExtract());
6215 16 Apr 21 nicklas 178       boolean isExternal = Reggie.isExternalItem(demuxName);
6182 25 Mar 21 nicklas 179       String rootName = isExternal ? lib.getTopExtractOrSample(dc).getName() : null;
6182 25 Mar 21 nicklas 180       
6182 25 Mar 21 nicklas 181       // Create job 
6215 16 Apr 21 nicklas 182       String mergedName = lib.getNextMergedSequencesName(dc);
6182 25 Mar 21 nicklas 183       Job importJob = Job.getNew(dc, null, null, null);
6182 25 Mar 21 nicklas 184       importJob.setItemSubtype(fastqImportJobType);
6182 25 Mar 21 nicklas 185       importJob.setPluginVersion("reggie-"+Reggie.VERSION);
6182 25 Mar 21 nicklas 186       importJob.setSendMessage(Values.getBoolean(sc.getUserClientSetting("plugins.sendmessage"), false));
6215 16 Apr 21 nicklas 187       importJob.setName("FASTQ Import to " + mergedName);
6211 14 Apr 21 nicklas 188       importJob.setParameterValue("pipeline", new StringParameterType(), Pipeline.RNA_SEQ.getId());
6182 25 Mar 21 nicklas 189       if (debug) importJob.setName(importJob.getName() + " (debug)");
6981 17 Jan 23 nicklas 190       if (partition != null) importJob.setParameterValue("partition", new StringParameterType(), partition);
7372 06 Oct 23 nicklas 191       if (submitOptionsOverride != null) importJob.setParameterValue("jobOptions", new StringParameterType(), submitOptionsOverride);
6182 25 Mar 21 nicklas 192       dc.saveItem(importJob);
6215 16 Apr 21 nicklas 193       
6215 16 Apr 21 nicklas 194       // Created MERGED derived bioassay set
6215 16 Apr 21 nicklas 195       DerivedBioAssay merged = DerivedBioAssay.getNew(dc, demuxed, importJob);
6215 16 Apr 21 nicklas 196       merged.setItemSubtype(mergedType);
6215 16 Apr 21 nicklas 197       Pipeline.RNA_SEQ.setAnnotation(dc, merged);
6215 16 Apr 21 nicklas 198       merged.setName(mergedName);
6215 16 Apr 21 nicklas 199       merged.setExtract(lib.getExtract());
6182 25 Mar 21 nicklas 200       merged.setSoftware(mergeSoftware);
6182 25 Mar 21 nicklas 201       merged.setProtocol(mergeProtocol);
6215 16 Apr 21 nicklas 202       DoNotUse.copyDoNotUseAnnotations(dc, lib.getExtract(), merged, false);
6215 16 Apr 21 nicklas 203       // Copy READS
6215 16 Apr 21 nicklas 204       Annotationtype.READS.copyAnnotationValues(dc, demuxed, merged, false);
6215 16 Apr 21 nicklas 205       Annotationtype.PF_READS.copyAnnotationValues(dc, demuxed, merged, false);
6215 16 Apr 21 nicklas 206       dc.saveItem(merged);
6182 25 Mar 21 nicklas 207       
6658 31 Mar 22 nicklas 208       String fastqFolder = ScriptUtil.checkValidPath(MergedSequences.generateDataFilesFolderForProjectArchive(mergedName, rootName, debug), true, true);
6658 31 Mar 22 nicklas 209       Annotationtype.DATA_FILES_FOLDER.setAnnotationValue(dc, merged, fastqFolder);
6182 25 Mar 21 nicklas 210       if (autoConfirm)
6182 25 Mar 21 nicklas 211       {
6182 25 Mar 21 nicklas 212         Annotationtype.AUTO_PROCESSING.setAnnotationValue(dc, merged, "AutoConfirm");
6182 25 Mar 21 nicklas 213       }
6182 25 Mar 21 nicklas 214
6658 31 Mar 22 nicklas 215       String archiveFolder = isExternal ? externalArchive : projectArchive;
6215 16 Apr 21 nicklas 216       String baseFileName = isExternal ? Reggie.removePrefix(mergedName) : mergedName;
6209 13 Apr 21 nicklas 217       
6182 25 Mar 21 nicklas 218       ScriptBuilder script = new ScriptBuilder();
6665 05 Apr 22 nicklas 219       script.cmd(debug ? "set -ex" : "set -e");
6658 31 Mar 22 nicklas 220
6182 25 Mar 21 nicklas 221       // Set file permissions based on consent or external group!
6215 16 Apr 21 nicklas 222       String externalGroup = isExternal ? Reggie.getExternalGroup(mergedName) : null;
6182 25 Mar 21 nicklas 223       ScriptUtil.setUmaskForItem(dc, lib, externalGroup, script);
6693 22 Apr 22 nicklas 224       script.newLine();
6693 22 Apr 22 nicklas 225       script.cmd(global_env);
6658 31 Mar 22 nicklas 226       script.export("ArchiveFolder", archiveFolder);
6658 31 Mar 22 nicklas 227       script.export("FASTQ1", ScriptUtil.checkValidFilename(fastqNameR1));
6658 31 Mar 22 nicklas 228       script.export("FASTQ2", ScriptUtil.checkValidFilename(fastqNameR2));
6658 31 Mar 22 nicklas 229       script.export("MergedName", mergedName);
6693 22 Apr 22 nicklas 230       script.export("ImportArchive", "${ImportArchiveRoot}"+rawFastqFolder);
6658 31 Mar 22 nicklas 231       script.export("FastqFolder", "${ArchiveFolder}"+fastqFolder);
6658 31 Mar 22 nicklas 232       script.export("BaseFileName", baseFileName);
6182 25 Mar 21 nicklas 233       script.newLine();
6658 31 Mar 22 nicklas 234       script.cmd(demux_env);
6658 31 Mar 22 nicklas 235       script.cmd(import_env);
6658 31 Mar 22 nicklas 236       if (debug) script.cmd(import_envdebug);
6658 31 Mar 22 nicklas 237       script.cmd(import_execute);
6182 25 Mar 21 nicklas 238
6182 25 Mar 21 nicklas 239       if (externalGroup != null)
6182 25 Mar 21 nicklas 240       {
6658 31 Mar 22 nicklas 241         ScriptUtil.addChgrp(externalGroup, fastqFolder, mergedName, archiveFolder+"/"+Reggie.getPrefix(mergedName), script);
6182 25 Mar 21 nicklas 242       }
6182 25 Mar 21 nicklas 243       
6674 11 Apr 22 nicklas 244       JobDefinition jobDef = new JobDefinition("FastqImport", jobConfig, batchConfig, importJob);
6658 31 Mar 22 nicklas 245       jobDef.addFile(ScriptUtil.upload("import-fastq.sh"));
6658 31 Mar 22 nicklas 246       jobDef.addFile(ScriptUtil.upload("demux-utils.sh"));
6658 31 Mar 22 nicklas 247       jobDef.addFile(ScriptUtil.upload("reggie-utils.sh"));
6658 31 Mar 22 nicklas 248       jobDef.addFile(ScriptUtil.upload("stdwrap.sh"));
6658 31 Mar 22 nicklas 249       jobDef.addFile(ScriptUtil.upload("singlecolumnaverager.awk"));
6658 31 Mar 22 nicklas 250       jobDef.addFile(ScriptUtil.upload("readlength_averager.awk"));
6182 25 Mar 21 nicklas 251       jobDef.setDebug(debug);
6182 25 Mar 21 nicklas 252       jobDef.setCmd(script.toString());
6182 25 Mar 21 nicklas 253       jobDefs.add(jobDef);
6182 25 Mar 21 nicklas 254     }
6182 25 Mar 21 nicklas 255     
6182 25 Mar 21 nicklas 256     return jobDefs;
6182 25 Mar 21 nicklas 257   }
6182 25 Mar 21 nicklas 258   
6182 25 Mar 21 nicklas 259   /**
6182 25 Mar 21 nicklas 260     Job completion handler for FASTQ import jobs.
6182 25 Mar 21 nicklas 261     
6182 25 Mar 21 nicklas 262      The handler downloads the
6182 25 Mar 21 nicklas 263     'demultiplex_metrics.txt' file from the job folder and parses out number of
6182 25 Mar 21 nicklas 264     reads and passed filter information for each sequenced library.
6182 25 Mar 21 nicklas 265     
6182 25 Mar 21 nicklas 266      The information
6182 25 Mar 21 nicklas 267     is stored on {@link MergedSequences} items in {@link Annotationtype#READS}
6182 25 Mar 21 nicklas 268     and {@link Annotationtype#PF_READS} annotations.
6182 25 Mar 21 nicklas 269   */
6182 25 Mar 21 nicklas 270   public static class FastqImportJobCompletionHandler
6182 25 Mar 21 nicklas 271     implements JobCompletionHandler
6182 25 Mar 21 nicklas 272   {
6182 25 Mar 21 nicklas 273     private XmlConfig cfg;
6182 25 Mar 21 nicklas 274     
6182 25 Mar 21 nicklas 275     public FastqImportJobCompletionHandler()
6182 25 Mar 21 nicklas 276     {}
6182 25 Mar 21 nicklas 277   
6182 25 Mar 21 nicklas 278     @Override
6182 25 Mar 21 nicklas 279     public String jobCompleted(SessionControl sc, OpenGridSession session, Job job, JobStatus status)
6182 25 Mar 21 nicklas 280     {
6182 25 Mar 21 nicklas 281       String jobName = status.getName();
6182 25 Mar 21 nicklas 282       String trimmomatic = session.getJobFileAsString(jobName, "trimmomatic.out", "UTF-8");
6182 25 Mar 21 nicklas 283       String fragments = session.getJobFileAsString(jobName, "fragments.out", "UTF-8");
6421 23 Sep 21 nicklas 284       String readlength = session.getJobFileAsString(jobName, "readlength.out", "UTF-8");
6182 25 Mar 21 nicklas 285       String files = session.getJobFileAsString(jobName, "files.out", "UTF-8");
6182 25 Mar 21 nicklas 286
6182 25 Mar 21 nicklas 287       cfg = Reggie.getConfig(session.getHost().getId());
6182 25 Mar 21 nicklas 288   
6421 23 Sep 21 nicklas 289       Metrics total = parseImportMetrics(sc, job, trimmomatic, fragments, readlength, files);
6182 25 Mar 21 nicklas 290       String msg = Values.formatNumber(total.reads/1000000f, 1) + "M reads; ";
6182 25 Mar 21 nicklas 291       msg += Values.formatNumber(total.passedFilter/1000000f, 1) + "M passed filter; ";
6182 25 Mar 21 nicklas 292       msg += Values.formatNumber(total.passedTrimmomatic[1]/1000000f, 1) + "M passed trimmomatic; ";
6215 16 Apr 21 nicklas 293       return msg;
6182 25 Mar 21 nicklas 294     }
6182 25 Mar 21 nicklas 295     
6421 23 Sep 21 nicklas 296     private Metrics parseImportMetrics(SessionControl sc, Job job, String trimmomatic, String align, String readlength, String files)
6182 25 Mar 21 nicklas 297     {
6182 25 Mar 21 nicklas 298       Metrics metrics = new Metrics();
6182 25 Mar 21 nicklas 299
6182 25 Mar 21 nicklas 300       // Parse the trimmomatic.out file
6182 25 Mar 21 nicklas 301       Pattern before = Pattern.compile(".*Input Read Pairs:\\s+(\\d+).*");
6182 25 Mar 21 nicklas 302       Pattern after = Pattern.compile(".*Both Surviving:\\s+(\\d+).*");
6182 25 Mar 21 nicklas 303       int trimmomaticStep = 0;
6182 25 Mar 21 nicklas 304       for (String line : trimmomatic.split("\n"))
6182 25 Mar 21 nicklas 305       {
6182 25 Mar 21 nicklas 306         Matcher m = after.matcher(line);
6182 25 Mar 21 nicklas 307         if (m.matches())
6182 25 Mar 21 nicklas 308         {
6182 25 Mar 21 nicklas 309           metrics.passedTrimmomatic[trimmomaticStep] = Values.getLong(m.group(1), -1);
6182 25 Mar 21 nicklas 310           trimmomaticStep++;
6182 25 Mar 21 nicklas 311           if (trimmomaticStep == 2) break;
6182 25 Mar 21 nicklas 312         }
6182 25 Mar 21 nicklas 313         m = before.matcher(line);
6182 25 Mar 21 nicklas 314         if (m.matches())
6182 25 Mar 21 nicklas 315         {
6474 04 Nov 21 nicklas 316           metrics.reads = Values.getLong(m.group(1), -1);
6474 04 Nov 21 nicklas 317           metrics.passedFilter = metrics.reads;
6182 25 Mar 21 nicklas 318         }
6182 25 Mar 21 nicklas 319       }
6182 25 Mar 21 nicklas 320       
6182 25 Mar 21 nicklas 321       // Parse fragments.out file
6182 25 Mar 21 nicklas 322       Pattern p = Pattern.compile("(\\d+)\\t(\\d+\\.?\\d*)\\t(\\d+\\.?\\d*)");
6182 25 Mar 21 nicklas 323       for (String line : align.split("\n"))
6182 25 Mar 21 nicklas 324       {
6182 25 Mar 21 nicklas 325         Matcher m = p.matcher(line);
6182 25 Mar 21 nicklas 326         if (m.matches())
6182 25 Mar 21 nicklas 327         {
6182 25 Mar 21 nicklas 328           metrics.fragmentSizeCount = Values.getInt(m.group(1), -1);
6182 25 Mar 21 nicklas 329           metrics.fragmentSizeAvg = Values.getInt(m.group(2), -1);
6182 25 Mar 21 nicklas 330           metrics.fragmentSizeStd = Values.getInt(m.group(3), -1);
6182 25 Mar 21 nicklas 331           break;
6182 25 Mar 21 nicklas 332         }
6182 25 Mar 21 nicklas 333       }
6182 25 Mar 21 nicklas 334
6421 23 Sep 21 nicklas 335       // Parse readlength.out file
6421 23 Sep 21 nicklas 336       p = Pattern.compile("(\\d+)\\t(\\d+\\.?\\d*)");
6421 23 Sep 21 nicklas 337       int readNo = -1;
6421 23 Sep 21 nicklas 338       for (String line : readlength.split("\n"))
6421 23 Sep 21 nicklas 339       {
6421 23 Sep 21 nicklas 340         Matcher m = p.matcher(line);
6421 23 Sep 21 nicklas 341         if (m.matches())
6421 23 Sep 21 nicklas 342         {
6421 23 Sep 21 nicklas 343           readNo++;
6421 23 Sep 21 nicklas 344           if (readNo >= metrics.readlengthCount.length) break;
6421 23 Sep 21 nicklas 345           metrics.readlengthCount[readNo] = Values.getInt(m.group(1), -1);
6421 23 Sep 21 nicklas 346           metrics.readlengthAvg[readNo] = Values.getInt(m.group(2), -1);
6421 23 Sep 21 nicklas 347         }
6421 23 Sep 21 nicklas 348       }
6421 23 Sep 21 nicklas 349       
6182 25 Mar 21 nicklas 350       DbControl dc = null;
6182 25 Mar 21 nicklas 351       try
6182 25 Mar 21 nicklas 352       {
6599 22 Feb 22 nicklas 353         dc = sc.newDbControl("Reggie: FASTQ import completed handler");
6182 25 Mar 21 nicklas 354
6184 26 Mar 21 nicklas 355         MergedSequences mergedSequences = MergedSequences.getByJob(dc, job);
6184 26 Mar 21 nicklas 356         DerivedBioAssay merged = mergedSequences.getItem();
6182 25 Mar 21 nicklas 357         
6182 25 Mar 21 nicklas 358         DataFileType fastqData = Datafiletype.FASTQ.load(dc);
6182 25 Mar 21 nicklas 359         ItemSubtype fastqType = fastqData.getGenericType();
6182 25 Mar 21 nicklas 360         FileServer projectArchive = Fileserver.PROJECT_ARCHIVE.load(dc);
6182 25 Mar 21 nicklas 361         FileServer externalArchive = Fileserver.EXTERNAL_ARCHIVE.load(dc);
7051 17 Feb 23 nicklas 362         FileServer importGateway = Fileserver.IMPORT_GATEWAY.load(dc);
7051 17 Feb 23 nicklas 363         FileServer importArchive = Fileserver.IMPORT_ARCHIVE.load(dc);
6182 25 Mar 21 nicklas 364         
6182 25 Mar 21 nicklas 365         Software mergeSoftware = merged.getSoftware();
6182 25 Mar 21 nicklas 366         String mergeParameterSet = (String)Annotationtype.PARAMETER_SET.getAnnotationValue(dc, mergeSoftware);
6182 25 Mar 21 nicklas 367         int bowtie_fragment_count_limit = Values.getInt(cfg.getConfig("demux/bowtie-fragment-count-limit", mergeParameterSet, "20000"));
6182 25 Mar 21 nicklas 368   
6474 04 Nov 21 nicklas 369         Annotationtype.READS.setAnnotationValue(dc, merged, metrics.reads);
6182 25 Mar 21 nicklas 370         Annotationtype.PF_READS.setAnnotationValue(dc, merged, metrics.passedFilter);
6182 25 Mar 21 nicklas 371         Annotationtype.ADAPTER_READS.setAnnotationValue(dc, merged, metrics.passedFilter - metrics.passedTrimmomatic[0]);
6182 25 Mar 21 nicklas 372         Annotationtype.PT_READS.setAnnotationValue(dc, merged, metrics.passedTrimmomatic[1]);
6182 25 Mar 21 nicklas 373         Annotationtype.FRAGMENT_SIZE_AVG.setAnnotationValue(dc, merged, metrics.fragmentSizeCount < bowtie_fragment_count_limit ? -1 : metrics.fragmentSizeAvg);
6182 25 Mar 21 nicklas 374         Annotationtype.FRAGMENT_SIZE_STDEV.setAnnotationValue(dc, merged, metrics.fragmentSizeCount < bowtie_fragment_count_limit ? -1 : metrics.fragmentSizeStd);
6421 23 Sep 21 nicklas 375         Annotationtype.READLENGTH_AVG_R1.setAnnotationValue(dc, merged, metrics.readlengthCount[0] < bowtie_fragment_count_limit ? -1 : metrics.readlengthAvg[0]);
6421 23 Sep 21 nicklas 376         Annotationtype.READLENGTH_AVG_R2.setAnnotationValue(dc, merged, metrics.readlengthCount[1] < bowtie_fragment_count_limit ? -1 : metrics.readlengthAvg[1]);
6421 23 Sep 21 nicklas 377           
6182 25 Mar 21 nicklas 378         // Create FASTQ file links
6182 25 Mar 21 nicklas 379         boolean useExternalProjectArchive = Reggie.isExternalItem(merged.getName());
6182 25 Mar 21 nicklas 380         FileServer fileArchive = useExternalProjectArchive ? externalArchive : projectArchive;
6182 25 Mar 21 nicklas 381         String analysisDir = useExternalProjectArchive ? Reggie.EXTERNAL_ANALYSIS_DIR : Reggie.SECONDARY_ANALYSIS_DIR;
6182 25 Mar 21 nicklas 382             
6182 25 Mar 21 nicklas 383         String dataFilesFolder = (String)Annotationtype.DATA_FILES_FOLDER.getAnnotationValue(dc, merged);
6182 25 Mar 21 nicklas 384         String baseFolder = Reggie.convertDataFilesFolderToBaseFolder(dataFilesFolder);
6182 25 Mar 21 nicklas 385         Directory localDataDir = Directory.getNew(dc, new Path(analysisDir+baseFolder, Path.Type.DIRECTORY));
6182 25 Mar 21 nicklas 386             
6182 25 Mar 21 nicklas 387         int lineNo = 0;
6182 25 Mar 21 nicklas 388         for (String line : files.split("\n"))
6182 25 Mar 21 nicklas 389         {
6182 25 Mar 21 nicklas 390           lineNo++;
6182 25 Mar 21 nicklas 391           
6182 25 Mar 21 nicklas 392           File f = File.getFile(dc, localDataDir, line.substring(line.lastIndexOf("/")+1), true);
6182 25 Mar 21 nicklas 393           f.setFileServer(fileArchive);
6182 25 Mar 21 nicklas 394           f.setItemSubtype(fastqType);
6182 25 Mar 21 nicklas 395           f.setDescription(metrics.reads + " READS; " + metrics.passedFilter + " PF_READS; " + metrics.passedTrimmomatic[1] + " PT_READS");
6421 23 Sep 21 nicklas 396           if (f.getName().contains(".fastq"))
6421 23 Sep 21 nicklas 397           {
6421 23 Sep 21 nicklas 398             f.setDescription(f.getDescription()+"; ReadLengthAvg="+metrics.readlengthAvg[f.getName().contains("R1.fastq")?0:1]);
6421 23 Sep 21 nicklas 399           }
6182 25 Mar 21 nicklas 400           String fileUrl = "sftp://" + fileArchive.getHost() + dataFilesFolder + "/" + f.getName();
6182 25 Mar 21 nicklas 401           try
6182 25 Mar 21 nicklas 402           {
6182 25 Mar 21 nicklas 403             f.setUrl(fileUrl, true);
6182 25 Mar 21 nicklas 404           }
6182 25 Mar 21 nicklas 405           catch (RuntimeException ex)
6182 25 Mar 21 nicklas 406           {
6182 25 Mar 21 nicklas 407             f.setUrl(fileUrl, false);
6182 25 Mar 21 nicklas 408           }
6182 25 Mar 21 nicklas 409           if (!f.isInDatabase())
6182 25 Mar 21 nicklas 410           {
6182 25 Mar 21 nicklas 411             dc.saveItem(f);
6182 25 Mar 21 nicklas 412           }
6182 25 Mar 21 nicklas 413           FileSetMember member = merged.getFileSet().addMember(f, fastqData);
6182 25 Mar 21 nicklas 414         }
6182 25 Mar 21 nicklas 415         
7051 17 Feb 23 nicklas 416         // Change the raw FASTQ files on the DemuxedSequences item to point
7051 17 Feb 23 nicklas 417         // to the new location in the ImportArchive
7051 17 Feb 23 nicklas 418         DemuxedSequences dx = mergedSequences.getSingleDemuxedSequences(dc);
7051 17 Feb 23 nicklas 419         String rawFastqFilesFolder = (String)Annotationtype.DATA_FILES_FOLDER.getAnnotationValue(dc, dx.getItem());
7051 17 Feb 23 nicklas 420         for (File f : Datafiletype.FASTQ.getAllFiles(dc, dx.getItem()))
7051 17 Feb 23 nicklas 421         {
7051 17 Feb 23 nicklas 422           if (importGateway.equals(f.getFileServer()))
7051 17 Feb 23 nicklas 423           {
7051 17 Feb 23 nicklas 424             String uri = "sftp://"+importArchive.getHost()+rawFastqFilesFolder+"/"+f.getName();
7051 17 Feb 23 nicklas 425             UriMetadata metadata = getUriMetadata(f, uri);
7051 17 Feb 23 nicklas 426             f.setFileServer(importArchive);
7051 17 Feb 23 nicklas 427             f.setUrl(uri, metadata);
7051 17 Feb 23 nicklas 428           }
7051 17 Feb 23 nicklas 429         }
6182 25 Mar 21 nicklas 430         dc.commit();
6182 25 Mar 21 nicklas 431       }
6182 25 Mar 21 nicklas 432       finally
6182 25 Mar 21 nicklas 433       {
6182 25 Mar 21 nicklas 434         if (dc != null) dc.close();
6182 25 Mar 21 nicklas 435       }
6182 25 Mar 21 nicklas 436       
6182 25 Mar 21 nicklas 437       return metrics;
6182 25 Mar 21 nicklas 438     }
7051 17 Feb 23 nicklas 439     
7051 17 Feb 23 nicklas 440     /**
7051 17 Feb 23 nicklas 441       Copy the existing metadata from the file.
7051 17 Feb 23 nicklas 442     */
7051 17 Feb 23 nicklas 443     private UriMetadata getUriMetadata(File f, String uri)
7051 17 Feb 23 nicklas 444     {
7051 17 Feb 23 nicklas 445       UriMetadata m = new UriMetadata(URI.create(uri));
7051 17 Feb 23 nicklas 446       m.setLastModified(f.getLastUpdate());
7051 17 Feb 23 nicklas 447       m.setLength(f.getSize());
7051 17 Feb 23 nicklas 448       m.setMd5(f.getMd5());
7051 17 Feb 23 nicklas 449       m.setMimeType(f.getMimeType());
7051 17 Feb 23 nicklas 450       m.setCharacterSet(f.getCharacterSet());
7051 17 Feb 23 nicklas 451       return m;
7051 17 Feb 23 nicklas 452     }
6182 25 Mar 21 nicklas 453   }
6182 25 Mar 21 nicklas 454   
6182 25 Mar 21 nicklas 455   
6182 25 Mar 21 nicklas 456   static class Metrics
6182 25 Mar 21 nicklas 457   {
6182 25 Mar 21 nicklas 458     long reads = 0;
6182 25 Mar 21 nicklas 459     long passedFilter = 0;
6182 25 Mar 21 nicklas 460     long[] passedTrimmomatic = new long[2];
6182 25 Mar 21 nicklas 461     int fragmentSizeAvg = -1;
6182 25 Mar 21 nicklas 462     int fragmentSizeStd = -1;
6182 25 Mar 21 nicklas 463     int fragmentSizeCount = -1;
6421 23 Sep 21 nicklas 464     int[] readlengthAvg = new int[2];
6421 23 Sep 21 nicklas 465     long[] readlengthCount = new long[2];
6182 25 Mar 21 nicklas 466   }
6182 25 Mar 21 nicklas 467
6182 25 Mar 21 nicklas 468   
6182 25 Mar 21 nicklas 469
6182 25 Mar 21 nicklas 470 }