Claude Cursor Skill

pipeline-wgbs

Execute ENCODE Whole Genome Bisulfite Sequencing (WGBS) pipeline from FASTQ to methylation calls. Child of pipeline-guide. Provides Nextflow execution with Docker and cloud deployment. Use when processing WGBS/bisulfite-seq data, calling methylation levels, generating bedMethyl f

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download ammawla-encode-toolkit-plugin_skills_pipeline-wgbs-36836c8.zip · 30 KB
Part of ammawla/encode-toolkit — 90 skills

Install

skills CLI npx skills add https://github.com/ammawla/encode-toolkit/tree/main/plugin/skills/pipeline-wgbs
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install ammawla-encode-toolkit@llmmart
Git git clone https://github.com/ammawla/encode-toolkit.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole ammawla/encode-toolkit collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

ENCODE WGBS Pipeline: FASTQ to Methylation Calls

When to Use

  • User wants to run a WGBS/bisulfite sequencing pipeline from FASTQ to methylation calls
  • User asks about "WGBS pipeline", "bisulfite sequencing", "methylation calling", "Bismark", or "bedMethyl"
  • User needs to process whole-genome bisulfite sequencing data following ENCODE standards
  • Example queries: "process my WGBS FASTQs", "call methylation levels from bisulfite-seq", "run Bismark on my WGBS data"

Execute the ENCODE DNA methylation pipeline for Whole Genome Bisulfite Sequencing data, producing per-CpG methylation levels in bedMethyl format.

Pipeline Overview

FASTQ -> Trim adapters -> Bismark align -> Deduplicate -> sort + index -> MethylDackel -> bedMethyl
  |           |                 |               |                |             |             |
 FastQC   Trim Galore    Bismark (Bowtie2)  deduplicate_   samtools      mbias +       coverage
                                             bismark                     extract        stats

Paired-end only: TRIM_GALORE and BISMARK_ALIGN both take two mates, and --reads must match pairs.

ENCODE Repository

  • GitHub: ENCODE-DCC/dna-me-pipeline
  • Container: built from scripts/Dockerfile in this skill (docker build -t encode-toolkit/pipeline-wgbs:1.0.0 scripts/); override with --container
  • WDL: Available for Cromwell execution
  • This skill: Nextflow DSL2 reimplementation for portability

Core Tools and Versions

These are the versions in scripts/Dockerfile, which is what the workflow runs.

Tool Version Purpose Citation
Trim Galore 0.6.10 Adapter + quality trimming (bisulfite-aware) Krueger (Babraham)
Bismark 0.24.2 Bisulfite-aware alignment + deduplication Krueger & Andrews 2011
Bowtie2 2.5.4 Backend aligner used by Bismark Langmead & Salzberg 2012
MethylDackel 0.6.1 Methylation extraction from BAM Ryan (GitHub)
samtools 1.19 BAM sorting and indexing Li et al. 2009
htslib 1.19 bgzip and tabix for the bedMethyl files Bonfield et al. 2021
FastQC 0.12.1 Read quality assessment Andrews (Babraham)
MultiQC 1.21 Aggregated QC reporting Ewels et al. 2016

The conda environment in bioinformatics-installer (environments/wgbs-env.yml) is a separate manual route pinned to the same versions of these tools; it also carries bedtools, which is not in the image.

Key Literature

  1. Krueger & Andrews 2011 - "Bismark: a flexible aligner and methylation caller for Bisulfite-Seq applications" (Bioinformatics, ~4,000 citations) DOI: 10.1093/bioinformatics/btr167

  2. Lister et al. 2009 - "Human DNA methylomes at base resolution show widespread epigenomic differences" (Nature, ~5,000 citations) DOI: 10.1038/nature08514

  3. Schultz et al. 2015 - "Human body epigenome maps reveal noncanonical DNA methylation variation" (Nature, ~1,500 citations) DOI: 10.1038/nature14248

  4. Pedersen et al. 2014 - "Fast and accurate alignment of long bisulfite-seq reads" arXiv:1401.1129 (bwa-meth)

  5. Amemiya et al. 2019 - "The ENCODE Blacklist" (Scientific Reports, ~1,372 citations) DOI: 10.1038/s41598-019-45839-z

Execution

--reads and --genome_dir are both required; the workflow stops before the first task if either is missing. --genome_dir is a Bismark genome folder — the output of bismark_genome_preparation, which must still contain the genome .fa, because MethylDackel reads it from there.

Quick Start (local, Docker)

nextflow run scripts/main.nf -profile local \
    --reads '/data/fastq/*_R{1,2}.fastq.gz' \
    --genome_dir /ref/bismark_index \
    --min_coverage 5 \
    --outdir results/ \
    -resume

SLURM HPC

nextflow run scripts/main.nf -profile slurm \
    --container /path/to/pipeline-wgbs.sif \
    --slurm_queue normal \
    --reads '/data/fastq/*_R{1,2}.fastq.gz' \
    --genome_dir /ref/bismark_index \
    --outdir results/ \
    -resume

Cloud

# Google Cloud Batch
nextflow run scripts/main.nf -profile gcp \
    --container us-docker.pkg.dev/<project>/<repo>/pipeline-wgbs:1.0.0 \
    --gcp_project <project> \
    --gcp_workdir gs://<bucket>/work \
    --reads 'gs://<bucket>/fastq/*_R{1,2}.fastq.gz' \
    --genome_dir gs://<bucket>/ref/bismark_index \
    --outdir gs://<bucket>/results

# AWS Batch
nextflow run scripts/main.nf -profile aws \
    --container <account>.dkr.ecr.<region>.amazonaws.com/pipeline-wgbs:1.0.0 \
    --aws_queue <job-queue> \
    --aws_workdir s3://<bucket>/work \
    --reads 's3://<bucket>/fastq/*_R{1,2}.fastq.gz' \
    --genome_dir s3://<bucket>/ref/bismark_index \
    --outdir s3://<bucket>/results

--outdir only sets where results are published; Google Batch and AWS Batch stage every task through the work directory, and the workflow stops with an error if it or the project/queue is missing.

Resource Requirements

Step CPUs RAM Time (30x human)
FastQC 2 4 GB <1 hour
Trim Galore 4 4 GB 1-2 hours
Bismark align 8 48 GB 8-16 hours
Deduplication 2 16 GB 1-2 hours
Sort + index 4 8 GB 1-2 hours
MethylDackel (mbias, extract) 2, 4 8 GB 1-2 hours
Total 8 48 GB 12-24 hours

Every process asks for memory { N.GB * task.attempt }, so a task killed for running out of memory is retried with more: the second attempt gets twice the figure in the table, the third three times it, bounded by --max_memory. nextflow.config scales the time the same way for BISMARK_ALIGN, DEDUPLICATE and METHYLDACKEL_EXTRACT, bounded by --max_time; the other processes declare no time limit. A task is retried only for exit codes 130-145 and 104 (killed for exceeding a limit); any other failure stops the run.

Pipeline Parameters

Parameter Default Description
--reads required Glob matching the paired FASTQ files, e.g. '/data/fastq/*_R{1,2}.fastq.gz'. Quote it
--genome_dir required Bismark genome folder (bismark_genome_preparation output, including the genome .fa)
--outdir ./results Directory results are published to
--min_coverage 5 Minimum read count a site must reach to appear in the bedMethyl files. The MethylDackel bedGraphs are written unfiltered
--merge_context true Merge the two strands of each CpG/CHG into one record (MethylDackel --mergeContext)
--skip_dedup false Skip deduplicate_bismark; the sorted BAM is then the raw alignment

Infrastructure parameters (nextflow.config)

Parameter Default Description
--container encode-toolkit/pipeline-wgbs:1.0.0 Image built from scripts/Dockerfile. Pass a registry image for gcp/aws, or a .sif file for slurm
--max_cpus, --max_memory, --max_time 16, 64.GB, 48.h Upper bounds applied to every process
--slurm_queue, --slurm_account normal, none SLURM partition and account
--gcp_project, --gcp_workdir none (both required for -profile gcp) Google Cloud project and gs:// work directory
--gcp_location, --gcp_disk us-central1, 200.GB Google Batch region and per-task disk
--aws_queue, --aws_workdir none (both required for -profile aws) AWS Batch job queue and s3:// work directory
--aws_region, --aws_cli_path us-east-1, /home/ec2-user/miniconda/bin/aws AWS region, and the AWS CLI path inside the Batch AMI

Notes on what the workflow does and does not do:

  • Aligner: Bismark with Bowtie2. bwa-meth is described in references/02-bismark-alignment.md as a manual alternative; it is not an option of this workflow and is not in the image.
  • Deduplication: deduplicate_bismark. Picard is not installed and is not used.
  • BAM filtering: there is no MAPQ or flag filtering step. The BAM handed to MethylDackel is the Bismark output, deduplicated and sorted. references/03-dedup-filtering.md gives the manual filtering commands if you want them.
  • Overlapping mates: MethylDackel never counts both mates of an overlapping read pair, so there is no switch for it. --merge_context is a separate choice about per-CpG versus per-cytosine output.
  • Read-position trimming at extraction: none. MethylDackel extract is called without --nOT/--nOB, because --clip_R2 10 at the trimming step already removes the end-repair bias. See the M-bias pitfall below.
  • Bisulfite conversion rate: not computed by the workflow. Estimate it from the CHH methylation percentage in the Bismark alignment report, or align a lambda/pUC19 spike-in separately when the sample carries real non-CpG methylation (ESCs, neurons). references/05-qc-metrics.md has both commands.

Output Files

results/
  fastqc/                      # FastQC on the raw reads
  trim_galore/                 # trimmed reads, trimming reports, and FastQC on the trimmed reads
  bismark/
    alignments/
      {sample}.sorted.bam      # final BAM: deduplicated unless --skip_dedup, sorted
      {sample}.sorted.bam.bai
      *_PE_report.txt          # Bismark alignment report (mapping rate, context methylation)
    dedup_reports/
      *.deduplication_report.txt
    mbias/
      {sample}_mbias_*.svg     # M-bias plots, one per strand
      {sample}_mbias_report.txt  # MethylDackel's suggested inclusion bounds
    methylation/
      {sample}_CpG.bedGraph    # MethylDackel output, every covered cytosine/CpG
      {sample}_CHG.bedGraph
      {sample}_CHH.bedGraph
      {sample}.CpG.bedMethyl.gz (+ .tbi)   # primary output, filtered by --min_coverage
      {sample}.CHG.bedMethyl.gz (+ .tbi)   # non-CpG contexts
      {sample}.CHH.bedMethyl.gz (+ .tbi)
  coverage/
    {sample}.coverage_stats.txt
  multiqc/
    multiqc_report.html
  pipeline_info/
    timeline.html, report.html, trace.txt  # Nextflow execution reports

Note the naming: the MethylDackel bedGraphs use an underscore before the context ({sample}_CpG.bedGraph), the bedMethyl files a dot ({sample}.CpG.bedMethyl.gz).

bedMethyl Format

The primary output is per-CpG methylation in the ENCODE bedMethyl layout (https://www.encodeproject.org/data-standards/wgbs/):

chr1  10468  10470  .  12  .  10468  10470  0,0,0  12  83

Columns: chr, start, end, name (.), score, strand, thickStart, thickEnd, colour, coverage, percent methylated. The score in column 5 is the read count capped at 1000, the strand in column 6 is . because MethylDackel's bedGraph carries no strand, and column 11 is an integer percentage. Sites below --min_coverage are dropped.

Coverage Statistics

coverage/{sample}.coverage_stats.txt is computed from the unfiltered {sample}_CpG.bedGraph, so it describes every covered site, not just the reported ones. It has five lines — this is a run at the default --min_coverage 5:

Covered CpGs (>=1x): 27184023
Mean coverage of covered CpGs: 12.4
Covered CpGs >=5x: 22903511 (84.3%)
Covered CpGs >=10x: 16992841 (62.5%)
Covered CpGs >=5x (--min_coverage, kept in bedMethyl): 22903511 (84.3%)

The 5x and 10x lines are fixed thresholds and do not follow --min_coverage. The last line does, and it is the one that describes what actually reached the bedMethyl files: at the default it repeats the >=5x line, with --min_coverage 10 it would repeat the >=10x line, and at any other value it stands on its own. All the percentages are of covered CpGs, not of all CpGs in the genome — the workflow never counts genomic CpGs that got zero reads. With --merge_context false the records are per cytosine rather than per CpG.

QC Thresholds (ENCODE Standards)

Metric Pass Warning Fail Source
Mapping rate >70% 50-70% <50% bismark/alignments/*_PE_report.txt
Duplication rate <30% 30-50% >50% bismark/dedup_reports/*.deduplication_report.txt
Mean coverage of covered CpGs >10x 5-10x <5x coverage/{sample}.coverage_stats.txt
Covered CpGs reaching >=5x >80% 60-80% <60% coverage/{sample}.coverage_stats.txt
Bisulfite conversion rate ≥98% 95-98% <95% External; see references/05-qc-metrics.md
Lambda spike-in conversion ≥98% 95-98% <95% External; requires a separate alignment

Critical Pitfalls

RRBS vs WGBS

RRBS (Reduced Representation) uses MspI digestion and covers ~10% of CpGs. WGBS covers the full genome. These are DIFFERENT protocols:

  • RRBS: this workflow is not set up for it. Deduplication can be skipped (--skip_dedup true), but the trimming is WGBS-specific and hardcoded (--clip_R2 10 --three_prime_clip_R1 1), there is no --rrbs switch, and the workflow re-trims whatever FASTQs it is given. Run RRBS trimming and alignment by hand — references/01-qc-trimming.md has the command
  • WGBS: full dedup required, standard Trim Galore settings
  • Never mix RRBS and WGBS data in the same analysis

Strand-Specific vs Merged CpG

Bismark reports methylation per strand by default. For most analyses, merge complementary CpG strands:

  • Forward C at position N and reverse G at position N+1 are the same CpG
  • MethylDackel --mergeContext handles this automatically
  • --merge_context true is the workflow default; set it to false only when you need strand-specific data

Incomplete Bisulfite Conversion

Conversion artifacts produce false methylation calls:

  • Always include lambda phage or pUC19 spike-in DNA
  • Unmethylated spike-in should show ≥98% conversion
  • The workflow does not measure this. Align the spike-in separately, or read the CHH methylation percentage out of the Bismark report, before trusting the calls

M-bias Plots

MethylDackel mbias runs on every sample and writes plots plus bismark/mbias/{sample}_mbias_report.txt, which captures MethylDackel's suggested inclusion bounds. Extraction itself excludes no read positions:

  • End-repair artifacts cause elevated methylation at read ends. The 5' end-repair bias of read 2 is already removed at the trimming step by --clip_R2 10
  • If the plots still show bias, re-run MethylDackel extract manually with --OT/--OB set to the suggested bounds. Note the argument order: --OT A,B,C,D includes positions A-B on read 1 and C-D on read 2, and the matching --nOT a,b,c,d excludes a bases from the start of read 1, b from its end, c from the start of read 2 and d from its end
  • --maxDepth is not an option of MethylDackel 0.6.1 and must not be passed

Low Coverage Regions

Regions with <5x coverage have unreliable methylation estimates:

  • The bedMethyl files are filtered to --min_coverage (default 5); the bedGraphs are not
  • For differential methylation analysis, consider --min_coverage 10
  • Report the >=5x and >=10x fractions from coverage/{sample}.coverage_stats.txt. Those two thresholds are fixed in the workflow and do not follow --min_coverage; the last line of the file is the one that does, so quote it too whenever the run used a value other than 5

Provenance Integration

After pipeline completion, log all outputs:

# Log derived bedMethyl files
encode_log_derived_file(
    file_path="/results/bismark/methylation/sample1.CpG.bedMethyl.gz",
    source_accessions=["ENCSR...", "ENCFF..."],
    description="CpG methylation calls from ENCODE WGBS pipeline",
    file_type="bedMethyl",
    tool_used="Bismark 0.24.2 + MethylDackel 0.6.1",
    parameters="bismark --genome /ref -1 R1.fq.gz -2 R2.fq.gz; MethylDackel extract --mergeContext --CHG --CHH; bedMethyl filtered at --min_coverage 5"
)

Reference Files

Detailed step-by-step documentation is provided in the references/ directory:

  1. 01-qc-trimming.md -- Bisulfite-specific adapter trimming with Trim Galore
  2. 02-bismark-alignment.md -- Bismark alignment and the bwa-meth manual alternative
  3. 03-dedup-filtering.md -- Deduplication, and manual BAM filtering the workflow skips
  4. 04-methylation-calling.md -- MethylDackel extraction and bedMethyl generation
  5. 05-qc-metrics.md -- Coverage stats, M-bias, and manual conversion-rate checks

Walkthrough: Processing ENCODE WGBS from FASTQ to Methylation Calls

Goal: Process whole-genome bisulfite sequencing FASTQ files through the ENCODE pipeline to generate per-CpG methylation calls for epigenomic analysis. Context: WGBS requires bisulfite-aware alignment (Bismark) and per-CpG methylation extraction (MethylDackel), with ≥98% bisulfite conversion expected of the library.

Step 1: Find WGBS experiment

encode_get_experiment(accession="ENCSR765JPC")

Expected output:

{
  "accession": "ENCSR765JPC",
  "assay_title": "WGBS",
  "biosample_summary": "liver tissue male adult (54 years)",
  "assembly": ["GRCh38"],
  "bio_replicate_count": 2,
  "tech_replicate_count": 2,
  "status": "released"
}

Step 2: List FASTQ files

encode_list_files(experiment_accession="ENCSR765JPC", file_format="fastq")

Expected output (a JSON array of file records; fields abridged):

[
  {"accession": "ENCFF300BS1", "file_format": "fastq", "output_type": "reads", "file_size_human": "45.0 GB", "biological_replicates": [1], "status": "released"},
  {"accession": "ENCFF301BS2", "file_format": "fastq", "output_type": "reads", "file_size_human": "46.0 GB", "biological_replicates": [1], "status": "released"}
]

Interpretation: WGBS files are very large (~45GB per read file). Ensure adequate storage (>500GB for processing).

Step 3: Download and name the FASTQs so a read-pair glob can find them

encode_download_files(file_accessions=["ENCFF300BS1", "ENCFF301BS2"], download_dir="/data/wgbs/fastq")

ENCODE names every FASTQ after its accession (ENCFF300BS1.fastq.gz), with no _R1/_R2 in the name, so the two files of a pair share no prefix and the --reads glob cannot pair them. Link them into the shape the glob expects. Which mate an accession is comes from the ENCODE file record on encodeproject.org, which carries paired_end (1 or 2) and paired_with; the MCP file tools do not return those two fields:

cd /data/wgbs/fastq
ln -s ENCFF300BS1.fastq.gz liver_rep1_R1.fastq.gz
ln -s ENCFF301BS2.fastq.gz liver_rep1_R2.fastq.gz

Step 4: Run the WGBS pipeline

nextflow run scripts/main.nf -profile local \
    --reads '/data/wgbs/fastq/liver_*_R{1,2}.fastq.gz' \
    --genome_dir /ref/bismark_index \
    --min_coverage 5 \
    --outdir results/ \
    -resume

Key pipeline steps:

  1. FastQC on the raw reads, then adapter/quality trimming with Trim Galore (which also runs FastQC on the trimmed reads)
  2. Bisulfite-aware alignment (Bismark with Bowtie2)
  3. Deduplication (deduplicate_bismark), then sort and index
  4. M-bias assessment and methylation extraction (MethylDackel), then conversion to bedMethyl
  5. CpG coverage statistics
  6. MultiQC aggregation

Step 5: Validate output quality

Metric Threshold Purpose
Mapping rate > 70% Alignment success (Bismark report)
Duplication rate < 30% Library complexity (dedup report)
Covered CpGs at >= 10x Enough for DMR calling Statistical power (coverage stats)
Bisulfite conversion >= 98% Library quality; measured outside this workflow

Step 6: Identify differentially methylated regions

Feed per-CpG methylation into -> methylation-aggregation for cross-tissue comparison and HMR/UMR/PMD identification.

Integration with downstream skills

  • Per-CpG methylation files feed into -> methylation-aggregation for cross-tissue atlas
  • DMRs feed into -> peak-annotation for nearest gene assignment
  • Methylation at regulatory elements connects to -> regulatory-elements
  • CpG variant methylation integrates with -> variant-annotation
  • Pipeline provenance logged by -> data-provenance

Code Examples

1. Find WGBS data for methylation analysis

encode_search_experiments(
  assay_title="WGBS",
  organ="brain"
)

Expected output:

{
  "results": [
    {
      "accession": "ENCSR321BRN",
      "assay_title": "WGBS",
      "biosample_summary": "brain tissue female adult (53 years)",
      "organ": "brain",
      "status": "released"
    }
  ],
  "total": 6,
  "limit": 25,
  "offset": 0,
  "has_more": false,
  "next_offset": null
}

2. Download processed methylation files

encode_search_files(
  assay_title="WGBS",
  organ="brain",
  file_format="bed",
  output_type="methylation state at CpG",
  assembly="GRCh38"
)

Expected output (fields abridged):

{
  "results": [
    {
      "accession": "ENCFF567MET",
      "file_format": "bed",
      "output_type": "methylation state at CpG",
      "assembly": "GRCh38",
      "file_size": 886144860,
      "file_size_human": "845.1 MB",
      "experiment_accession": "ENCSR321BRN"
    }
  ],
  "total": 3,
  "limit": 25,
  "offset": 0,
  "has_more": false,
  "next_offset": null
}

Integration

This skill produces... Feed into... Purpose
Per-CpG methylation (bedMethyl) methylation-aggregation Cross-tissue methylation atlas
Per-CpG methylation (bedMethyl) visualization-workflow Display methylation in a genome browser (tabix-indexed BED; the workflow writes no bigWig)
Differentially methylated regions peak-annotation Assign DMRs to nearest genes
Methylation at regulatory sites regulatory-elements Correlate methylation with cCRE activity
CpG methylation near variants variant-annotation Annotate variants affecting CpG methylation
Coverage and mapping metrics quality-assessment Validate coverage and alignment against ENCODE standards
Pipeline parameters data-provenance Record Bismark/MethylDackel versions
Methylation at promoters gtex-expression Correlate promoter methylation with gene expression

Related Skills

  • pipeline-guide -- Parent skill with compute resource assessment and cloud setup
  • methylation-aggregation -- Aggregate methylation data across samples/tissues
  • quality-assessment -- Evaluate pipeline output quality metrics
  • data-provenance -- Track all pipeline inputs, outputs, and parameters
  • download-encode -- Download ENCODE WGBS FASTQ files for pipeline input
  • publication-trust -- Verify literature claims backing analytical decisions

Presenting Results

When reporting WGBS pipeline results:

  • Mapping and duplication: Report the mapping rate from bismark/alignments/*_PE_report.txt (>70% expected) and the duplication rate from bismark/dedup_reports/ (<30% expected)
  • CpG coverage depth: Report the mean coverage of covered CpGs, the percentage reaching >=5x and >=10x, and the last line's --min_coverage count from coverage/{sample}.coverage_stats.txt, and state that these are percentages of covered CpGs rather than of all genomic CpGs
  • Global methylation level: Report the genome-wide average CpG methylation percentage and note any non-CpG (CHG/CHH) methylation if relevant to the tissue. Both come from the Bismark report or from the bedGraphs
  • bedMethyl output paths: Provide paths to the CpG bedMethyl file and the CHG/CHH context files, and state the --min_coverage value they were filtered at
  • M-bias assessment: No read positions are excluded at extraction. Report MethylDackel's suggested bounds from bismark/mbias/{sample}_mbias_report.txt, and say whether a manual re-extraction with --OT/--OB was done
  • Bisulfite conversion rate: This workflow does not compute it. If a lambda/pUC19 spike-in was aligned separately, or the CHH percentage was used as a proxy, report the number and say which method produced it (≥98% pass, 95-98% warning, <95% fail)
  • Output summary: Report covered CpG sites, sites passing the coverage filter, and the MultiQC report at multiqc/multiqc_report.html
  • Next steps: Suggest methylation-aggregation for cross-sample averaging and HMR/UMR/PMD identification

For the request: "$ARGUMENTS"

Files (encode-toolkit)
  • references
    • 01-qc-trimming.md 3 KB
      # QC and Trimming for WGBS Data
      
      Bisulfite-converted reads require specialized trimming to handle adapter
      contamination and conversion-induced sequence biases.
      
      ## Pre-Trimming QC with FastQC
      
      ```bash
      fastqc --threads 4 --outdir fastqc_raw/ sample_R1.fastq.gz sample_R2.fastq.gz
      ```
      
      Key checks before trimming:
      - Per-base sequence quality (expect Phred >28 across most positions)
      - Adapter content (Illumina universal adapter is common)
      - Per-base sequence content (bisulfite conversion causes C->T skew -- this is EXPECTED)
      - Overrepresented sequences
      
      **Important**: FastQC will flag per-base sequence content as FAIL for bisulfite data.
      This is normal and expected because unmethylated C is converted to T.
      
      ## Adapter Trimming with Trim Galore
      
      Trim Galore auto-detects Illumina adapters and applies bisulfite-aware trimming. This is
      the command the workflow runs, with `--cores` set from the process CPU count:
      
      ```bash
      trim_galore \
          --paired \
          --quality 20 \
          --phred33 \
          --length 36 \
          --cores 4 \
          --clip_R2 10 \
          --three_prime_clip_R1 1 \
          --fastqc \
          sample_R1.fastq.gz \
          sample_R2.fastq.gz
      ```
      
      The trimmed reads, the trimming reports and the FastQC reports that `--fastqc` produces
      for the trimmed reads are all published to `trim_galore/`, and the trimming and trimmed-read
      FastQC reports are fed to MultiQC. FastQC on the *raw* reads is a separate process and
      lands in `fastqc/`.
      
      ### Parameter Rationale
      
      | Parameter | Value | Reason |
      |-----------|-------|--------|
      | `--quality 20` | Phred 20 | Standard quality cutoff |
      | `--length 36` | 36 bp | Minimum length after trimming |
      | `--clip_R2 10` | 10 bp | Remove end-repair artifacts from read 2 (5' end) |
      | `--three_prime_clip_R1 1` | 1 bp | Remove filled-in C from end repair |
      | `--cores 4` | 4 | Parallel processing (Trim Galore uses 3x cores internally) |
      
      ### RRBS-Specific Trimming (not reachable from this workflow)
      
      The trimming above is hardcoded and WGBS-specific: there is no `--rrbs` switch and no
      parameter that changes the clip settings, and the workflow re-trims whatever it is given.
      For RRBS data, run Trim Galore by hand with the `--rrbs` flag to handle MspI-digested
      fragments, and then run Bismark and MethylDackel on the result yourself rather than through
      this workflow:
      
      ```bash
      trim_galore \
          --paired \
          --rrbs \
          --quality 20 \
          --length 36 \
          --fastqc \
          --cores 4 \
          --output_dir trim_galore/ \
          sample_R1.fastq.gz \
          sample_R2.fastq.gz
      ```
      
      The `--rrbs` flag removes 2 bp from the 3' end of reads that were filled in
      during end-repair of MspI-digested fragments (CCGG sites).
      
      ## Post-Trimming QC
      
      Trim Galore produces a trimming report with:
      - Total reads processed
      - Reads with adapter detected
      - Reads too short after trimming
      - Quality-trimmed bases
      
      Verify in the report:
      - Adapter detection rate should be >0% (if 0%, adapters may not be standard)
      - Reads passing filter should be >90%
      - Read length distribution should be reasonable (median >50 bp for 150 bp reads)
      
    • 02-bismark-alignment.md 4.3 KB
      # Bismark Alignment for WGBS
      
      Bisulfite-converted reads require a specialized aligner that accounts for
      C-to-T conversion. Bismark handles this by aligning to both C-to-T and G-to-A
      converted genomes simultaneously.
      
      ## Genome Preparation (one-time prep, outside the workflow)
      
      Build the bisulfite-converted genome index. The directory you prepare is what you pass as
      `--genome_dir`, and it must still contain the genome `.fa`, because MethylDackel reads the
      FASTA from the same directory later.
      
      ```bash
      bismark_genome_preparation \
          --bowtie2 \
          --parallel 4 \
          --verbose \
          /ref/genome/
      ```
      
      This creates two converted genomes:
      - C-to-T converted (for original top strand and complementary to bottom)
      - G-to-A converted (for original bottom strand and complementary to top)
      
      Requires approximately 12 GB disk space for human genome.
      
      ## Bismark Alignment
      
      This is what the workflow runs, in the task directory:
      
      ```bash
      mkdir -p tmp
      bismark \
          --genome /ref/genome/ \
          --bowtie2 \
          --parallel 4 \
          --score_min L,0,-0.2 \
          --no_mixed \
          --no_discordant \
          --maxins 1000 \
          --temp_dir $PWD/tmp \
          -1 sample_R1_val_1.fq.gz \
          -2 sample_R2_val_2.fq.gz
      ```
      
      Of the two outputs, only the `*_PE_report.txt` is published (to
      `bismark/alignments/`). The raw unsorted BAM stays in the work directory; what reaches
      `bismark/alignments/<sample>.sorted.bam` is the deduplicated, coordinate-sorted BAM from
      the later step.
      
      ### Key Parameters
      
      | Parameter | Value | Reason |
      |-----------|-------|--------|
      | `--parallel 4` | 4 instances | Each uses 2 Bowtie2 threads = 8 total threads |
      | `--score_min L,0,-0.2` | Linear penalty | ENCODE default; tolerates bisulfite mismatches |
      | `--no_mixed` | Discard | Both mates must align |
      | `--no_discordant` | Discard | Mates must be properly paired |
      | `--maxins 1000` | 1000 bp | Maximum insert size for paired reads |
      
      ### Memory Requirements
      
      Bismark parallel mode runs several Bowtie2 instances, each holding its own copy of a
      converted genome index. `nextflow.config` allocates 48 GB to `BISMARK_ALIGN` with
      `--parallel 4` on a human genome, and multiplies it by the attempt number on a retry,
      capped by `--max_memory` (64 GB by default, so a retry gets 64 GB). Budget for the 48 GB
      figure rather than a per-instance estimate.
      
      ## Alternative: bwa-meth
      
      bwa-meth is not part of the bundled workflow or container image. The commands below are for
      running it by hand when Bismark is too slow or memory-hungry for your genome.
      
      bwa-meth is faster than Bismark for large genomes and uses less memory:
      
      ```bash
      # Index genome (one-time)
      bwameth.py index /ref/genome/genome.fa
      
      # Align
      bwameth.py \
          --threads 8 \
          --reference /ref/genome/genome.fa \
          sample_R1_trimmed.fq.gz \
          sample_R2_trimmed.fq.gz \
          | samtools sort -@ 4 -o sample_bwameth.bam
      
      samtools index sample_bwameth.bam
      ```
      
      ### Bismark vs bwa-meth Comparison
      
      | Feature | Bismark | bwa-meth |
      |---------|---------|----------|
      | Speed | Slower (~2x) | Faster |
      | RAM | 48 GB allocated (parallel) | ~16 GB |
      | Accuracy | Gold standard | Comparable |
      | This workflow | The only aligner it runs | Not available; manual only |
      | Methylation calling | Built-in | Requires MethylDackel |
      
      Recommendation: Use Bismark for ENCODE compatibility. Use bwa-meth outside this workflow
      when processing many samples and speed is critical.
      
      ## Lambda/pUC19 Spike-in Alignment (not run by this workflow)
      
      If spike-in DNA was used, align to the spike-in genome by hand to measure the conversion
      rate. The workflow does not do this and reports no conversion rate:
      
      ```bash
      bismark \
          --genome /ref/lambda/ \
          --bowtie2 \
          -1 sample_R1_trimmed.fq.gz \
          -2 sample_R2_trimmed.fq.gz \
          --output_dir lambda_out/ \
          --unmapped
      ```
      
      The lambda genome is fully unmethylated, so any detected methylation represents
      incomplete bisulfite conversion. Expect conversion rate ≥98%.
      
      ## Alignment QC Checks
      
      After alignment, verify in the Bismark report (`bismark/alignments/*_PE_report.txt`,
      also parsed into the MultiQC report):
      - **Mapping efficiency**: >70% for WGBS (lower than standard WGS due to conversion)
      - **Unique alignments**: Should dominate over multimappers
      - **C methylated in CpG context**: Typically 70-85% for mammalian somatic tissue
      - **C methylated in CHG context**: Should be <1% in somatic tissue (>5% in plants/ESCs)
      - **C methylated in CHH context**: Should be <1% in somatic tissue
      
    • 03-dedup-filtering.md 4 KB
      # Deduplication and Filtering for WGBS
      
      PCR duplicates inflate coverage estimates and bias methylation calls.
      Deduplication is essential for WGBS but must NOT be used for RRBS.
      
      ## Bismark Deduplication
      
      Bismark provides its own deduplication tool optimized for bisulfite data, and this is what
      the workflow runs (skipped with `--skip_dedup`):
      
      ```bash
      deduplicate_bismark \
          --bam \
          --paired \
          bismark_out/sample_pe.bam
      ```
      
      Bismark deduplication identifies duplicates by their alignment positions on
      both strands, accounting for bisulfite conversion. This is preferred over
      Picard for bisulfite data; Picard is not installed in the image.
      
      The deduplicated BAM is then sorted and indexed with samtools and published as
      `bismark/alignments/<sample>.sorted.bam` (+ `.bai`). The deduplication report goes to
      `bismark/dedup_reports/`.
      
      ### Expected Duplication Rates
      
      | Library Quality | Duplication Rate | Action |
      |----------------|------------------|--------|
      | Good | <20% | Proceed |
      | Acceptable | 20-40% | Proceed with caution |
      | Poor | 40-60% | Consider resequencing |
      | Very poor | >60% | Library failed -- redo |
      
      ## Manual Alternative: Picard MarkDuplicates (not run by this workflow)
      
      Picard is neither in the container image nor used by the workflow. If you align with
      bwa-meth by hand (`02-bismark-alignment.md`), which has no built-in dedup, install Picard
      separately and run:
      
      ```bash
      picard MarkDuplicates \
          INPUT=sample_bwameth_sorted.bam \
          OUTPUT=sample_dedup.bam \
          METRICS_FILE=sample_dup_metrics.txt \
          REMOVE_DUPLICATES=true \
          VALIDATION_STRINGENCY=LENIENT \
          ASSUME_SORTED=true
      ```
      
      ## Optional Manual BAM Filtering (not run by this workflow)
      
      The workflow hands MethylDackel the deduplicated, sorted BAM with no MAPQ or flag
      filtering. If you want a filtered BAM, produce it yourself from the published
      `<sample>.sorted.bam` and point MethylDackel at that instead:
      
      ```bash
      samtools view -b -h \
          -q 10 \
          -F 1804 \
          -f 2 \
          bismark/alignments/sample.sorted.bam \
          | samtools sort -@ 4 -o sample_filtered.bam
      
      samtools index sample_filtered.bam
      ```
      
      ### Filter Flag Explanation
      
      | Flag | Binary | Meaning |
      |------|--------|---------|
      | `-q 10` | MAPQ >= 10 | Minimum mapping quality |
      | `-F 4` | 0x4 | Remove unmapped reads |
      | `-F 8` | 0x8 | Remove reads whose mate is unmapped |
      | `-F 256` | 0x100 | Remove secondary alignments |
      | `-F 512` | 0x200 | Remove reads failing QC |
      | `-F 1024` | 0x400 | Remove PCR duplicates |
      | `-f 2` | 0x2 | Keep only properly paired |
      
      Combined: `-F 1804` = 4 + 8 + 256 + 512 + 1024, removing unmapped, mate-unmapped,
      secondary, QC-fail and duplicate reads.
      
      ## RRBS: Skip Deduplication
      
      For RRBS libraries, MspI digestion creates identical fragment starts at cut
      sites. These are NOT PCR duplicates and must be retained. The trimming in this workflow is
      WGBS-specific (`01-qc-trimming.md`), so RRBS is better processed by hand; if you run it
      through the workflow anyway, at least set `--skip_dedup true`.
      
      ```bash
      # Do NOT run deduplication for RRBS.
      # To filter by hand instead, drop the duplicate bit from the mask (780 = 4+8+256+512):
      samtools view -b -h -q 10 -F 780 -f 2 sample.bam \
          | samtools sort -@ 4 -o sample_filtered.bam
      ```
      
      ## Coverage Statistics
      
      The workflow computes its coverage statistics from the CpG bedGraph, not from the BAM;
      see `05-qc-metrics.md`. The commands below are alternatives you can run by hand on the
      published BAM. `bedtools` is not in the container image — it ships with the conda
      environment instead.
      
      ```bash
      samtools depth -a bismark/alignments/sample.sorted.bam \
          | awk '{sum+=$3; n++} END {print "Mean coverage:", sum/n}'
      
      samtools flagstat bismark/alignments/sample.sorted.bam > sample_flagstat.txt
      
      # CpG-specific coverage: reads overlapping each CpG (last column), as a histogram.
      # The BED goes in -a so the output is text; with a BAM in -a, bedtools writes BAM.
      bedtools coverage \
          -a /ref/CpG_sites.bed \
          -b bismark/alignments/sample.sorted.bam \
          -counts \
          | awk '{print $NF}' | sort -n | uniq -c
      ```
      
    • 04-methylation-calling.md 5.6 KB
      # Methylation Calling with MethylDackel
      
      MethylDackel (formerly PileOMeth) extracts per-CpG methylation levels from
      bisulfite-aligned BAM files. This workflow then converts its bedGraph output to the
      ENCODE bedMethyl layout (https://www.encodeproject.org/data-standards/wgbs/).
      
      ## M-bias Assessment (Run First)
      
      The workflow runs `MethylDackel mbias` on every sample before extraction:
      
      ```bash
      MethylDackel mbias \
          --CHG --CHH \
          /ref/genome/genome.fa \
          sample.sorted.bam \
          sample_mbias > sample_mbias_report.txt 2>&1
      ```
      
      This produces SVG plots showing methylation level by read position, and the redirected
      text output carries MethylDackel's suggested inclusion bounds. Both land in
      `bismark/mbias/`. Look for:
      - Elevated methylation at the 5' end of read 2 (end-repair artifact). The workflow already
        removes this at trimming with `--clip_R2 10`, so it should be gone
      - Irregular methylation at read ends (adapter contamination)
      
      ## Methylation Extraction
      
      This is exactly what the workflow runs (`--mergeContext` is dropped when
      `--merge_context false`):
      
      ```bash
      MethylDackel extract \
          --mergeContext \
          --CHG --CHH \
          --opref sample \
          /ref/genome/genome.fa \
          sample.sorted.bam
      ```
      
      ### Key Parameters
      
      | Parameter | Value | Reason |
      |-----------|-------|--------|
      | `--mergeContext` | Enabled by `--merge_context true` | Merge forward/reverse strand CpG data into one record |
      | `--CHG --CHH` | Enabled | Also extract non-CpG methylation (useful for ESCs, neurons) |
      | `--opref sample` | Output prefix | Names the three bedGraphs |
      
      ### Parameters the Workflow Deliberately Does Not Pass
      
      | Parameter | Why not |
      |-----------|---------|
      | `--minDepth` | Extraction is unfiltered so the coverage statistics can see every covered site. The `--min_coverage` cut is applied when the bedMethyl files are written |
      | `--maxDepth` | Not an option in MethylDackel 0.6.1. `getopt_long` rejects the long form and `extract` exits with a usage error. Do not pass it |
      | `--nOT` / `--nOB` | The 5' end-repair bias of read 2 is removed at trimming (`--clip_R2 10`), so no read positions are excluded here |
      
      ### How `--OT`/`--nOT` Arguments Are Ordered
      
      Getting this wrong silently trims the wrong end. From the MethylDackel 0.6.1 help,
      `--OT A,B,C,D` means "include calls at positions from A through B on read #1 and C
      through D on read #2". The `--nOT a,b,c,d` form is the complement and *excludes*:
      
      | Slot | Meaning |
      |------|---------|
      | 1 | bases from the start (5') of read 1 |
      | 2 | bases from the end (3') of read 1 |
      | 3 | bases from the start (5') of read 2 |
      | 4 | bases from the end (3') of read 2 |
      
      So `--nOT 0,0,0,10` trims read 2's **3'** end, not its 5' end; read 2's 5' end is
      `--nOT 0,0,10,0`. `--nOB 0,10,0,0` trims read 1's 3' end. If the M-bias plots still show
      a problem, re-extract by hand with the bounds the mbias report suggests.
      
      ### Context-Specific Output Files
      
      MethylDackel produces one bedGraph per context, named from `--opref` with an underscore.
      They are published to `bismark/methylation/` and hold every covered site:
      
      - `<sample>_CpG.bedGraph` -- CpG methylation (primary)
      - `<sample>_CHG.bedGraph` -- CHG methylation (non-CpG)
      - `<sample>_CHH.bedGraph` -- CHH methylation (non-CpG)
      
      Columns are chrom, start, end, methylation percentage, methylated read count,
      unmethylated read count, and the file starts with a `track` header line.
      
      ## Convert to bedMethyl Format
      
      The workflow converts each context with this awk, then sorts, compresses and indexes:
      
      ```bash
      for context in CpG CHG CHH; do
          awk -v min_cov=5 'BEGIN {OFS="\t"} !/^track/ {
              cov = $5 + $6
              if (cov == 0 || cov < min_cov) next
              score = (cov > 1000) ? 1000 : cov
              print $1, $2, $3, ".", score, ".", $2, $3, "0,0,0", cov, int(($5 / cov) * 100 + 0.5)
          }' sample_${context}.bedGraph \
              | sort -k1,1 -k2,2n \
              | bgzip > sample.${context}.bedMethyl.gz
      
          tabix -p bed sample.${context}.bedMethyl.gz
      done
      ```
      
      Four details matter and are easy to get wrong:
      
      - **`!/^track/`** skips MethylDackel's header line. Without it the header is parsed as data.
      - **Column 5 (score)** is the read count capped at 1000, per the ENCODE definition — not
        the methylation percentage scaled by 10.
      - **Column 6 (strand)** is `.`. The MethylDackel bedGraph carries no strand, and with
        `--mergeContext` a record covers both strands of the CpG anyway.
      - **Column 11** is an integer percentage (rounded), and column 10 is the coverage.
      
      Sites below `min_cov` are dropped, which is the only place `--min_coverage` is applied.
      
      ## Per-Chromosome Extraction (Parallel, not run by this workflow)
      
      For very large BAMs you can parallelize extraction by chromosome by hand:
      
      ```bash
      for chr in $(samtools idxstats sample.sorted.bam | cut -f1 | grep -v '*'); do
          MethylDackel extract \
              --mergeContext \
              --opref "perchr/${chr}" \
              -r "${chr}" \
              /ref/genome/genome.fa \
              sample.sorted.bam &
      done
      wait
      
      # Concatenate results, dropping the per-file track headers
      cat perchr/*_CpG.bedGraph | awk '!/^track/' | sort -k1,1 -k2,2n > sample_CpG.bedGraph
      ```
      
      ## Global Methylation Summary (manual)
      
      Compute genome-wide methylation statistics from a published bedGraph:
      
      ```bash
      awk '!/^track/ {
          meth += $5; unmeth += $6; n++
      } END {
          total = meth + unmeth;
          print "Covered sites:", n;
          print "Mean methylation:", (meth/total)*100 "%";
          print "Methylated reads:", meth;
          print "Unmethylated reads:", unmeth
      }' sample_CpG.bedGraph
      ```
      
      Expected values for mammalian somatic tissue:
      - Global CpG methylation: 70-85%
      - CpG islands: 5-15% (mostly unmethylated)
      - Gene bodies: 60-80%
      - Intergenic: 75-90%
      
    • 05-qc-metrics.md 6.4 KB
      # WGBS QC Metrics and Conversion Rate Assessment
      
      Quality control for WGBS requires bisulfite-specific metrics beyond
      standard alignment QC. The most critical metric, the bisulfite conversion rate, is not
      computed by this workflow — the sections below say which commands you have to run
      yourself.
      
      ## What the Workflow Produces
      
      | Output | Contents |
      |--------|----------|
      | `bismark/alignments/*_PE_report.txt` | Mapping efficiency, and the percentage of C methylated in CpG/CHG/CHH context |
      | `bismark/dedup_reports/*.deduplication_report.txt` | Duplicate count and rate |
      | `bismark/mbias/<sample>_mbias_*.svg`, `<sample>_mbias_report.txt` | M-bias plots and MethylDackel's suggested inclusion bounds |
      | `coverage/<sample>.coverage_stats.txt` | Covered CpGs, their mean coverage, and the fraction reaching >=5x, >=10x and `--min_coverage`x |
      | `multiqc/multiqc_report.html` | Aggregated report |
      
      ## Coverage Statistics
      
      `COVERAGE_STATS` parses the unfiltered `<sample>_CpG.bedGraph`, so it sees every covered
      site rather than only the ones that pass `--min_coverage`:
      
      ```bash
      awk -v min_cov=5 '!/^track/ {
          cov = $5 + $6; sum += cov; n++;
          if (cov >= 5)       c5++;
          if (cov >= 10)      c10++;
          if (cov >= min_cov) cmin++
      } END {
          if (n == 0) { print "Covered CpGs: 0"; exit }
          printf "Covered CpGs (>=1x): %d\n", n;
          printf "Mean coverage of covered CpGs: %.1f\n", sum/n;
          printf "Covered CpGs >=5x: %d (%.1f%%)\n", c5, c5/n*100;
          printf "Covered CpGs >=10x: %d (%.1f%%)\n", c10, c10/n*100;
          printf "Covered CpGs >=%dx (--min_coverage, kept in bedMethyl): %d (%.1f%%)\n", min_cov, cmin, cmin/n*100
      }' sample_CpG.bedGraph > sample.coverage_stats.txt
      ```
      
      `min_cov` is `--min_coverage`, so the five-line file looks like this at the default of 5:
      
      ```
      Covered CpGs (>=1x): 27184023
      Mean coverage of covered CpGs: 12.4
      Covered CpGs >=5x: 22903511 (84.3%)
      Covered CpGs >=10x: 16992841 (62.5%)
      Covered CpGs >=5x (--min_coverage, kept in bedMethyl): 22903511 (84.3%)
      ```
      
      Three things to keep straight when reporting these numbers:
      
      - The 5x and 10x thresholds are fixed in the workflow. They do not follow `--min_coverage`.
      - The last line is the one that does, and it is the count that reached the bedMethyl
        files. At the default it duplicates the >=5x line; at any other `--min_coverage` it does
        not.
      - The percentages are of *covered* CpGs. A CpG that received zero reads is not in the
        bedGraph and is not counted, so this is not the genome-wide CpG completeness.
      
      With `--merge_context false` the records are per cytosine, not per CpG, and the counts
      roughly double.
      
      ## Bisulfite Conversion Rate (Lambda Spike-in, not run by this workflow)
      
      Lambda phage DNA is fully unmethylated. Any methylation detected on lambda
      represents incomplete bisulfite conversion. Run this yourself, against the trimmed reads,
      if a spike-in was included:
      
      ```bash
      # Align to lambda genome
      bismark \
          --genome /ref/lambda/ \
          --bowtie2 \
          --parallel 2 \
          -1 sample_R1_val_1.fq.gz \
          -2 sample_R2_val_2.fq.gz \
          --output_dir lambda_out/ \
          --unmapped
      
      # Extract methylation from lambda alignments
      MethylDackel extract \
          --mergeContext \
          --minDepth 1 \
          /ref/lambda/genome.fa \
          lambda_out/sample_pe.bam
      
      # Calculate conversion rate
      awk '!/^track/ {meth+=$5; unmeth+=$6} END {
          total=meth+unmeth;
          conv=(unmeth/total)*100;
          print "Conversion rate: " conv "%";
          print "Unconverted (false methylation): " (meth/total)*100 "%"
      }' lambda_CpG.bedGraph
      ```
      
      ### Conversion Rate Thresholds
      
      | Rate | Status | Action |
      |------|--------|--------|
      | >99.5% | Excellent | Proceed |
      | 99.0-99.5% | Acceptable | Proceed with note |
      | 98.0-99.0% | Warning | May inflate methylation estimates |
      | <98.0% | Fail | Do NOT use this library |
      
      ## Non-CpG Methylation as Conversion Proxy
      
      If no spike-in is available, use CHH methylation as a proxy. The Bismark alignment report
      already carries "C methylated in CHH context"; the same number can be recomputed from the
      published CHH bedGraph:
      
      ```bash
      awk '!/^track/ {meth+=$5; unmeth+=$6} END {
          print "CHH methylation: " (meth/(meth+unmeth))*100 "%"
      }' sample_CHH.bedGraph
      ```
      
      In somatic tissue, CHH methylation should be <1%. Higher values suggest
      incomplete conversion. Exception: embryonic stem cells and neurons can have
      genuine non-CpG methylation (2-5%), which is why this is a proxy rather than a
      measurement.
      
      ## Additional Manual Coverage Checks
      
      ```bash
      # Genome-wide coverage distribution from the published BAM
      samtools depth -a bismark/alignments/sample.sorted.bam | \
          awk '{cov[$3]++} END {for (c in cov) print c, cov[c]}' | \
          sort -k1,1n > coverage_distribution.txt
      
      # Mean and median coverage (needs gawk for asort)
      samtools depth -a bismark/alignments/sample.sorted.bam | \
          awk '{sum+=$3; n++; a[n]=$3; if ($3>=5) sum5++} END {
              asort(a);
              print "Mean:", sum/n;
              print "Median:", a[int(n/2)];
              print "Total bases:", n;
              print "Bases >=5x:", sum5/n*100 "%"
          }'
      ```
      
      ## Mapping Statistics
      
      The mapping efficiency in the Bismark `*_PE_report.txt` is the primary number. For a
      flag-level breakdown of the final BAM:
      
      ```bash
      samtools flagstat bismark/alignments/sample.sorted.bam > flagstat.txt
      ```
      
      Key values to extract:
      - Total reads in the final (deduplicated) BAM
      - Mapped reads (Bismark mapping efficiency >70% expected)
      - Properly paired (expect >95% of mapped)
      - Duplication rate (from the deduplication report)
      
      ## MultiQC Report
      
      The workflow runs:
      
      ```bash
      multiqc --title "ENCODE WGBS Pipeline" --filename multiqc_report --force .
      ```
      
      `--filename` is required: without it MultiQC 1.21 derives the file name from `--title`
      and writes `ENCODE-WGBS-Pipeline_multiqc_report.html`, which would not match the declared
      output.
      
      The inputs collected are the raw-read FastQC reports, the Trim Galore trimming reports,
      the FastQC reports for the trimmed reads, the Bismark `*_PE_report.txt` files and the
      `*.deduplication_report.txt` files, so the duplication rate appears in the report as well
      as in `bismark/dedup_reports/`. With `--skip_dedup` there are no deduplication reports to
      collect. Picard metrics do not exist for this pipeline.
      
      ## Summary QC Table Format
      
      Generate a per-sample summary for reporting:
      
      ```bash
      echo -e "Sample\tTotal_Reads\tMapping_Rate\tDedup_Rate\tConversion\tMean_CpG_Cov\tCpGs_5x"
      echo -e "${SAMPLE}\t${TOTAL}\t${MAP_RATE}\t${DEDUP_RATE}\t${CONV_RATE}\t${MEAN_COV}\t${CPGS_5X}"
      ```
      
      `CONV_RATE` has to come from the manual check above; everything else is in the published
      reports.
      
    • literature.md 12.7 KB
      # WGBS Pipeline — Literature References
      
      **Last updated:** 2026-03-07
      **Purpose:** Reference catalog for the pipeline-wgbs skill — papers defining ENCODE WGBS processing standards, bisulfite-aware alignment, methylation extraction, and quality assessment for whole-genome bisulfite sequencing.
      
      ---
      
      ## DNA Methylation Method & Standards
      
      ---
      
      ### Lister et al. 2009 — Human DNA methylomes at base resolution
      
      - **Citation:** Lister R, Pelizzola M, Dowen RH, Hawkins RD, Hon G, Tonti-Filippini J, Nott JR, Lee L, Ye Z, Ngo QM, Edsall L, Antosiewicz-Bourget J, Stewart R, Ruotti V, Millar AH, Thomson JA, Ren B, Ecker JR. Human DNA methylomes at base resolution show widespread epigenomic differences. Nature, 462(7271):315-322, 2009.
      - **DOI:** [10.1038/nature08514](https://doi.org/10.1038/nature08514)
      - **PMID:** 19829295 | **PMC:** PMC2857523
      - **Citations:** ~5,000
      - **Key findings:** First base-resolution whole-genome DNA methylation maps for human (H1 ESCs and IMR90 fibroblasts). Demonstrated that ~25% of all methylated cytosines in embryonic stem cells are in non-CpG context (CHG, CHH), a phenomenon largely absent in differentiated cells. Identified widespread methylation differences between cell types, including large partially methylated domains (PMDs) covering ~40% of the genome in fibroblasts that correlate with gene repression and late-replicating chromatin. Established WGBS as the gold standard for comprehensive methylation profiling at single-nucleotide resolution, requiring ~30x genome coverage for reliable quantification.
      
      ---
      
      ### Schultz et al. 2015 — Human body epigenome maps
      
      - **Citation:** Schultz MD, He Y, Whitaker JW, Hariharan M, Mukamel EA, Leung D, Rajagopal N, Nery JR, Urich MA, Chen H, Lin S, Lin Y, Jung I, Schmitt AD, Selvaraj S, Ren B, Sejnowski TJ, Wang W, Ecker JR. Human body epigenome maps reveal noncanonical DNA methylation variation. Nature, 523(7559):212-216, 2015.
      - **DOI:** [10.1038/nature14248](https://doi.org/10.1038/nature14248)
      - **PMID:** 26030523 | **PMC:** PMC4539777
      - **Citations:** ~1,500
      - **Key findings:** Generated WGBS methylomes for 18 human tissues as part of the Roadmap Epigenomics Project. Identified tissue-specific differentially methylated regions (DMRs) and described three classes of genomic methylation: highly methylated regions (HMRs, >80%), partially methylated domains (PMDs, 50-80%), and unmethylated regions (UMRs, <20%). PMDs are associated with late-replicating heterochromatin and expand during aging and in cancer. UMRs at CpG islands mark active promoters, while tissue-specific UMRs often mark active enhancers. Established the analytical framework for WGBS data interpretation used in this pipeline.
      
      ---
      
      ### ENCODE Project Consortium 2020 — Expanded encyclopaedias of DNA elements
      
      - **Citation:** ENCODE Project Consortium et al. Expanded encyclopaedias of DNA elements in the human and mouse genomes. Nature, 583(7818):699-710, 2020.
      - **DOI:** [10.1038/s41586-020-2493-4](https://doi.org/10.1038/s41586-020-2493-4)
      - **PMID:** 32728249 | **PMC:** PMC7410828
      - **Citations:** ~2,500
      - **Key findings:** ENCODE Phase 3 paper establishing DNA methylation as a core epigenomic layer alongside histone modifications and chromatin accessibility. WGBS data is used to identify methylation valleys (large UMRs) at key developmental genes and to classify candidate cis-Regulatory Elements (cCREs) by their methylation status. Established the ENCODE WGBS pipeline standards: bisulfite conversion rate ≥98%, minimum 30x CpG coverage for reliable DMR calling, and GRCh38/mm10 as reference assemblies.
      
      ---
      
      ### Hitz et al. 2023 — The ENCODE Uniform Analysis Pipelines
      
      - **Citation:** Hitz BC, Lee JW, Jolanki O, et al. The ENCODE Uniform Analysis Pipelines. Research Square (preprint), 2023.
      - **DOI:** [10.21203/rs.3.rs-311127/v1](https://doi.org/10.21203/rs.3.rs-311127/v1)
      - **Citations:** ~84
      - **Key findings:** Documents the official ENCODE WGBS pipeline specification: Bismark for bisulfite-aware alignment, deduplication with Picard MarkDuplicates, MethylDackel for methylation extraction, and lambda phage spike-in for conversion rate quality control. Specifies bedMethyl as the standard output format and defines QC thresholds: bisulfite conversion ≥98%, mapping rate >70%, and sufficient CpG coverage depth for downstream DMR analysis. Pipeline infrastructure uses Docker containers and WDL for reproducible execution.
      
      ---
      
      ### Foox et al. 2021 — Performance assessment of DNA sequencing platforms
      
      - **Citation:** Foox J, Nordlund J, Lalonde E, Lim S, Deschamps-Francoeur G, Trognitz F, Holmes M, Close MC, et al. Performance assessment of DNA sequencing platforms in the ABRF Next-Generation Sequencing Study. Nature Biotechnology, 39(9):1129-1140, 2021.
      - **DOI:** [10.1038/s41587-021-01049-5](https://doi.org/10.1038/s41587-021-01049-5)
      - **PMID:** 34504353
      - **Citations:** ~200
      - **Key findings:** Multi-site benchmarking of sequencing platforms for WGBS applications. Demonstrated that bisulfite conversion rate is the most critical QC parameter, with rates below 99% introducing thousands of false-positive methylation calls across the genome. Platform-specific biases in GC-rich regions affect CpG island coverage. Supports the ENCODE requirement for ≥98% conversion rate and provides the evidence base for this pipeline's QC thresholds.
      
      ---
      
      ## Core Pipeline Tools
      
      ---
      
      ### Krueger & Andrews 2011 — Bismark
      
      - **Citation:** Krueger F, Andrews SR. Bismark: a flexible aligner and methylation caller for Bisulfite-Seq applications. Bioinformatics, 27(11):1571-1572, 2011.
      - **DOI:** [10.1093/bioinformatics/btr167](https://doi.org/10.1093/bioinformatics/btr167)
      - **PMID:** 21493656 | **PMC:** PMC3102221
      - **Citations:** ~4,000
      - **Key findings:** Introduced Bismark, the most widely used bisulfite-aware aligner. Bismark performs in silico C-to-T conversion of both the reference genome and sequencing reads, then aligns using Bowtie2 as the backend. After alignment, it determines the original methylation state of each cytosine by comparing the unconverted read to the reference. Handles all three cytosine contexts (CpG, CHG, CHH) and generates comprehensive methylation reports. The ENCODE pipeline uses Bismark as the default aligner for WGBS data, leveraging its --paired mode with --no_overlap to avoid double-counting methylation in overlapping paired-end reads.
      
      ---
      
      ### Pedersen et al. 2014 — bwa-meth
      
      - **Citation:** Pedersen BS, Eyring K, De S, Yang IV, Schwartz DA. Fast and accurate alignment of long bisulfite-seq reads. arXiv:1401.1129, 2014.
      - **DOI:** [10.48550/arXiv.1401.1129](https://doi.org/10.48550/arXiv.1401.1129)
      - **Citations:** ~200
      - **Key findings:** Introduced bwa-meth, an alternative bisulfite-aware aligner that wraps BWA-MEM for bisulfite-converted reads. Rather than creating four converted reference copies (like Bismark), bwa-meth converts only the C-to-T strand and the G-to-A strand, achieving faster alignment while maintaining accuracy. Particularly advantageous for longer reads (>100 bp) where BWA-MEM's local alignment outperforms Bowtie2's end-to-end mode. Included in this pipeline as an alternative aligner option (--aligner bwameth) for users who prefer faster processing or have long-read bisulfite data.
      
      ---
      
      ### MethylDackel — Methylation extraction from BAM files
      
      - **Citation:** Ryan DP. MethylDackel: A (mostly) universal methylation extractor for BS-seq experiments. GitHub, 2023.
      - **URL:** [https://github.com/dpryan79/MethylDackel](https://github.com/dpryan79/MethylDackel)
      - **Key findings:** MethylDackel (formerly PileOMeth) extracts per-base methylation metrics from BAM files produced by any bisulfite-aware aligner. Key features used in this pipeline: --mergeContext flag to merge complementary CpG dinucleotide strands, --minDepth to filter low-coverage positions, M-bias plot generation for identifying end-repair artifacts, and --OT/--OB position-based trimming to remove biased read positions. MethylDackel outputs in bedMethyl format, the ENCODE standard for methylation data. Replaces Bismark's built-in methylation extractor with improved speed and flexibility.
      
      ---
      
      ## Quality Control
      
      ---
      
      ### Ewels et al. 2016 — MultiQC
      
      - **Citation:** Ewels P, Magnusson M, Lundin S, Käller M. MultiQC: summarize analysis results for multiple tools and samples in a single report. Bioinformatics, 32(19):3047-3048, 2016.
      - **DOI:** [10.1093/bioinformatics/btw354](https://doi.org/10.1093/bioinformatics/btw354)
      - **PMID:** 27312411 | **Citations:** ~6,800
      - **WGBS role:** Aggregates QC metrics from FastQC, Bismark alignment reports, Bismark deduplication reports, and MethylDackel M-bias plots into a unified HTML report. Provides batch-level assessment of bisulfite conversion rates, mapping rates, and duplication across all samples.
      
      ---
      
      ## Supplementary Tools (Non-WGBS-Specific)
      
      See pipeline-chipseq/references/literature.md for detailed descriptions of shared tools.
      
      ---
      
      ### Li et al. 2009 — SAMtools
      
      - **DOI:** [10.1093/bioinformatics/btp352](https://doi.org/10.1093/bioinformatics/btp352) | **PMID:** 19505943 | **Citations:** ~53,700
      - **WGBS role:** BAM sorting, indexing, and filtering. Used for coordinate sorting after Bismark alignment and computing alignment statistics. Provides samtools flagstat for mapping rate assessment.
      
      ---
      
      ### Broad Institute — Picard MarkDuplicates
      
      - **URL:** [https://broadinstitute.github.io/picard/](https://broadinstitute.github.io/picard/)
      - **WGBS role:** PCR duplicate marking and removal. Critical for WGBS because PCR amplification of bisulfite-converted DNA is biased toward unmethylated molecules (which align better after conversion), making duplicates non-random. High duplication rates (>30%) indicate insufficient library complexity and can bias methylation estimates.
      
      ---
      
      ### Andrews 2010 — FastQC
      
      - **URL:** [https://www.bioinformatics.babraham.ac.uk/projects/fastqc/](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/)
      - **WGBS role:** Raw read quality assessment. Bisulfite-converted reads have characteristic quality profiles: reduced base diversity (most Cs converted to Ts), asymmetric per-base composition, and lower quality scores than standard WGS. These patterns are expected and not cause for concern in WGBS data.
      
      ---
      
      ### Martin 2011 — Cutadapt (basis for Trim Galore)
      
      - **DOI:** [10.14806/ej.17.1.200](https://doi.org/10.14806/ej.17.1.200) | **Citations:** ~13,000
      - **WGBS role:** Adapter trimming via Trim Galore wrapper. Particularly important for WGBS because bisulfite conversion reduces sequence complexity, making adapter contamination harder to detect. Trim Galore includes bisulfite-specific adapter detection and optional RRBS-aware trimming (--rrbs flag) for reduced representation data.
      
      ---
      
      ### Amemiya et al. 2019 — ENCODE Blacklist
      
      - **DOI:** [10.1038/s41598-019-45839-z](https://doi.org/10.1038/s41598-019-45839-z) | **PMID:** 31249361 | **Citations:** ~1,372
      - **WGBS role:** Blacklist v2 filtering removes artifact-prone regions before downstream analysis. In WGBS, blacklisted regions can show aberrant methylation estimates due to alignment artifacts in repetitive sequences. Applied after methylation calling to filter bedMethyl output.
      
      ---
      
      ## Additional Relevant Papers
      
      ---
      
      ### Hansen et al. 2012 — BSmooth: large-scale WGBS smoothing
      
      - **Citation:** Hansen KD, Langmead B, Irizarry RA. BSmooth: from whole genome bisulfite sequencing reads to differentially methylated regions. Genome Biology, 13(10):R83, 2012.
      - **DOI:** [10.1186/gb-2012-13-10-r83](https://doi.org/10.1186/gb-2012-13-10-r83)
      - **PMID:** 23034175 | **PMC:** PMC3491411
      - **Citations:** ~1,200
      - **Key findings:** Introduced local-likelihood smoothing for WGBS data, demonstrating that single-CpG methylation estimates from WGBS are inherently noisy even at high coverage, and that smoothing across neighboring CpGs substantially improves differential methylation detection. Established the analytical framework for identifying differentially methylated regions (DMRs) from WGBS data, implemented in the bsseq R/Bioconductor package. Relevant for downstream analysis of pipeline output.
      
      ---
      
      ### Peters et al. 2015 — DMRcate: differentially methylated region analysis
      
      - **Citation:** Peters TJ, Buckley MJ, Statham AL, Pidsley R, Samaras K, Lord RV, Clark SJ, Molloy PL. De novo identification of differentially methylated regions in the human genome. Epigenetics & Chromatin, 8:6, 2015.
      - **DOI:** [10.1186/1756-8935-8-6](https://doi.org/10.1186/1756-8935-8-6)
      - **PMID:** 25972926 | **PMC:** PMC4429357
      - **Citations:** ~900
      - **Key findings:** Introduced DMRcate, a method for de novo identification of differentially methylated regions using kernel smoothing and bump-hunting. Works with both array (450K/EPIC) and WGBS data, providing a unified framework for DMR detection. Relevant for downstream analysis of bedMethyl output from this pipeline, particularly when comparing methylation across conditions or tissues.
      
  • scripts
    • Dockerfile 2.8 KB · in bundle
    • main.nf 8.9 KB · in bundle
    • nextflow.config 4.2 KB · in bundle
  • SKILL.md 24.2 KB
    ---
    name: pipeline-wgbs
    description: "Execute ENCODE Whole Genome Bisulfite Sequencing (WGBS) pipeline from FASTQ to methylation calls. Child of pipeline-guide. Provides Nextflow execution with Docker and cloud deployment. Use when processing WGBS/bisulfite-seq data, calling methylation levels, generating bedMethyl files. Trigger on: WGBS pipeline, bisulfite sequencing, methylation calling, DNA methylation pipeline, bismark, bwa-meth, bedMethyl."
    ---
    
    # ENCODE WGBS Pipeline: FASTQ to Methylation Calls
    
    ## When to Use
    
    - User wants to run a WGBS/bisulfite sequencing pipeline from FASTQ to methylation calls
    - User asks about "WGBS pipeline", "bisulfite sequencing", "methylation calling", "Bismark", or "bedMethyl"
    - User needs to process whole-genome bisulfite sequencing data following ENCODE standards
    - Example queries: "process my WGBS FASTQs", "call methylation levels from bisulfite-seq", "run Bismark on my WGBS data"
    
    Execute the ENCODE DNA methylation pipeline for Whole Genome Bisulfite Sequencing data,
    producing per-CpG methylation levels in bedMethyl format.
    
    ## Pipeline Overview
    
    ```
    FASTQ -> Trim adapters -> Bismark align -> Deduplicate -> sort + index -> MethylDackel -> bedMethyl
      |           |                 |               |                |             |             |
     FastQC   Trim Galore    Bismark (Bowtie2)  deduplicate_   samtools      mbias +       coverage
                                                 bismark                     extract        stats
    ```
    
    Paired-end only: `TRIM_GALORE` and `BISMARK_ALIGN` both take two mates, and `--reads` must
    match pairs.
    
    ### ENCODE Repository
    
    - **GitHub**: `ENCODE-DCC/dna-me-pipeline`
    - **Container**: built from `scripts/Dockerfile` in this skill (`docker build -t encode-toolkit/pipeline-wgbs:1.0.0 scripts/`); override with `--container`
    - **WDL**: Available for Cromwell execution
    - **This skill**: Nextflow DSL2 reimplementation for portability
    
    ## Core Tools and Versions
    
    These are the versions in `scripts/Dockerfile`, which is what the workflow runs.
    
    | Tool | Version | Purpose | Citation |
    |------|---------|---------|----------|
    | Trim Galore | 0.6.10 | Adapter + quality trimming (bisulfite-aware) | Krueger (Babraham) |
    | Bismark | 0.24.2 | Bisulfite-aware alignment + deduplication | Krueger & Andrews 2011 |
    | Bowtie2 | 2.5.4 | Backend aligner used by Bismark | Langmead & Salzberg 2012 |
    | MethylDackel | 0.6.1 | Methylation extraction from BAM | Ryan (GitHub) |
    | samtools | 1.19 | BAM sorting and indexing | Li et al. 2009 |
    | htslib | 1.19 | `bgzip` and `tabix` for the bedMethyl files | Bonfield et al. 2021 |
    | FastQC | 0.12.1 | Read quality assessment | Andrews (Babraham) |
    | MultiQC | 1.21 | Aggregated QC reporting | Ewels et al. 2016 |
    
    The conda environment in `bioinformatics-installer` (`environments/wgbs-env.yml`) is a
    separate manual route pinned to the same versions of these tools; it also carries
    bedtools, which is not in the image.
    
    ## Key Literature
    
    1. **Krueger & Andrews 2011** - "Bismark: a flexible aligner and methylation caller for
       Bisulfite-Seq applications" (Bioinformatics, ~4,000 citations)
       DOI: 10.1093/bioinformatics/btr167
    
    2. **Lister et al. 2009** - "Human DNA methylomes at base resolution show widespread
       epigenomic differences" (Nature, ~5,000 citations)
       DOI: 10.1038/nature08514
    
    3. **Schultz et al. 2015** - "Human body epigenome maps reveal noncanonical DNA
       methylation variation" (Nature, ~1,500 citations)
       DOI: 10.1038/nature14248
    
    4. **Pedersen et al. 2014** - "Fast and accurate alignment of long bisulfite-seq reads"
       arXiv:1401.1129 (bwa-meth)
    
    5. **Amemiya et al. 2019** - "The ENCODE Blacklist" (Scientific Reports, ~1,372 citations)
       DOI: 10.1038/s41598-019-45839-z
    
    ## Execution
    
    `--reads` and `--genome_dir` are both required; the workflow stops before the first task
    if either is missing. `--genome_dir` is a Bismark genome folder — the output of
    `bismark_genome_preparation`, which must still contain the genome `.fa`, because
    MethylDackel reads it from there.
    
    ### Quick Start (local, Docker)
    
    ```bash
    nextflow run scripts/main.nf -profile local \
        --reads '/data/fastq/*_R{1,2}.fastq.gz' \
        --genome_dir /ref/bismark_index \
        --min_coverage 5 \
        --outdir results/ \
        -resume
    ```
    
    ### SLURM HPC
    
    ```bash
    nextflow run scripts/main.nf -profile slurm \
        --container /path/to/pipeline-wgbs.sif \
        --slurm_queue normal \
        --reads '/data/fastq/*_R{1,2}.fastq.gz' \
        --genome_dir /ref/bismark_index \
        --outdir results/ \
        -resume
    ```
    
    ### Cloud
    
    ```bash
    # Google Cloud Batch
    nextflow run scripts/main.nf -profile gcp \
        --container us-docker.pkg.dev/<project>/<repo>/pipeline-wgbs:1.0.0 \
        --gcp_project <project> \
        --gcp_workdir gs://<bucket>/work \
        --reads 'gs://<bucket>/fastq/*_R{1,2}.fastq.gz' \
        --genome_dir gs://<bucket>/ref/bismark_index \
        --outdir gs://<bucket>/results
    
    # AWS Batch
    nextflow run scripts/main.nf -profile aws \
        --container <account>.dkr.ecr.<region>.amazonaws.com/pipeline-wgbs:1.0.0 \
        --aws_queue <job-queue> \
        --aws_workdir s3://<bucket>/work \
        --reads 's3://<bucket>/fastq/*_R{1,2}.fastq.gz' \
        --genome_dir s3://<bucket>/ref/bismark_index \
        --outdir s3://<bucket>/results
    ```
    
    `--outdir` only sets where results are published; Google Batch and AWS Batch stage every
    task through the work directory, and the workflow stops with an error if it or the
    project/queue is missing.
    
    ## Resource Requirements
    
    | Step | CPUs | RAM | Time (30x human) |
    |------|------|-----|-------------------|
    | FastQC | 2 | 4 GB | <1 hour |
    | Trim Galore | 4 | 4 GB | 1-2 hours |
    | Bismark align | 8 | 48 GB | 8-16 hours |
    | Deduplication | 2 | 16 GB | 1-2 hours |
    | Sort + index | 4 | 8 GB | 1-2 hours |
    | MethylDackel (mbias, extract) | 2, 4 | 8 GB | 1-2 hours |
    | **Total** | **8** | **48 GB** | **12-24 hours** |
    
    Every process asks for `memory { N.GB * task.attempt }`, so a task killed for running out
    of memory is retried with more: the second attempt gets twice the figure in the table, the
    third three times it, bounded by `--max_memory`. `nextflow.config` scales the time the
    same way for `BISMARK_ALIGN`, `DEDUPLICATE` and `METHYLDACKEL_EXTRACT`, bounded by
    `--max_time`; the other processes declare no time limit. A task is retried only for exit
    codes 130-145 and 104 (killed for exceeding a limit); any other failure stops the run.
    
    ## Pipeline Parameters
    
    | Parameter | Default | Description |
    |-----------|---------|-------------|
    | `--reads` | required | Glob matching the paired FASTQ files, e.g. `'/data/fastq/*_R{1,2}.fastq.gz'`. Quote it |
    | `--genome_dir` | required | Bismark genome folder (`bismark_genome_preparation` output, including the genome `.fa`) |
    | `--outdir` | `./results` | Directory results are published to |
    | `--min_coverage` | `5` | Minimum read count a site must reach to appear in the bedMethyl files. The MethylDackel bedGraphs are written unfiltered |
    | `--merge_context` | `true` | Merge the two strands of each CpG/CHG into one record (`MethylDackel --mergeContext`) |
    | `--skip_dedup` | `false` | Skip `deduplicate_bismark`; the sorted BAM is then the raw alignment |
    
    ### Infrastructure parameters (`nextflow.config`)
    
    | Parameter | Default | Description |
    |-----------|---------|-------------|
    | `--container` | `encode-toolkit/pipeline-wgbs:1.0.0` | Image built from `scripts/Dockerfile`. Pass a registry image for `gcp`/`aws`, or a `.sif` file for `slurm` |
    | `--max_cpus`, `--max_memory`, `--max_time` | `16`, `64.GB`, `48.h` | Upper bounds applied to every process |
    | `--slurm_queue`, `--slurm_account` | `normal`, none | SLURM partition and account |
    | `--gcp_project`, `--gcp_workdir` | none (both required for `-profile gcp`) | Google Cloud project and `gs://` work directory |
    | `--gcp_location`, `--gcp_disk` | `us-central1`, `200.GB` | Google Batch region and per-task disk |
    | `--aws_queue`, `--aws_workdir` | none (both required for `-profile aws`) | AWS Batch job queue and `s3://` work directory |
    | `--aws_region`, `--aws_cli_path` | `us-east-1`, `/home/ec2-user/miniconda/bin/aws` | AWS region, and the AWS CLI path inside the Batch AMI |
    
    Notes on what the workflow does and does not do:
    - **Aligner**: Bismark with Bowtie2. bwa-meth is described in `references/02-bismark-alignment.md`
      as a manual alternative; it is not an option of this workflow and is not in the image.
    - **Deduplication**: `deduplicate_bismark`. Picard is not installed and is not used.
    - **BAM filtering**: there is no MAPQ or flag filtering step. The BAM handed to
      MethylDackel is the Bismark output, deduplicated and sorted. `references/03-dedup-filtering.md`
      gives the manual filtering commands if you want them.
    - **Overlapping mates**: MethylDackel never counts both mates of an overlapping read pair, so
      there is no switch for it. `--merge_context` is a separate choice about per-CpG versus
      per-cytosine output.
    - **Read-position trimming at extraction**: none. `MethylDackel extract` is called without
      `--nOT`/`--nOB`, because `--clip_R2 10` at the trimming step already removes the
      end-repair bias. See the M-bias pitfall below.
    - **Bisulfite conversion rate**: not computed by the workflow. Estimate it from the CHH
      methylation percentage in the Bismark alignment report, or align a lambda/pUC19 spike-in
      separately when the sample carries real non-CpG methylation (ESCs, neurons).
      `references/05-qc-metrics.md` has both commands.
    
    ## Output Files
    
    ```
    results/
      fastqc/                      # FastQC on the raw reads
      trim_galore/                 # trimmed reads, trimming reports, and FastQC on the trimmed reads
      bismark/
        alignments/
          {sample}.sorted.bam      # final BAM: deduplicated unless --skip_dedup, sorted
          {sample}.sorted.bam.bai
          *_PE_report.txt          # Bismark alignment report (mapping rate, context methylation)
        dedup_reports/
          *.deduplication_report.txt
        mbias/
          {sample}_mbias_*.svg     # M-bias plots, one per strand
          {sample}_mbias_report.txt  # MethylDackel's suggested inclusion bounds
        methylation/
          {sample}_CpG.bedGraph    # MethylDackel output, every covered cytosine/CpG
          {sample}_CHG.bedGraph
          {sample}_CHH.bedGraph
          {sample}.CpG.bedMethyl.gz (+ .tbi)   # primary output, filtered by --min_coverage
          {sample}.CHG.bedMethyl.gz (+ .tbi)   # non-CpG contexts
          {sample}.CHH.bedMethyl.gz (+ .tbi)
      coverage/
        {sample}.coverage_stats.txt
      multiqc/
        multiqc_report.html
      pipeline_info/
        timeline.html, report.html, trace.txt  # Nextflow execution reports
    ```
    
    Note the naming: the MethylDackel bedGraphs use an underscore before the context
    (`{sample}_CpG.bedGraph`), the bedMethyl files a dot (`{sample}.CpG.bedMethyl.gz`).
    
    ### bedMethyl Format
    
    The primary output is per-CpG methylation in the ENCODE bedMethyl layout
    (https://www.encodeproject.org/data-standards/wgbs/):
    
    ```
    chr1  10468  10470  .  12  .  10468  10470  0,0,0  12  83
    ```
    
    Columns: chr, start, end, name (`.`), score, strand, thickStart, thickEnd, colour,
    coverage, percent methylated. The score in column 5 is the read count capped at 1000, the
    strand in column 6 is `.` because MethylDackel's bedGraph carries no strand, and column 11
    is an integer percentage. Sites below `--min_coverage` are dropped.
    
    ### Coverage Statistics
    
    `coverage/{sample}.coverage_stats.txt` is computed from the unfiltered
    `{sample}_CpG.bedGraph`, so it describes every covered site, not just the reported ones.
    It has five lines — this is a run at the default `--min_coverage 5`:
    
    ```
    Covered CpGs (>=1x): 27184023
    Mean coverage of covered CpGs: 12.4
    Covered CpGs >=5x: 22903511 (84.3%)
    Covered CpGs >=10x: 16992841 (62.5%)
    Covered CpGs >=5x (--min_coverage, kept in bedMethyl): 22903511 (84.3%)
    ```
    
    The 5x and 10x lines are fixed thresholds and do not follow `--min_coverage`. The last
    line does, and it is the one that describes what actually reached the bedMethyl files: at
    the default it repeats the >=5x line, with `--min_coverage 10` it would repeat the >=10x
    line, and at any other value it stands on its own. All the percentages are of *covered*
    CpGs, not of all CpGs in the genome — the workflow never counts genomic CpGs that got zero
    reads. With `--merge_context false` the records are per cytosine rather than per CpG.
    
    ## QC Thresholds (ENCODE Standards)
    
    | Metric | Pass | Warning | Fail | Source |
    |--------|------|---------|------|--------|
    | Mapping rate | >70% | 50-70% | <50% | `bismark/alignments/*_PE_report.txt` |
    | Duplication rate | <30% | 30-50% | >50% | `bismark/dedup_reports/*.deduplication_report.txt` |
    | Mean coverage of covered CpGs | >10x | 5-10x | <5x | `coverage/{sample}.coverage_stats.txt` |
    | Covered CpGs reaching >=5x | >80% | 60-80% | <60% | `coverage/{sample}.coverage_stats.txt` |
    | Bisulfite conversion rate | ≥98% | 95-98% | <95% | External; see `references/05-qc-metrics.md` |
    | Lambda spike-in conversion | ≥98% | 95-98% | <95% | External; requires a separate alignment |
    
    ## Critical Pitfalls
    
    ### RRBS vs WGBS
    RRBS (Reduced Representation) uses MspI digestion and covers ~10% of CpGs.
    WGBS covers the full genome. These are DIFFERENT protocols:
    - RRBS: this workflow is not set up for it. Deduplication can be skipped
      (`--skip_dedup true`), but the trimming is WGBS-specific and hardcoded
      (`--clip_R2 10 --three_prime_clip_R1 1`), there is no `--rrbs` switch, and the workflow
      re-trims whatever FASTQs it is given. Run RRBS trimming and alignment by hand —
      `references/01-qc-trimming.md` has the command
    - WGBS: full dedup required, standard Trim Galore settings
    - Never mix RRBS and WGBS data in the same analysis
    
    ### Strand-Specific vs Merged CpG
    Bismark reports methylation per strand by default. For most analyses, merge
    complementary CpG strands:
    - Forward C at position N and reverse G at position N+1 are the same CpG
    - MethylDackel `--mergeContext` handles this automatically
    - `--merge_context true` is the workflow default; set it to `false` only when you need
      strand-specific data
    
    ### Incomplete Bisulfite Conversion
    Conversion artifacts produce false methylation calls:
    - Always include lambda phage or pUC19 spike-in DNA
    - Unmethylated spike-in should show ≥98% conversion
    - The workflow does not measure this. Align the spike-in separately, or read the CHH
      methylation percentage out of the Bismark report, before trusting the calls
    
    ### M-bias Plots
    `MethylDackel mbias` runs on every sample and writes plots plus
    `bismark/mbias/{sample}_mbias_report.txt`, which captures MethylDackel's suggested
    inclusion bounds. Extraction itself excludes no read positions:
    - End-repair artifacts cause elevated methylation at read ends. The 5' end-repair bias of
      read 2 is already removed at the trimming step by `--clip_R2 10`
    - If the plots still show bias, re-run `MethylDackel extract` manually with `--OT`/`--OB`
      set to the suggested bounds. Note the argument order: `--OT A,B,C,D` *includes*
      positions A-B on read 1 and C-D on read 2, and the matching `--nOT a,b,c,d` *excludes*
      a bases from the start of read 1, b from its end, c from the start of read 2 and d from
      its end
    - `--maxDepth` is not an option of MethylDackel 0.6.1 and must not be passed
    
    ### Low Coverage Regions
    Regions with <5x coverage have unreliable methylation estimates:
    - The bedMethyl files are filtered to `--min_coverage` (default 5); the bedGraphs are not
    - For differential methylation analysis, consider `--min_coverage 10`
    - Report the >=5x and >=10x fractions from `coverage/{sample}.coverage_stats.txt`. Those
      two thresholds are fixed in the workflow and do not follow `--min_coverage`; the last
      line of the file is the one that does, so quote it too whenever the run used a value
      other than 5
    
    ## Provenance Integration
    
    After pipeline completion, log all outputs:
    
    ```python
    # Log derived bedMethyl files
    encode_log_derived_file(
        file_path="/results/bismark/methylation/sample1.CpG.bedMethyl.gz",
        source_accessions=["ENCSR...", "ENCFF..."],
        description="CpG methylation calls from ENCODE WGBS pipeline",
        file_type="bedMethyl",
        tool_used="Bismark 0.24.2 + MethylDackel 0.6.1",
        parameters="bismark --genome /ref -1 R1.fq.gz -2 R2.fq.gz; MethylDackel extract --mergeContext --CHG --CHH; bedMethyl filtered at --min_coverage 5"
    )
    ```
    
    ## Reference Files
    
    Detailed step-by-step documentation is provided in the `references/` directory:
    
    1. `01-qc-trimming.md` -- Bisulfite-specific adapter trimming with Trim Galore
    2. `02-bismark-alignment.md` -- Bismark alignment and the bwa-meth manual alternative
    3. `03-dedup-filtering.md` -- Deduplication, and manual BAM filtering the workflow skips
    4. `04-methylation-calling.md` -- MethylDackel extraction and bedMethyl generation
    5. `05-qc-metrics.md` -- Coverage stats, M-bias, and manual conversion-rate checks
    
    ## Walkthrough: Processing ENCODE WGBS from FASTQ to Methylation Calls
    
    **Goal**: Process whole-genome bisulfite sequencing FASTQ files through the ENCODE pipeline to generate per-CpG methylation calls for epigenomic analysis.
    **Context**: WGBS requires bisulfite-aware alignment (Bismark) and per-CpG methylation extraction (MethylDackel), with ≥98% bisulfite conversion expected of the library.
    
    ### Step 1: Find WGBS experiment
    
    ```
    encode_get_experiment(accession="ENCSR765JPC")
    ```
    
    Expected output:
    ```json
    {
      "accession": "ENCSR765JPC",
      "assay_title": "WGBS",
      "biosample_summary": "liver tissue male adult (54 years)",
      "assembly": ["GRCh38"],
      "bio_replicate_count": 2,
      "tech_replicate_count": 2,
      "status": "released"
    }
    ```
    
    ### Step 2: List FASTQ files
    
    ```
    encode_list_files(experiment_accession="ENCSR765JPC", file_format="fastq")
    ```
    
    Expected output (a JSON array of file records; fields abridged):
    ```json
    [
      {"accession": "ENCFF300BS1", "file_format": "fastq", "output_type": "reads", "file_size_human": "45.0 GB", "biological_replicates": [1], "status": "released"},
      {"accession": "ENCFF301BS2", "file_format": "fastq", "output_type": "reads", "file_size_human": "46.0 GB", "biological_replicates": [1], "status": "released"}
    ]
    ```
    
    **Interpretation**: WGBS files are very large (~45GB per read file). Ensure adequate storage (>500GB for processing).
    
    ### Step 3: Download and name the FASTQs so a read-pair glob can find them
    
    ```
    encode_download_files(file_accessions=["ENCFF300BS1", "ENCFF301BS2"], download_dir="/data/wgbs/fastq")
    ```
    
    ENCODE names every FASTQ after its accession (`ENCFF300BS1.fastq.gz`), with no `_R1`/`_R2`
    in the name, so the two files of a pair share no prefix and the `--reads` glob cannot pair
    them. Link them into the shape the glob expects. Which mate an accession is comes from the
    ENCODE file record on encodeproject.org, which carries `paired_end` (1 or 2) and
    `paired_with`; the MCP file tools do not return those two fields:
    
    ```bash
    cd /data/wgbs/fastq
    ln -s ENCFF300BS1.fastq.gz liver_rep1_R1.fastq.gz
    ln -s ENCFF301BS2.fastq.gz liver_rep1_R2.fastq.gz
    ```
    
    ### Step 4: Run the WGBS pipeline
    
    ```bash
    nextflow run scripts/main.nf -profile local \
        --reads '/data/wgbs/fastq/liver_*_R{1,2}.fastq.gz' \
        --genome_dir /ref/bismark_index \
        --min_coverage 5 \
        --outdir results/ \
        -resume
    ```
    
    Key pipeline steps:
    1. FastQC on the raw reads, then adapter/quality trimming with Trim Galore (which also runs FastQC on the trimmed reads)
    2. Bisulfite-aware alignment (Bismark with Bowtie2)
    3. Deduplication (`deduplicate_bismark`), then sort and index
    4. M-bias assessment and methylation extraction (MethylDackel), then conversion to bedMethyl
    5. CpG coverage statistics
    6. MultiQC aggregation
    
    ### Step 5: Validate output quality
    
    | Metric | Threshold | Purpose |
    |---|---|---|
    | Mapping rate | > 70% | Alignment success (Bismark report) |
    | Duplication rate | < 30% | Library complexity (dedup report) |
    | Covered CpGs at >= 10x | Enough for DMR calling | Statistical power (coverage stats) |
    | Bisulfite conversion | >= 98% | Library quality; measured outside this workflow |
    
    ### Step 6: Identify differentially methylated regions
    
    Feed per-CpG methylation into -> **methylation-aggregation** for cross-tissue comparison and HMR/UMR/PMD identification.
    
    ### Integration with downstream skills
    - Per-CpG methylation files feed into -> **methylation-aggregation** for cross-tissue atlas
    - DMRs feed into -> **peak-annotation** for nearest gene assignment
    - Methylation at regulatory elements connects to -> **regulatory-elements**
    - CpG variant methylation integrates with -> **variant-annotation**
    - Pipeline provenance logged by -> **data-provenance**
    
    ## Code Examples
    
    ### 1. Find WGBS data for methylation analysis
    
    ```
    encode_search_experiments(
      assay_title="WGBS",
      organ="brain"
    )
    ```
    
    Expected output:
    ```json
    {
      "results": [
        {
          "accession": "ENCSR321BRN",
          "assay_title": "WGBS",
          "biosample_summary": "brain tissue female adult (53 years)",
          "organ": "brain",
          "status": "released"
        }
      ],
      "total": 6,
      "limit": 25,
      "offset": 0,
      "has_more": false,
      "next_offset": null
    }
    ```
    
    ### 2. Download processed methylation files
    
    ```
    encode_search_files(
      assay_title="WGBS",
      organ="brain",
      file_format="bed",
      output_type="methylation state at CpG",
      assembly="GRCh38"
    )
    ```
    
    Expected output (fields abridged):
    ```json
    {
      "results": [
        {
          "accession": "ENCFF567MET",
          "file_format": "bed",
          "output_type": "methylation state at CpG",
          "assembly": "GRCh38",
          "file_size": 886144860,
          "file_size_human": "845.1 MB",
          "experiment_accession": "ENCSR321BRN"
        }
      ],
      "total": 3,
      "limit": 25,
      "offset": 0,
      "has_more": false,
      "next_offset": null
    }
    ```
    
    ## Integration
    
    | This skill produces... | Feed into... | Purpose |
    |---|---|---|
    | Per-CpG methylation (bedMethyl) | **methylation-aggregation** | Cross-tissue methylation atlas |
    | Per-CpG methylation (bedMethyl) | **visualization-workflow** | Display methylation in a genome browser (tabix-indexed BED; the workflow writes no bigWig) |
    | Differentially methylated regions | **peak-annotation** | Assign DMRs to nearest genes |
    | Methylation at regulatory sites | **regulatory-elements** | Correlate methylation with cCRE activity |
    | CpG methylation near variants | **variant-annotation** | Annotate variants affecting CpG methylation |
    | Coverage and mapping metrics | **quality-assessment** | Validate coverage and alignment against ENCODE standards |
    | Pipeline parameters | **data-provenance** | Record Bismark/MethylDackel versions |
    | Methylation at promoters | **gtex-expression** | Correlate promoter methylation with gene expression |
    
    ## Related Skills
    
    - `pipeline-guide` -- Parent skill with compute resource assessment and cloud setup
    - `methylation-aggregation` -- Aggregate methylation data across samples/tissues
    - `quality-assessment` -- Evaluate pipeline output quality metrics
    - `data-provenance` -- Track all pipeline inputs, outputs, and parameters
    - `download-encode` -- Download ENCODE WGBS FASTQ files for pipeline input
    - `publication-trust` -- Verify literature claims backing analytical decisions
    
    ## Presenting Results
    
    When reporting WGBS pipeline results:
    
    - **Mapping and duplication**: Report the mapping rate from `bismark/alignments/*_PE_report.txt` (>70% expected) and the duplication rate from `bismark/dedup_reports/` (<30% expected)
    - **CpG coverage depth**: Report the mean coverage of covered CpGs, the percentage reaching >=5x and >=10x, and the last line's `--min_coverage` count from `coverage/{sample}.coverage_stats.txt`, and state that these are percentages of covered CpGs rather than of all genomic CpGs
    - **Global methylation level**: Report the genome-wide average CpG methylation percentage and note any non-CpG (CHG/CHH) methylation if relevant to the tissue. Both come from the Bismark report or from the bedGraphs
    - **bedMethyl output paths**: Provide paths to the CpG bedMethyl file and the CHG/CHH context files, and state the `--min_coverage` value they were filtered at
    - **M-bias assessment**: No read positions are excluded at extraction. Report MethylDackel's suggested bounds from `bismark/mbias/{sample}_mbias_report.txt`, and say whether a manual re-extraction with `--OT`/`--OB` was done
    - **Bisulfite conversion rate**: This workflow does not compute it. If a lambda/pUC19 spike-in was aligned separately, or the CHH percentage was used as a proxy, report the number and say which method produced it (≥98% pass, 95-98% warning, <95% fail)
    - **Output summary**: Report covered CpG sites, sites passing the coverage filter, and the MultiQC report at `multiqc/multiqc_report.html`
    - **Next steps**: Suggest `methylation-aggregation` for cross-sample averaging and HMR/UMR/PMD identification
    
    ## For the request: "$ARGUMENTS"
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related