#!/usr/bin/make -rRf
# Pipeline for the Goldrush program
# Written by Puneet Sidhu, Johnathan Wong, Lauren Coombe, and Vladimir Nikolic
# GoldRush v1.1.0

# Input files
reads=reads

polisher=goldpolish
polished_infix=$(polisher)-polished
# ntlink or minimap2
polisher_mapper=minimap2

# Shared memory location for GoldPolish
shared_mem=/dev/shm

# ntlink mapping parameter (used if polisher_mapper=ntlink)
polish_k=32
polish_w=100

# Set max number of user processes
set_ulimit=goldrush-ulimit

ifeq ($(polisher), goldpolish)
polisher_logs=GoldPolish
else
polisher_logs=$(polisher)
endif

ifeq ($(polisher_mapper),ntlink)
goldpolish_opts=--ntlink --k-ntlink $(polish_k) --w-ntlink $(polish_w)
else ifeq ($(polisher_mapper),minimap2)
goldpolish_opts=--minimap2
else
$(error "Unknown mapper: $(polisher_mapper)")
endif

# Find the complete long read file name
fastq_uncompressed=$(shell test -f $(reads).fastq && echo "true")
ifeq ($(fastq_uncompressed), true)
long_reads=$(reads).fastq
endif
fastq_uncompressed=$(shell test -f $(reads).fq && echo "true")
ifeq ($(fastq_uncompressed), true)
long_reads=$(reads).fq
endif

define ERROR_MESSAGE
Reads file not found.
Expected reads file to be `$(reads).fastq` or `$(reads).fq`, but neither were found in the working directory.
Please check the supplied `reads` parameter in your goldrush command, and ensure that the `.fq` or `.fastq` suffix is not included.
For example, if your reads file is `my_reads.fq`, specify `reads=my_reads`
endef

# Default parameters GoldRush-Path
k=22
w=16
tile=1000
b=10
u=5
a=1
o=0.1
x=10
h=3
s=1011011110110111101101
r=0.9
M=5
p=w$(w)_x$(x)
p1=$(p)_silver_path
p2=$(p)_golden_path
P=15
d=5
m=20000
# Common parameters for scaffolding and correction tools
z=1000
t=48

# Default Tigmint parameters
span=2
dist=500
cut=250

# Default ntLink parameters
k_ntLink=40
w_ntLink=250
rounds=5

# Development mode - retains intermediate files. Specify dev=True to enable.
dev=False

# Determine path to Gold Rush executables
bin=$(shell dirname `command -v $(MAKEFILE_LIST)`)

# Use pigz or bgzip for parallel compression if available.
ifneq ($(shell command -v pigz),)
gzip=pigz -p$t
else
ifneq ($(shell command -v bgzip),)
gzip=bgzip -@$t
else
gzip=gzip
endif
endif

# Record run time and memory usage in a file using GNU time
track_time=0
ifeq ($(track_time), 0)
time=
else
ifneq ($(shell command -v gtime),)
time=command gtime -v -o $@.time
else
time=command time -v -o $@.time
endif
ifneq ($(shell command -v memusg),)
time=command memusg -t -o $@.time
endif
endif

.PHONY: help run version clean path-tigmint-ntlink path-polish goldrush-path racon goldpolish path-tigmint tigmint ntLink-with-tigmint check-G check-reads
.DELETE_ON_ERROR:
.SECONDARY:

version:
	@echo "goldrush v1.1.0"

# Help
help:
	@echo "GoldRush"
	@echo "v1.1.0"
	@echo ""
	@echo "Usage: goldrush [COMMAND] [OPTION=VALUE]…"
	@echo ""
	@echo "For example, to run the default pipeline on reads 'reads.fq' with a genome size of gsize:"
	@echo "goldrush run reads=reads G=gsize"
	@echo ""
	@echo "	Commands:"
	@echo ""
	@echo "	run			run default GoldRush pipeline: GoldRush-Path + Polisher (GoldPolish by default) + Tigmint-long + ntLink (default 5 rounds)"
	@echo ""
	@echo "	goldrush-path		run GoldRush-Path"
	@echo "	path-polish		run GoldRush-Path, then $(polisher_logs)"
	@echo "	path-tigmint		run GoldRush-Path, then $(polisher_logs), then Tigmint-long"
	@echo "	path-tigmint-ntLink	run GoldRush-Path, then $(polisher_logs), then Tigmint-long, then ntLink (default 5 rounds)"
	@echo ""
	@echo "	General options (required):"
	@echo "	reads			read name [reads]. File must have .fq or .fastq extension, but do not include the suffix in the supplied read name"
	@echo "	G			haploid genome size (bp) (e.g. '3e9' for human genome)"
	@echo ""
	@echo "	General options (optional):"
	@echo "	t			number of threads [$(t)]"
	@echo "	z			minimum size of contig (bp) to scaffold [$(z)]"
	@echo "	track_time		If 1 then track the run time and memory usage, if 0 then don't [$(track_time)]"
	@echo ""
	@echo "	GoldRush-Path options:"
	@echo "	k			base k value to generate hash [$(k)]"
	@echo "	w			weight of spaced seed (number of 1's) [$(w)]"
	@echo "	tile			tile size [$(tile)]"
	@echo "	b			during insertion, number of consecutive tiles to be inserted with the same ID [$(b)]"
	@echo "	u			minimum number of unassigned tiles for the read to be considered unassigned [$(u)]"
	@echo "	a			maximum number of tiles that can be assigned, minimum number of overlapping tiles kept after trimming [$(a)]"
	@echo "	o			occupancy of the miBF [$(o)]"
	@echo "	x			threshold for number of hits in miBF for a given frame to be considered assigned [$(x)]"
	@echo "	h			number of seed patterns to use [$(h)]"
	@echo "	s			spaced seed design [$(s)]"
	@echo "	m			minimum read length [$(m)]"
	@echo "	M			maximum number of silver paths to generate [$(M)]"
	@echo "	r			ratio of full genome in golden path [$(r)]"
	@echo "	P			minimum average phred score for each read [$(P)]"
	@echo "	d			remove reads with greater or equal than d difference between average phred quality of first half and second half of the read [$(d)]"
	@echo "	p			prefix to use for the output paths [w$(w)_x$(x)]"
	@echo ""
	@echo "	Tigmint-long options:"
	@echo "	span			min number of spanning molecules [$(span)]"
	@echo "	dist			maximum distance between alignments to be considered the same molecule [$(dist)]"
	@echo ""
	@echo "	ntLink options:"
	@echo "	k_ntLink		k-mer size for minimizers [$(k_ntLink)]"
	@echo "	w_ntLink		window size for minimizers [$(w_ntLink)]"
	@echo "	rounds			number of rounds of ntLink [$(rounds)]"
	@echo ""
	@echo "	GoldPolish options:"
	@echo "	polisher_mapper		Whether to use ntlink or minimap2 for mappings [$(polisher_mapper)]"
	@echo "	shared_mem		Shared memory path where polishing occurs [/dev/shm] "
	@echo ""
	@echo "Notes:"
	@echo "	- GoldRush-Path generates silver paths before generating the golden path"
	@echo "	- Ensure that all input files are in the current working directory, making soft-links if needed"

clean: $(p2).fa
ifneq ($(dev), True)
	rm -f $(p1)_*.fq
endif
	@echo "Clean Done"

# Set-up pipelines
run: path-tigmint-ntLink check-G check-reads clean
path-polish: $(polisher) check-G check-reads clean
path-tigmint: tigmint check-G check-reads clean

path-tigmint-ntLink: ntLink_all_rounds ntLink_softlink clean

check-G:
ifndef G
	$(error G is a required parameter. Run 'goldrush help' for more information)
endif

check-reads:
# Print error if reads file isn't found
ifeq ($(long_reads),)
	$(error $(ERROR_MESSAGE))
endif


# Run GoldRush-Path
goldrush-path: $(p2).fa check-G check-reads clean

$(p2).fa: $(p1)_all.fq
	$(time) goldrush-path  -k $(k) -w $(w) -t $(tile) -u $(u) -a $(a) -o $(o) -p $(p2) -i $< -h $(h) -j $(t) -P $(P) -d $(d) -x$(x) -s $(s) -g $(G) -b $(b)  -m 0
	echo "Done GoldRush-Path! Golden path can be found in: $@"

$(p1)_all.fq: $(p1)_$(M).fq
	cat $(p1)_*.fq > $@

$(p1)_$(M).fq: $(long_reads)
	$(time) goldrush-path  -k $(k) -w $(w) -t $(tile) -u $(u) -a $(a) -o $(o) -p $(p1) -i $<  -h $(h) -j $(t) -x$(x) -P $(P) -d $(d) -s $(s) -g $(G) -b $(b) -r $(r) --silver_path -M $(M) -m $(m)

%.racon-polished.fa: %.fa.$(long_reads).sam %.fa
	$(time) racon -u -t$(t) $(long_reads) $^ > $@
	echo "Done GoldRush-Path + $(polisher_logs)! $(polisher_logs) polished golden path can be found in: $@"

%.goldpolish-polished.fa: %.fa $(long_reads)
	$(time) $(set_ulimit) goldpolish $(goldpolish_opts) -t$(t) -m$(shared_mem) $< $(long_reads) $@
	echo "Done GoldRush-Path + $(polisher_logs)! $(polisher_logs) polished golden path can be found in: $@"

# Run racon
racon: $(p2).racon-polished.fa check-G check-reads

goldpolish: $(p2).goldpolish-polished.fa check-G check-reads

$(p2).fa.$(long_reads).sam: $(p2).fa $(long_reads)
	$(time) minimap2 -t $(t) -a -x map-ont  $< $(long_reads) > $@


# Run tigmint after GoldRush-Path
tigmint: $(p2).$(polished_infix).span$(span).dist$(dist).tigmint.fa check-G check-reads

$(p2).$(polished_infix).span$(span).dist$(dist).tigmint.fa: $(p2).$(polished_infix).cut$(cut).tigmint.fa
	ln -sf $< $@
	echo "Done GoldRush-Path + $(polisher_logs) + Tigmint-long! Post-Tigmint-long golden path can be found in: $@"

%.$(polished_infix).cut$(cut).tigmint.fa: %.$(polished_infix).fa $(long_reads)
	$(time) tigmint-make tigmint-long draft=$(p2).$(polished_infix) reads=$(reads) cut=$(cut) t=$t G=$G span=$(span) dist=$(dist)

# Run ntLink rounds after tigmint
ntLink_all_rounds: $(p2).$(polished_infix).span$(span).dist$(dist).tigmint.fa.k$(k_ntLink).w$(w_ntLink).z$z.ntLink.gap_fill.$(rounds)rounds.fa check-G check-reads

%.fa.k$(k_ntLink).w$(w_ntLink).z$z.ntLink.gap_fill.$(rounds)rounds.fa: %.fa $(long_reads)
	$(time) ntLink_rounds run_rounds_gaps target=$< t=$t k=$(k_ntLink) w=$(w_ntLink) z=$z rounds=$(rounds) reads=$(long_reads)
ifneq ($(dev), True)
	ntLink_rounds clean target=$< t=$t k=$(k_ntLink) w=$(w_ntLink) z=$z rounds=$(rounds) reads=$(long_reads)
endif

ntLink_softlink: $(p2).$(polished_infix).span$(span).dist$(dist).tigmint.fa.k$(k_ntLink).w$(w_ntLink).ntLink-$(rounds)rounds.fa check-G check-reads

%.k$(k_ntLink).w$(w_ntLink).ntLink-$(rounds)rounds.fa: %.k$(k_ntLink).w$(w_ntLink).z$z.ntLink.gap_fill.$(rounds)rounds.fa
	ln -sf $(lastword $^) $@
	echo "Done GoldRush-Path + $(polisher_logs) + Tigmint-long + $(rounds) ntLink rounds! Your final assembly can be found in: $@"
