2026-03-16 HHY的chip-seq

Bowtie2 比对 参考基因集路径

FA=/refdir/database/server/reference/genome/mm10/mm10.fa

INDEX=/refdir/database/server/reference/index/bowtie/mm10

CHROMSIZES=/refdir/database/server/reference/genome/mm10/mm10.chrom.sizes

GTF=/home/data/t210424/Genome/Mouse/Mus_musculus.GRCm38.99.ucsc.gtf

工作路径/home/data/t210424/chipseq

样本信息samples.csv

环境检查

/home/data/t210424/chipseq/scripts/check_chip_env.sh

#!/usr/bin/env bash

set -euo pipefail

FA="/refdir/database/server/reference/genome/mm10/mm10.fa"

INDEX="/refdir/database/server/reference/index/bowtie/mm10"

CHROMSIZES="/refdir/database/server/reference/genome/mm10/mm10.chrom.sizes"

GTF="/home/data/t210424/Genome/Mouse/Mus_musculus.GRCm38.99.ucsc.gtf"

SAMPLE_SHEET="/home/data/t210424/chipseq/samples.csv"

echo "=== 检查软件 ==="

for x in bowtie2 samtools macs3 bamCoverage awk; do

    if command -v "$x" >/dev/null 2>&1; then

        echo "[OK] $x -> $(command -v "$x")"

    else

        echo "[MISSING] $x"

    fi

done

echo

echo "=== 检查参考文件 ==="

for f in \

    "$FA" \

    "$CHROMSIZES" \

    "$GTF" \

    "${INDEX}.1.bt2" \

    "${INDEX}.2.bt2" \

    "${INDEX}.3.bt2" \

    "${INDEX}.4.bt2" \

    "${INDEX}.rev.1.bt2" \

    "${INDEX}.rev.2.bt2" \

    "$SAMPLE_SHEET"

do

    if [[ -s "$f" ]]; then

        echo "[OK] $f"

    else

        echo "[MISSING OR EMPTY] $f"

    fi

done

echo

echo "=== 检查 samples.csv 列数 ==="

awk -F',' '{print NF}' "$SAMPLE_SHEET" | sort | uniq -c

echo

echo "=== 检查 samples.csv 前几行 ==="

head "$SAMPLE_SHEET"

echo

echo "=== 检查 samples.csv 里的 fastq 是否存在 ==="

awk -F',' 'NR>1 {print $5"\n"$6}' "$SAMPLE_SHEET" | while read -r f; do

    [[ -z "$f" ]] && continue

    if [[ -s "$f" ]]; then

        echo "[OK] $f"

    else

        echo "[MISSING OR EMPTY] $f"

    fi

done

echo

echo "=== 检查完成 ==="

QC

#Bowtie2比对参数→Samtools过滤 → 去重Markdup → 去除线粒体噪音 → Peak Calling  bigWig信号归一

#H3K36me3所以写的board宽峰

/home/data/t210424/chipseq/scripts/run_chipseq_mm10_trim_fastp.sh

#!/usr/bin/env bash

set -euo pipefail

shopt -s nullglob

SAMPLE_SHEET="${1:-/home/data/t210424/chipseq/samples.csv}"

PROJECT_DIR="${2:-/home/data/t210424/chipseq/run_trimmed}"

FA="/refdir/database/server/reference/genome/mm10/mm10.fa"

INDEX="/refdir/database/server/reference/index/bowtie/mm10"

CHROMSIZES="/refdir/database/server/reference/genome/mm10/mm10.chrom.sizes"

GTF="/home/data/t210424/Genome/Mouse/Mus_musculus.GRCm38.99.ucsc.gtf"

THREADS=8

SORT_THREADS=4

SORT_MEM="1G"

GENOME_SIZE="mm"

PEAK_MODE="broad"

MACS_QVALUE="0.01"

MAPQ=30

REMOVE_CHRM=1

MAKE_BIGWIG=1

LOG_DIR="${PROJECT_DIR}/00_logs"

FASTP_DIR="${PROJECT_DIR}/01_fastp"

BAM_DIR="${PROJECT_DIR}/02_bam"

QC_DIR="${PROJECT_DIR}/03_qc"

PEAK_DIR="${PROJECT_DIR}/04_peaks"

BW_DIR="${PROJECT_DIR}/05_bigwig"

TMP_DIR="${PROJECT_DIR}/06_tmp"

mkdir -p "${PROJECT_DIR}" "${LOG_DIR}" "${FASTP_DIR}" "${BAM_DIR}" "${QC_DIR}" "${PEAK_DIR}" "${BW_DIR}" "${TMP_DIR}"

log() {

    echo "[$(date '+%F %T')] $*"

}

die() {

    echo "[ERROR] $*" >&2

    exit 1

}

check_file() {

    [[ -s "$1" ]] || die "文件不存在或为空 $1"

}

trim_spaces() {

    local x="$1"

    x="${x#"${x%%[![:space:]]*}"}"

    x="${x%"${x##*[![:space:]]}"}"

    echo "$x"

}

declare -A FINAL_BAM

declare -A GROUP_OF

declare -A KIND_OF

declare -A INPUT_OF

process_one_sample() {

    local sample="$1"

    local group="$2"

    local kind="$3"

    local input_id="$4"

    local fq1="$5"

    local fq2="$6"

    local sample_dir="${BAM_DIR}/${sample}"

    mkdir -p "${sample_dir}"

    local fastp_log="${LOG_DIR}/${sample}.fastp.log"

    local fastp_html="${FASTP_DIR}/${sample}.fastp.html"

    local fastp_json="${FASTP_DIR}/${sample}.fastp.json"

    local trim_r1="${TMP_DIR}/${sample}.trim.R1.fastq.gz"

    local trim_r2="${TMP_DIR}/${sample}.trim.R2.fastq.gz"

    local bowtie_log="${LOG_DIR}/${sample}.bowtie2.log"

    local final_bam="${sample_dir}/${sample}.final.bam"

    local final_bai="${final_bam}.bai"

    local flagstat_txt="${QC_DIR}/${sample}.flagstat.txt"

    local idxstats_txt="${QC_DIR}/${sample}.idxstats.txt"

    local namesort_bam="${sample_dir}/${sample}.namesort.bam"

    local fixmate_bam="${sample_dir}/${sample}.fixmate.bam"

    local coordsort_bam="${sample_dir}/${sample}.coordsort.bam"

    local rmdup_bam="${sample_dir}/${sample}.rmdup.bam"

    local keep_chrom_txt="${sample_dir}/${sample}.keep_chroms.txt"

    if [[ -s "${final_bam}" && -s "${final_bai}" ]]; then

        log "跳过 ${sample},已存在最终 BAM"

        FINAL_BAM["${sample}"]="${final_bam}"

        GROUP_OF["${sample}"]="${group}"

        KIND_OF["${sample}"]="${kind}"

        INPUT_OF["${sample}"]="${input_id}"

        return

    fi

    check_file "${fq1}"

    check_file "${fq2}"

    log "开始 fastp ${sample}"

    fastp \

        -i "${fq1}" \

        -I "${fq2}" \

        -o "${trim_r1}" \

        -O "${trim_r2}" \

        --detect_adapter_for_pe \

        -q 20 \

        -l 20 \

        -w "${THREADS}" \

        -h "${fastp_html}" \

        -j "${fastp_json}" \

        > "${fastp_log}" 2>&1

    check_file "${trim_r1}"

    check_file "${trim_r2}"

    log "开始 bowtie2 ${sample}"

    bowtie2 \

        --very-sensitive \

        --no-mixed \

        --no-discordant \

        -X 2000 \

        -x "${INDEX}" \

        -1 "${trim_r1}" \

        -2 "${trim_r2}" \

        -p "${THREADS}" \

        2> "${bowtie_log}" | \

    samtools view \

        -@ "${SORT_THREADS}" \

        -b \

        -f 2 \

        -F 3852 \

        -q "${MAPQ}" \

        - | \

    samtools sort \

        -n \

        -@ "${SORT_THREADS}" \

        -m "${SORT_MEM}" \

        -T "${TMP_DIR}/${sample}.namesort" \

        -o "${namesort_bam}" \

        -

    rm -f "${trim_r1}" "${trim_r2}"

    log "fixmate ${sample}"

    samtools fixmate \

        -m \

        -@ "${SORT_THREADS}" \

        "${namesort_bam}" \

        "${fixmate_bam}"

    rm -f "${namesort_bam}"

    log "坐标排序 ${sample}"

    samtools sort \

        -@ "${SORT_THREADS}" \

        -m "${SORT_MEM}" \

        -T "${TMP_DIR}/${sample}.coordsort" \

        -o "${coordsort_bam}" \

        "${fixmate_bam}"

    rm -f "${fixmate_bam}"

    log "去重复 ${sample}"

    samtools markdup \

        -r \

        -@ "${SORT_THREADS}" \

        "${coordsort_bam}" \

        "${rmdup_bam}"

    rm -f "${coordsort_bam}"

    if [[ "${REMOVE_CHRM}" -eq 1 ]]; then

        log "去除 chrM ${sample}"

        samtools index -@ "${SORT_THREADS}" "${rmdup_bam}"

        samtools idxstats "${rmdup_bam}" | \

            cut -f1 | \

            grep -v '^chrM$' | \

            grep -v '^\*$' > "${keep_chrom_txt}"

        samtools view \

            -@ "${SORT_THREADS}" \

            -b \

            "${rmdup_bam}" \

            $(tr '\n' ' ' < "${keep_chrom_txt}") \

            -o "${final_bam}"

        samtools index -@ "${SORT_THREADS}" "${final_bam}"

        rm -f "${rmdup_bam}" "${rmdup_bam}.bai" "${keep_chrom_txt}"

    else

        mv "${rmdup_bam}" "${final_bam}"

        samtools index -@ "${SORT_THREADS}" "${final_bam}"

    fi

    log "QC 统计 ${sample}"

    samtools flagstat -@ "${SORT_THREADS}" "${final_bam}" > "${flagstat_txt}"

    samtools idxstats "${final_bam}" > "${idxstats_txt}"

    if [[ "${MAKE_BIGWIG}" -eq 1 ]]; then

        log "生成 bigWig ${sample}"

        bamCoverage \

            -b "${final_bam}" \

            -o "${BW_DIR}/${sample}.CPM.bw" \

            -p "${THREADS}" \

            --binSize 50 \

            --normalizeUsing CPM

    fi

    FINAL_BAM["${sample}"]="${final_bam}"

    GROUP_OF["${sample}"]="${group}"

    KIND_OF["${sample}"]="${kind}"

    INPUT_OF["${sample}"]="${input_id}"

    log "完成样本 ${sample}"

}

call_peaks_for_one_ip() {

    local ip_sample="$1"

    local input_sample="$2"

    local ip_bam="${FINAL_BAM[${ip_sample}]}"

    local input_bam="${FINAL_BAM[${input_sample}]}"

    local outdir="${PEAK_DIR}/${ip_sample}"

    local macs_log="${LOG_DIR}/${ip_sample}.macs2.log"

    [[ -s "${ip_bam}" ]] || die "IP BAM 不存在 ${ip_bam}"

    [[ -s "${input_bam}" ]] || die "Input BAM 不存在 ${input_bam}"

    mkdir -p "${outdir}"

    log "开始 call peak ${ip_sample} vs ${input_sample}"

    if [[ "${PEAK_MODE}" == "broad" ]]; then

        macs2 callpeak \

            -t "${ip_bam}" \

            -c "${input_bam}" \

            -f BAMPE \

            -g "${GENOME_SIZE}" \

            -n "${ip_sample}" \

            --outdir "${outdir}" \

            --broad \

            --broad-cutoff 0.1 \

            --keep-dup all \

            2> "${macs_log}"

    else

        macs2 callpeak \

            -t "${ip_bam}" \

            -c "${input_bam}" \

            -f BAMPE \

            -g "${GENOME_SIZE}" \

            -n "${ip_sample}" \

            --outdir "${outdir}" \

            -q "${MACS_QVALUE}" \

            --keep-dup all \

            2> "${macs_log}"

    fi

    log "完成 peak calling ${ip_sample}"

}

log "开始读取样本表 ${SAMPLE_SHEET}"

check_file "${SAMPLE_SHEET}"

while IFS=',' read -r sample group kind input_id fq1 fq2; do

    sample="$(trim_spaces "${sample}")"

    group="$(trim_spaces "${group}")"

    kind="$(trim_spaces "${kind}")"

    input_id="$(trim_spaces "${input_id}")"

    fq1="$(trim_spaces "${fq1}")"

    fq2="$(trim_spaces "${fq2}")"

    [[ -z "${sample}" ]] && continue

    [[ "${sample}" =~ ^# ]] && continue

    [[ "${sample}" == "sample_id" ]] && continue

    process_one_sample "${sample}" "${group}" "${kind}" "${input_id}" "${fq1}" "${fq2}"

done < "${SAMPLE_SHEET}"

log "开始 peak calling"

while IFS=',' read -r sample group kind input_id fq1 fq2; do

    sample="$(trim_spaces "${sample}")"

    kind="$(trim_spaces "${kind}")"

    input_id="$(trim_spaces "${input_id}")"

    [[ -z "${sample}" ]] && continue

    [[ "${sample}" =~ ^# ]] && continue

    [[ "${sample}" == "sample_id" ]] && continue

    if [[ "${kind}" == "ip" ]]; then

        [[ "${input_id}" == "NA" || -z "${input_id}" ]] && die "IP 样本 ${sample} 没有对应 input_id"

        [[ -n "${FINAL_BAM[${input_id}]:-}" ]] || die "IP 样本 ${sample} 对应的 input ${input_id} 未处理成功"

        call_peaks_for_one_ip "${sample}" "${input_id}"

    fi

done < "${SAMPLE_SHEET}"

log "写出最终 BAM 清单"

{

    echo "sample_id,group,kind,input_id,final_bam"

    while IFS=',' read -r sample group kind input_id fq1 fq2; do

        sample="$(trim_spaces "${sample}")"

        group="$(trim_spaces "${group}")"

        kind="$(trim_spaces "${kind}")"

        input_id="$(trim_spaces "${input_id}")"

        [[ -z "${sample}" ]] && continue

        [[ "${sample}" =~ ^# ]] && continue

        [[ "${sample}" == "sample_id" ]] && continue

        echo "${sample},${group},${kind},${input_id},${FINAL_BAM[${sample}]}"

    done < "${SAMPLE_SHEET}"

} > "${PROJECT_DIR}/final_bam_manifest.csv"

log "全部完成"

log "结果目录"

log "FASTP  ${FASTP_DIR}"

log "BAM    ${BAM_DIR}"

log "QC      ${QC_DIR}"

log "Peaks  ${PEAK_DIR}"

log "bigWig  ${BW_DIR}"

log "Logs    ${LOG_DIR}"

chmod +x /home/data/t210424/chipseq/scripts/run_chipseq_mm10_trim_fastp.sh

后台运行+日志输出

chmod +x /home/data/t210424/chipseq/scripts/run_chipseq_mm10_trim_fastp.sh

cd /home/data/t210424/chipseq

nohup stdbuf -oL -eL bash /home/data/t210424/chipseq/scripts/run_chipseq_mm10_trim_fastp.sh \

  /home/data/t210424/chipseq/samples.csv \

  /home/data/t210424/chipseq/run_trimmed \

  > /home/data/t210424/chipseq/run_trimmed.nohup.log 2>&1 &

echo $! > /home/data/t210424/chipseq/run_trimmed.pid

disown

进程查看

ps -fp $(cat /home/data/t210424/chipseq/run_trimmed.pid)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容