Skip to content

Commit 3416922

Browse files
Merge pull request #372 from qbicsoftware/release/2.27.0
Release/2.27.0
2 parents 9fb49d8 + 8c944b1 commit 3416922

18 files changed

+1480
-27
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ Make sure, that you have defined the Github package Maven repository, in order f
100100

101101
A Nanopore NGS measurement output is delivered to us as a nested folder structure, following this model:
102102

103-
![Nanopore Data Structure Model](./doc/figures/Nanopore_Data_Structure_Model.svg)
103+
![Nanopore Data Structure Model](./doc/figures/Nanopore_Data_Structure_Model.png)
104104

105105

106106
#### Nanopore usage example
1.02 MB
Loading

doc/figures/Nanopore_Data_Structure_Model.svg

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/main/groovy/life/qbic/datamodel/datasets/OxfordNanoporeExperiment.groovy

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ final class OxfordNanoporeExperiment implements ExperimentFolder {
244244
FAST5_FILE(FQDN_FILES + ".Fast5File"),
245245
FASTQ_FILE(FQDN_FILES + ".FastQFile"),
246246
FASTQ_ZIPPED_FILE(FQDN_FILES + ".FastQZippedFile"),
247+
POD5_FILE(FQDN_FILES + ".Pod5File"),
247248
FINAL_SUMMARY_LOG(FQDN_FILES + ".FinalSummaryLog"),
248249
MUX_SCAN_DATA_LOG(FQDN_FILES + ".MuxScanDataLog"),
249250
REPORT_MD_LOG(FQDN_FILES + ".ReportMdLog"),
@@ -299,10 +300,14 @@ final class OxfordNanoporeExperiment implements ExperimentFolder {
299300
FASTQ_FOLDER(FQDN_FOLDERS + ".FastQFolder"),
300301
FAST5_PASS_FOLDER(FQDN_FOLDERS + ".Fast5PassFolder"),
301302
FAST5_FAIL_FOLDER(FQDN_FOLDERS + ".Fast5FailFolder"),
303+
FAST5_SKIP_FOLDER(FQDN_FOLDERS + ".Fast5SkipFolder"),
302304
FASTQ_PASS_FOLDER(FQDN_FOLDERS + ".FastQPassFolder"),
303305
FASTQ_FAIL_FOLDER(FQDN_FOLDERS + ".FastQFailFolder"),
304306
UNCLASSIFIED_FAST5_FOLDER(FQDN_FOLDERS + ".UnclassifiedFast5Folder"),
305307
UNCLASSIFIED_FASTQ_FOLDER(FQDN_FOLDERS + ".UnclassifiedFastQFolder"),
308+
POD5_PASS_FOLDER(FQDN_FOLDERS + ".Pod5PassFolder"),
309+
POD5_FAIL_FOLDER(FQDN_FOLDERS + ".Pod5FailFolder"),
310+
POD5_SKIP_FOLDER(FQDN_FOLDERS + ".Pod5SkipFolder"),
306311
OTHER_REPORTS_FOLDER(FQDN_FOLDERS + ".OtherReportsFolder"),
307312
BASECALLING_FOLDER(FQDN_FOLDERS + ".BasecallingFolder"),
308313

src/main/groovy/life/qbic/datamodel/datasets/OxfordNanoporeMeasurement.groovy

Lines changed: 59 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,13 @@ final class OxfordNanoporeMeasurement {
5757
this.pooledSamplesMeasurement = containsAtLeastOneBarcodedFolder(folders["fast5pass"])
5858
// There can be still pooled samples in the failed folder, worst case is all
5959
// samples failed, so we need to check there too
60-
if (! pooledSamplesMeasurement) {
60+
if (!pooledSamplesMeasurement) {
6161
this.pooledSamplesMeasurement = containsAtLeastOneBarcodedFolder(folders["fast5fail"])
6262
}
6363
}
6464

6565
private void assessBasecallingStatus() {
66-
this.hasBasecallingData = folders["basecalling"];
66+
this.hasBasecallingData = folders["basecalling"]
6767
}
6868

6969
private static boolean containsAtLeastOneBarcodedFolder(DataFolder folder) {
@@ -84,12 +84,24 @@ final class OxfordNanoporeMeasurement {
8484
case Fast5FailFolder:
8585
folders["fast5fail"] = element as Fast5FailFolder
8686
break
87+
case Fast5SkipFolder:
88+
folders["fast5skip"] = element as Fast5SkipFolder
89+
break
8790
case FastQPassFolder:
8891
folders["fastqpass"] = element as FastQPassFolder
8992
break
9093
case FastQFailFolder:
9194
folders["fastqfail"] = element as FastQFailFolder
9295
break
96+
case Pod5PassFolder:
97+
folders["pod5pass"] = element as Pod5PassFolder
98+
break
99+
case Pod5FailFolder:
100+
folders["pod5fail"] = element as Pod5FailFolder
101+
break
102+
case Pod5SkipFolder:
103+
folders["pod5skip"] = element as Pod5SkipFolder
104+
break
93105
case DataFile:
94106
logFilesCollection.add(element as DataFile)
95107
break
@@ -101,24 +113,38 @@ final class OxfordNanoporeMeasurement {
101113
}
102114

103115
private void assessState() throws IllegalStateException {
104-
// Condition one: Don't allow Fast5 pass and fail folder are empty
105-
assessFast5Content()
106-
// Condition two: Don't allow Fastq pass and fail folder are empty
107-
assessFastQContent()
116+
boolean isValid = false
117+
// We need to ensure that fastq and fast5 information is provided if guppy basecaller was used
118+
if (areFast5FoldersInMeasurement() && areFastQFoldersInMeasurement()) {
119+
isValid = true
120+
}
121+
//// We need to ensure that pod5_skip and fast5_skip information is provided if dorado basecaller was used
122+
if (arePod5FoldersInMeasurement()) {
123+
isValid = true
124+
}
125+
if (isValid == false) {
126+
throw new IllegalStateException("No valid data is contained in measurement")
127+
}
108128
}
109129

110-
private void assessFast5Content() throws IllegalStateException {
111-
if (folders["fast5pass"].getChildren().isEmpty() && folders["fast5fail"].getChildren()
112-
.isEmpty()) {
113-
throw new IllegalStateException("The fast5 pass folder and fail folder are empty.")
114-
}
130+
// Condition one: Don't allow empty Fast5 pass and fail folder
131+
private boolean areFast5FoldersInMeasurement() {
132+
return isDataFolderInMeasurement("fast5pass") || isDataFolderInMeasurement("fast5fail")
133+
}
134+
// Condition two: Don't allow empty Fastq pass and fail folder
135+
private boolean areFastQFoldersInMeasurement() {
136+
return isDataFolderInMeasurement("fastqpass") || isDataFolderInMeasurement("fastqfail")
137+
}
138+
// Condition three: Don't allow empty Pod5 skip and fast5 skip folder
139+
private boolean arePod5FoldersInMeasurement() {
140+
return isDataFolderInMeasurement("fast5skip") || isDataFolderInMeasurement("pod5skip")
115141
}
116142

117-
private void assessFastQContent() throws IllegalStateException {
118-
if (folders["fastqpass"].getChildren().isEmpty() && folders["fastqfail"].getChildren()
119-
.isEmpty()) {
120-
throw new IllegalStateException("The fastq pass folder and fail folder are empty.")
143+
private boolean isDataFolderInMeasurement(String string) {
144+
if (folders[string] == null) {
145+
return false
121146
}
147+
return !folders[string].getChildren().isEmpty()
122148
}
123149

124150
/**
@@ -284,12 +310,25 @@ final class OxfordNanoporeMeasurement {
284310
private Map<String, Map<String, DataFolder>> prepareRawData(String sampleId) {
285311
final def result = new HashMap()
286312
final def dataFolders = [
287-
"fast5fail": (folders.get("fast5fail") as DataFolder),
288-
"fast5pass": (folders.get("fast5pass") as DataFolder),
289-
"fastqpass": (folders.get("fastqpass") as DataFolder),
290-
"fastqfail": (folders.get("fastqfail") as DataFolder)
313+
"fast5fail" : (folders.get("fast5fail") as DataFolder),
314+
"fast5pass" : (folders.get("fast5pass") as DataFolder),
315+
"fastqpass" : (folders.get("fastqpass") as DataFolder),
316+
"fastqfail" : (folders.get("fastqfail") as DataFolder)
291317
]
292-
if(hasBasecallingData) dataFolders.put("basecalling", (folders.get("basecalling") as DataFolder))
318+
if (hasBasecallingData) dataFolders.put("basecalling", (folders.get("basecalling") as DataFolder))
319+
//Only add dorado based minimal required datafolders if present
320+
if (folders.get("fast5skip") != null) {
321+
dataFolders.put("fast5skip", (folders.get("fast5skip") as DataFolder))
322+
}
323+
if (folders.get("pod5skip") != null) {
324+
dataFolders.put("pod5skip", (folders.get("pod5skip") as DataFolder))
325+
}
326+
if (folders.get("pod5fail") != null) {
327+
dataFolders.put("pod5fail", (folders.get("pod5fail") as DataFolder))
328+
}
329+
if (folders.get("pod5pass") != null) {
330+
dataFolders.put("pod5pass", (folders.get("pod5pass") as DataFolder))
331+
}
293332
result.put(sampleId, dataFolders)
294333
return result
295334
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package life.qbic.datamodel.datasets.datastructure.files.nanopore
2+
3+
import life.qbic.datamodel.datasets.datastructure.files.DataFile
4+
5+
/**
6+
* A specialisation of a DataFile, represents an Oxford Nanopore pod5 file
7+
*
8+
*/
9+
class Pod5File extends DataFile {
10+
11+
final private static String FILE_TYPE = "pod5"
12+
13+
final private static String NAME_SCHEMA = /.*\.pod5$/
14+
15+
protected Pod5File(String name, String relativePath) {
16+
super(name, relativePath, FILE_TYPE)
17+
validateName()
18+
}
19+
20+
static Pod5File create(String name, String relativePath) {
21+
return new Pod5File(name, relativePath)
22+
}
23+
24+
private void validateName() {
25+
if (!(this.name =~ NAME_SCHEMA)) {
26+
throw new IllegalArgumentException("Name must match the Nanopore summary schema!")
27+
}
28+
}
29+
30+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package life.qbic.datamodel.datasets.datastructure.folders.nanopore
2+
3+
import life.qbic.datamodel.datasets.datastructure.files.nanopore.Fast5File
4+
import life.qbic.datamodel.datasets.datastructure.folders.DataFolder
5+
6+
/**
7+
* A special case of a DataFolder, its name is always fast5_skip.
8+
*
9+
* Its children field contains a list of type List<Fast5Files>
10+
*
11+
*/
12+
class Fast5SkipFolder extends DataFolder {
13+
14+
final private static String NAME_SCHEMA = /fast5_skip/
15+
16+
protected Fast5SkipFolder() {}
17+
18+
protected Fast5SkipFolder(String name, String relativePath, List<Fast5File> children) {
19+
super(name, relativePath, children)
20+
validateName()
21+
}
22+
23+
/**
24+
* Creates a new instance of a Fast5SkipFolder object
25+
* @param relativePath The relative path of the folder
26+
* @param children A list with child elements of the folder
27+
* @return A new instance of a Fast5SkipFolder object
28+
*/
29+
static Fast5SkipFolder create(String name, String relativePath, List<Fast5File> children) {
30+
return new Fast5SkipFolder(name, relativePath, children)
31+
}
32+
33+
private void validateName() {
34+
if (!(this.name =~ NAME_SCHEMA)) {
35+
throw new IllegalArgumentException("Name must match the Nanopore Fast5Skip directory schema!")
36+
}
37+
}
38+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package life.qbic.datamodel.datasets.datastructure.folders.nanopore
2+
3+
import life.qbic.datamodel.datasets.datastructure.folders.DataFolder
4+
5+
/**
6+
* A special case of a DataFolder, its name is always pod5_fail.
7+
*
8+
* Its children field contains either a list of type List<Pod5Files> or List<Pod5Folder>
9+
*
10+
*/
11+
class Pod5FailFolder extends DataFolder {
12+
13+
final private static String NAME_SCHEMA = /pod5_fail/
14+
15+
protected Pod5FailFolder() {}
16+
17+
protected Pod5FailFolder(String name, String relativePath, List children) {
18+
super(name, relativePath, children)
19+
validateName()
20+
}
21+
22+
/**
23+
* Creates a new instance of a Pod5FailFolder object
24+
*
25+
* @param name The folder name
26+
* @param relativePath The relative path of the folder
27+
* @param children A list with child elements of the folder
28+
* @return A new instance of a Pod5FailFolder object
29+
*/
30+
static Pod5FailFolder create(String name, String relativePath, List children) {
31+
new Pod5FailFolder(name, relativePath, children)
32+
}
33+
34+
private void validateName() {
35+
if (!(this.name =~ NAME_SCHEMA)) {
36+
throw new IllegalArgumentException("Name must match the Nanopore Pod5Fail directory schema!")
37+
}
38+
}
39+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package life.qbic.datamodel.datasets.datastructure.folders.nanopore
2+
3+
import life.qbic.datamodel.datasets.datastructure.folders.DataFolder
4+
5+
/**
6+
* A special case of a DataFolder, its name is always pod5_pass.
7+
*
8+
* Its children field contains either a list of type List<Pod5Files> or List<Pod5Folder>
9+
*
10+
*/
11+
class Pod5PassFolder extends DataFolder {
12+
13+
final private static String NAME_SCHEMA = /pod5_pass/
14+
15+
protected Pod5PassFolder() {}
16+
17+
protected Pod5PassFolder(String name, String relativePath, List<?> children) {
18+
super(name, relativePath, children)
19+
validateName()
20+
}
21+
22+
/**
23+
* Creates a new instance of a Pod5PassFolder object
24+
*
25+
* @param name The folder name
26+
* @param relativePath The relative path of the folder
27+
* @param children A list with child elements of the folder
28+
* @return A new instance of a Pod5PassFolder object
29+
*/
30+
static Pod5PassFolder create(String name, String relativePath, List<?> children) {
31+
new Pod5PassFolder(name, relativePath, children)
32+
}
33+
34+
private void validateName() {
35+
if (!(this.name =~ NAME_SCHEMA)) {
36+
throw new IllegalArgumentException("Name must match the Nanopore Pod5Pass directory schema!")
37+
}
38+
}
39+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package life.qbic.datamodel.datasets.datastructure.folders.nanopore
2+
3+
import life.qbic.datamodel.datasets.datastructure.files.nanopore.Pod5File
4+
import life.qbic.datamodel.datasets.datastructure.folders.DataFolder
5+
6+
/**
7+
* A special case of a DataFolder, its name is always pod5_skip.
8+
*
9+
* Its children field contains a list of type List<Pod5Files>
10+
*
11+
*/
12+
class Pod5SkipFolder extends DataFolder {
13+
14+
final private static String NAME_SCHEMA = /pod5_skip/
15+
16+
protected Pod5SkipFolder() {}
17+
18+
protected Pod5SkipFolder(String name, String relativePath, List<Pod5File> children) {
19+
super(name, relativePath, children)
20+
validateName()
21+
}
22+
23+
/**
24+
* Creates a new instance of a Pod5SkipFolder object
25+
* @param relativePath The relative path of the folder
26+
* @param children A list with child elements of the folder
27+
* @return A new instance of a Pod5SkipFolder object
28+
*/
29+
static Pod5SkipFolder create(String name, String relativePath, List<Pod5File> children) {
30+
return new Pod5SkipFolder(name, relativePath, children)
31+
}
32+
33+
private void validateName() {
34+
if (!(this.name =~ NAME_SCHEMA)) {
35+
throw new IllegalArgumentException("Name must match the Nanopore Pod5Skip directory schema!")
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)