#' @title
#' Calculate the ordering of events
#'
#' @description
#' For each event, we generate distributions of time of event occurance using profiles within clusters. These distributions are then pair wise compared and the results of all comparisons are represented in the graph space, where events are the graph nodes, and the directional edges represent that the source node event occurs significantly early than the target node. This graph is then utilized to generate the ordering.
#'
#' @param list_Tc List of matrices, where each matrix contains time course data for each 'ome'.
#' @param list_clusters List of vectors, one for each 'ome', where the order of the 'ome' should be similar to that in list_Tc. Each of these vectors contains a cluster label (assumed to be numeric and starting from 1). The length and order of the genes in these clusters should also be similar to the order in the matricies provided in list_Tc.
#' @param list_events List of matricies, where each matrix contains the time regions (and events for the centroid) generated by running the \code{calcEvents} function.
#' @param list_timeMap List of vectors, one for each 'ome', where each vector indicates the time point at which each of the 'omic' data sets were measured. For example, if a phosphoproteomics data set was measured at basal, 2minutes and 5minutes, and a proteomics data set was measured at basal, 3minutes and 5 minutes, then list_timeMap=[c(0,1,3), c(0,2,3)] (phosphoproteomics, then proteomics).
#' @param test The test used to compare the event time distributions. The choice is between a parametric or a non-parametric test:
#' \describe{
#' 		\item{\code{wilcox}}{Choosing this will result in event times being compared using the Mann Whitney U test}
#' 		\item{\code{t-test}}{Choosing this will result in event times being compared using the Students t-test}
#' }
#' @param fdrSignif The significance cutoff for FDR correction, performed after pairwise comparisons of the event times.
#' @param incrEventTh Value between 0 and 1, to define the threshold at which a phosphorylation (or increasing) event occurs. Here, a threshold of 0 corresponds to the minimum value within an interval. (Such an event is designated as 1).
#' @param decrEventTh Value between 0 and 1, to define the threshold at which a dephosphorylation (or decreasing) event occurs. A threshold of 0 corresponds to the maximum value within an interval. (Such an event is designated as -1).
#'
#'
#' @return A list with four named objects ($mat_events_withOrder, $individEventOrder, $signifs, $test) is returned, which encodes the order of the events and the clusters.
#'
#'
#' @importFrom methods is
#' @importFrom stats p.adjust wilcox.test t.test
#' @importFrom nem transitive.reduction
#' @importFrom igraph graph_from_adjacency_matrix adjacent_vertices V are.connected vertex_connectivity
#'
#' @seealso \code{\link[e1071]{cmeans}} for clustering time profiles, \code{\link{calcEvents}} for identifying events.
#'
#' @export
calculateOrder_combined <- function(list_Tc, list_clusters, list_events, list_timeMap, test="wilcox", fdrSignif=0.05, incrEventTh=0.5, decrEventTh=0.5){

	# stopifnot(is(list_Tc, "list"), length(list_Tc) > 0, (length(clusters) == nrow(Tc)), is(mat_events, "matrix"), (fdrSignif >0 && fdrSignif <= 1 ), (incrEventTh >= 0 && incrEventTh <= 1), (decrEventTh >= 0 && decrEventTh <= 1))

	if (!(test == eventOrderTest$param) && !(test == eventOrderTest$nonParam)){
		stop(paste("Test ", test, " not recognized.", sep=""))
	}

	list_list_distributions = list()
	events_combined = list_events[[1]]

	for (i in 1:length(list_Tc)){
		# 1. split into sub matricies
		list_splitMat = splitIntoSubMatrices(list_Tc[[i]], list_clusters[[i]])

		# 2. getDistOfAllEvents
		list_distributions = getDistOfAllEvents_v3(list_events[[i]], list_splitMat, incrEventTh, decrEventTh, list_timeMap[[i]])

		# 3. Combine all distributions
		list_list_distributions = c(list_list_distributions, list_distributions)

		# 4. Renumber and combine mat_events.
		if (i == 1){
			events_combined[,Col_events$combinedDatasetNum] <- rep(i, nrow(events_combined))
		}
		else {
			# add dataset number
			list_events[[i]][,Col_events$combinedDatasetNum] <-rep(i, nrow(list_events[[i]]))

			# adjust the cluster numbers
			list_events[[i]][,Col_events$clus] <- list_events[[i]][,Col_events$clus] + max(events_combined[,Col_events$clus])

			# add to the events matrix.
			events_combined <- rbind(events_combined, list_events[[i]])
		}
	}

	# 5. Run

	list_pVal_stat <- list()

	if (test==eventOrderTest$nonParam){
		print ("Running wilcoxon test.")
		list_pVal_stat <- performWilcoxonSignedRankTabular(list_list_distributions)

		title_testType = "(Non-parametric)"
	}
	else {
		print("Running t-test.")
		list_pVal_stat <- performTtestsTabular(list_list_distributions)

		title_testType = "(Parametric)"
	}

	# FDR adjustment for multiple testing.
	mat_pValsFDR <- matrix(stats::p.adjust(as.vector(list_pVal_stat[[1]]), method='fdr'), ncol=nrow(events_combined))

	# Convert to adjacency matrix.
	signifs <- mat_pValsFDR < fdrSignif
	statistic_t <- list_pVal_stat[[2]]
	statistic_t[!signifs] <- NA

	statistic_t[statistic_t > 0] <- NA
	statistic_t[is.na(statistic_t)] <- 0
	statistic_t[statistic_t < 0] <- 1

	# library(nem) # for trasitive reduction
	# library(igraph) # for adjacency matrix
	reducted <- nem::transitive.reduction(statistic_t)
	net = igraph::graph_from_adjacency_matrix(reducted, mode="directed")

	list_eventsOrder <- getEventsOrderInGraph(reducted, net) # computing the order of the events in the mat_events based on a bfs search.
	list_eventsOrder <- adjustEvents(list_eventsOrder, signifs)

	mat_events_withOrder <- appendOrder(events_combined, list_eventsOrder)

	res <- list(mat_events_withOrder, list_eventsOrder, signifs, test)
	names(res) <- c("mat_events_withOrder", "individEventOrder", "signifs", "test")
	return (res)

}

#' @title
#' Visualize the order of events for a multiomics data set.
#'
#' @description
#' A plot depicting the temporal order of events is generated. The order is shown using two visualizations, event maps (top) and event sparklines (bottom). The event sparkline is a summary of the event map.
#'
#' @param theOrder A list containing information regarding the order of events and clusters generated via the \code{calculateOrder} function.
#'
#'
#' @return A plot containing the ordered clusters by occurance of first event is generated (see description).
#'
#'
#' @importFrom methods is
#' @importFrom graphics plot segments axis rect text lines
#' @importFrom shape Arrows
#'
#' @seealso \code{\link{calculateOrder}}
#'
#' @export
visualizeOrder_combined <- function(theOrder){
# Visualise the ordering of events

	stopifnot(is(theOrder, "list"), length(theOrder) == 4)

	mat_events_withOrder <- theOrder$mat_events_withOrder
	list_eventsOrder <- theOrder$individEventOrder
	signifs <- theOrder$signifs
	test <- theOrder$test

	title_testType = ""
	## Getting other things ready for plotting

	if (test==eventOrderTest$nonParam){
		title_testType = "(Non-parametric)"
	}
	else {
		title_testType = "(Parametric)"
	}

	# plotting constants
	sigEventsDiff_x = 0.5
	nonSigEventsDiff_x = 0.25

	eventPtGraph_y = -1
	yLabelInit = -1.8
	yLabelSpace = 0.5

	lineDiff_y = 1

	# graphXStart = -1
	eventStart_x = 0

	blockSpacingFmEvent_x = sigEventsDiff_x/2
	blockStart_x = eventStart_x - blockSpacingFmEvent_x

	#x_lineStart, y_lineStart, y_lineDecr, x_incr_sig, x_incr_nonSig

	yPos_eventPts = -1

	# plotting values

	list_blocks <- getRectBlock(list_eventsOrder, signifs)
	# print(list_blocks)

	mat_eventPoints <- getTheClusLines(mat_events_withOrder, list_eventsOrder, signifs, list_blocks, eventStart_x, sigEventsDiff_x, nonSigEventsDiff_x, lineDiff_y)

	eventEnd_x = max(as.numeric(mat_eventPoints[,cols_matFifty$col_x])) #  + blockSpacingFmEvent_x
	blockEnd_x = eventEnd_x + blockSpacingFmEvent_x

	mat_bgRects <- getRectPoints(mat_eventPoints, list_blocks, blockStart_x, blockSpacingFmEvent_x)

	# mat_eventPoints <- adjustByBgRects(mat_bgRects, list_eventsOrder, mat_eventPoints)

	mat_grayLines <- getGrayLines(mat_eventPoints, signifs)

	mat_grayLines_v2 <- getGrayLines_v2(list_eventsOrder, mat_eventPoints, signifs)

	mat_clusConnLines <- getClusConnLines(mat_eventPoints, blockStart_x, blockEnd_x)

	# make all the down clusConnLines to opaque
	mat_clusConnLines <- makeDecrBarOpaque(mat_clusConnLines, TRUE)

	# a set of points to set up the graph.
	# print(mat_eventPoints)
	graphics::plot(mat_eventPoints[,cols_matFifty$col_x], mat_eventPoints[,cols_matFifty$col_y], asp=NA, yaxt="n", lwd=0.25, col=colors_orderedEvents$incr, pch=".", xlab="Temporal order", ylab="Clusters",  main=paste("Temporal order of events in clusters", title_testType, sep=""), xlim=c(eventStart_x, eventEnd_x), ylim=c(-4, max(as.numeric(mat_eventPoints[,cols_matFifty$col_clus]))), xaxt="n", bty="n", cex.main = 0.8) #,
	# print("over here..")
	# background gray rectangles.
	if (nrow(mat_bgRects) > 0){
		for (rowNum in 1:nrow(mat_bgRects)){
			if (rowNum%%2 == 1){
				graphics::rect(mat_bgRects[rowNum,1], lineDiff_y/2, mat_bgRects[rowNum,2], max(as.numeric(mat_eventPoints[,cols_matFifty$col_clus])) + (lineDiff_y/2), col = "#ededed", border=NA)
			}

		}
	}

	graphics::segments(x0=as.numeric(mat_grayLines[,cols_clusPlotObjs$col_x0]), y0=as.numeric(mat_grayLines[,cols_clusPlotObjs$col_y0]), x1=as.numeric(mat_grayLines[,cols_clusPlotObjs$col_x1]), y1=as.numeric(mat_grayLines[,cols_clusPlotObjs$col_y1]), col="#808080", lty="dotted", lwd=0.5)
	# C99999

	# rect(-0.5, 0, 0.5, 17.5, col = "yellow", border="#ededed")

	# the cluster lines
	graphics::segments(x0=as.numeric(mat_clusConnLines[,cols_clusPlotObjs$col_x0]), y0=as.numeric(mat_clusConnLines[,cols_clusPlotObjs$col_y0]), x1=as.numeric(mat_clusConnLines[,cols_clusPlotObjs$col_x1]), y1=as.numeric(mat_clusConnLines[,cols_clusPlotObjs$col_y1]), col=mat_clusConnLines[,cols_clusPlotObjs$col_col], lwd=16, lend=2)

	# the events (arrows) within a graph

	# print(mat_events_withOrder)
	# print(max(mat_events_withOrder[,Col_events$combinedDatasetNum]))
	# print(mat_eventPoints)
	# return ()

	# gray lines in events points maps
	straightGrayLines = mat_grayLines_v2[mat_grayLines_v2[,cols_grayLines_v2$col_isSemiCirc] == FALSE,]
	graphics::segments(x0=as.numeric(straightGrayLines[,cols_grayLines_v2$col_x0]), y0=rep(yPos_eventPts, length(straightGrayLines)), x1=as.numeric(straightGrayLines[,cols_grayLines_v2$col_x1]), y1=rep(yPos_eventPts, length(straightGrayLines)), lwd=1, col="#A2A2A2") #, lty="dotted")

	# gray curves in events points map
	mat_curvePoints = mat_grayLines_v2[mat_grayLines_v2[,cols_grayLines_v2$col_isSemiCirc] == TRUE,,drop=FALSE]

	if (length(mat_curvePoints) > 0 && nrow(mat_curvePoints) > 0){
		for (i in 1:nrow(mat_curvePoints)){
			list_pts = calcCurves(mat_curvePoints[i, cols_grayLines_v2$col_x0], mat_curvePoints[i, cols_grayLines_v2$col_x1], -1)
			graphics::lines(list_pts[[1]], list_pts[[2]], col="#A2A2A2")
		}
	}

	## plotting arrows in event map & event sparkline.

	# printing up and down events (in arc events map)
	y_adjust = 0.15

	for (i in 1:length(Color_multiomics)) {

		mat_upEvents = mat_eventPoints[mat_eventPoints[,cols_matFifty$col_dir] == Color_multiomics[[i]]$incr,]

		mat_downEvents = mat_eventPoints[mat_eventPoints[,cols_matFifty$col_dir] == Color_multiomics[[i]]$decr,]

		### Event map.
		## arrow bottoms
		shape::Arrows(x0=as.numeric(mat_upEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_upEvents[,cols_matFifty$col_x]), y0=as.numeric(mat_upEvents[,cols_matFifty$col_y])-0.01-0.2,  y1=as.numeric(mat_upEvents[,cols_matFifty$col_y])-0.01, arr.type="triangle", arr.length=0.01, arr.width=0.01, col=Color_multiomics[[i]]$incr, lwd=2, lend=2, arr.adj=0)

		shape::Arrows(x0=as.numeric(mat_downEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_downEvents[,cols_matFifty$col_x]), y0=as.numeric(mat_downEvents[,cols_matFifty$col_y])+0.25,  y1=as.numeric(mat_downEvents[,cols_matFifty$col_y])+0.25-0.2, arr.type="triangle", arr.length=0.01, arr.width=0.01, col=Color_multiomics[[i]]$decr, lwd=2, lend=2, arr.adj=0)

		## arrow bottoms
		shape::Arrows(x0=as.numeric(mat_upEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_upEvents[,cols_matFifty$col_x]), y0=as.numeric(mat_upEvents[,cols_matFifty$col_y])-0.01-0.2,  y1=as.numeric(mat_upEvents[,cols_matFifty$col_y])-0.01, arr.type="triangle", arr.length=0.01, arr.width=0.01, col=Color_multiomics[[i]]$incr, lwd=2, lend=2, arr.adj=0)

		shape::Arrows(x0=as.numeric(mat_downEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_downEvents[,cols_matFifty$col_x]), y0=as.numeric(mat_downEvents[,cols_matFifty$col_y])+0.25,  y1=as.numeric(mat_downEvents[,cols_matFifty$col_y])+0.25-0.2, arr.type="triangle", arr.length=0.01, arr.width=0.01, col=Color_multiomics[[i]]$decr, lwd=2, lend=2, arr.adj=0)

		## sharp arrow heads
		shape::Arrows(x0=as.numeric(mat_upEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_upEvents[,cols_matFifty$col_x]), y0=as.numeric(mat_upEvents[,cols_matFifty$col_y])-0.01-0.2,  y1=as.numeric(mat_upEvents[,cols_matFifty$col_y])-0.01, arr.type="triangle", arr.length=0.13, arr.width=0.15, col=Color_multiomics[[i]]$incr, arr.adj=0, segment=FALSE)

		shape::Arrows(x0=as.numeric(mat_downEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_downEvents[,cols_matFifty$col_x]), y0=as.numeric(mat_downEvents[,cols_matFifty$col_y])+0.25,  y1=as.numeric(mat_downEvents[,cols_matFifty$col_y])+0.25-0.2, arr.type="triangle", arr.length=0.13, arr.width=0.15, col=Color_multiomics[[i]]$decr, arr.adj=0, segment=FALSE)

		### Event sparkline

		## arrow bottom lines
		shape::Arrows(x0=as.numeric(mat_upEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_upEvents[,cols_matFifty$col_x]), y0=rep(-1.2, nrow(mat_upEvents)), y1=rep(-1, nrow(mat_upEvents)), arr.type="triangle", arr.length=0.01, arr.width=0.01, col=Color_multiomics[[i]]$incr, lwd=2, lend=2, arr.adj=0)

		shape::Arrows(x0=as.numeric(mat_downEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_downEvents[,cols_matFifty$col_x]), y0=rep(-0.8, nrow(mat_downEvents)), y1=rep(-1, nrow(mat_downEvents)), arr.type="triangle", arr.length=0.01, arr.width=0.01, col=Color_multiomics[[i]]$decr, lwd=2, lend=2, arr.adj=0)

		## sharp arrow heads
		shape::Arrows(x0=as.numeric(mat_upEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_upEvents[,cols_matFifty$col_x]), y0=rep(-1.2, nrow(mat_upEvents)), y1=rep(-1, nrow(mat_upEvents)), arr.type="triangle", arr.length=0.13, arr.width=0.15, col=Color_multiomics[[i]]$incr, arr.adj=0, segment=FALSE)

		shape::Arrows(x0=as.numeric(mat_downEvents[,cols_matFifty$col_x]), x1=as.numeric(mat_downEvents[,cols_matFifty$col_x]), y0=rep(-0.8, nrow(mat_downEvents)), y1=rep(-1, nrow(mat_downEvents)), arr.type="triangle", arr.length=0.13, arr.width=0.15, col=Color_multiomics[[i]]$decr, arr.adj=0, segment=FALSE)
	}

	vec_labels <- getYaxisLabels(mat_eventPoints)
	mat_labels <- adjustLabelsByDataset(mat_events_withOrder, vec_labels)

	# axis labels on sides 2 and 4.
	Map(axis, side=2, at=seq(1,nrow(mat_labels)), col.axis=rev(mat_labels[,Col_labels$color]), labels=rev(mat_labels[,Col_labels$label]), lwd=0, las=1)
	graphics::axis(2,at=seq(1,nrow(mat_labels)),labels=FALSE, col=NA)

	Map(axis, side=4, at=seq(1,nrow(mat_labels)), col.axis=rev(mat_labels[,Col_labels$color]), labels=rev(mat_labels[,Col_labels$label]), lwd=0, las=1)
	graphics::axis(4,at=seq(1,nrow(mat_labels)),labels=FALSE, col=NA)

	# graphics::axis(side=4, las=1, at=seq(1,length(vec_labels)), labels=rev(vec_labels), cex=0.02,  col = NA ) #, col.ticks = 1)

	# x label text.
	mat_xLabelsClus <- getXaxisLabels(list_eventsOrder, mat_eventPoints, signifs, list_blocks, eventStart_x, sigEventsDiff_x, nonSigEventsDiff_x, yLabelInit, yLabelSpace);
	print(as.numeric(mat_xLabelsClus[,3]))

	mat_xLabels <- adjustLabelsByDataset(mat_events_withOrder, as.numeric(mat_xLabelsClus[,3]))

	mat_xLabelsClus[,3] <- mat_xLabels[,Col_labels$label]

	graphics::text(x=as.numeric(mat_xLabelsClus[,1]), y=as.numeric(mat_xLabelsClus[,2]), labels=mat_xLabelsClus[,3], offset=0, cex=0.5, col=mat_xLabelsClus[,4])

}

adjustLabelsByDataset_forMat <- function(mat_events_withOrder, vec_labels){
	mat_labels = matrix(ncol=2, nrow=length(vec_labels))

	for (i in 1:length(vec_labels)){
		# print(vec_labels[i])
		datasetNums <- mat_events_withOrder[mat_events_withOrder[,Col_events$clus] == vec_labels[i],Col_events$combinedDatasetNum]

		dsNum = datasetNums[1]

		if (dsNum > 1) {
			theRows <- mat_events_withOrder[,Col_events$combinedDatasetNum] == (dsNum - 1)

			maxClusNumOfPrev <- max(mat_events_withOrder[theRows, Col_events$clus])

			adjustedClusNum <- vec_labels[i] - maxClusNumOfPrev

			mat_labels[i, Col_labels$label] = adjustedClusNum
			mat_labels[i, Col_labels$color] = Color_multiomics[[dsNum]]$incr

			# print(paste(vec_labels[i], dsNum, maxClusNumOfPrev, adjustedClusNum))

		}
		else{
			mat_labels[i, Col_labels$label] = vec_labels[i]
			mat_labels[i, Col_labels$color] = Color_multiomics[[dsNum]]$incr

		}

	}

	return(mat_labels)
}

adjustLabelsByDataset <- function(mat_events_withOrder, vec_labels){
	mat_labels = matrix(ncol=2, nrow=length(vec_labels))

	for (i in 1:length(vec_labels)){
		# print(vec_labels[i])
		datasetNums <- mat_events_withOrder[mat_events_withOrder[,Col_events$clus] == vec_labels[i],Col_events$combinedDatasetNum]

		dsNum = datasetNums[1]

		if (dsNum > 1) {
			theRows <- mat_events_withOrder[,Col_events$combinedDatasetNum] == (dsNum - 1)

			maxClusNumOfPrev <- max(mat_events_withOrder[theRows, Col_events$clus])

			adjustedClusNum <- vec_labels[i] - maxClusNumOfPrev

			mat_labels[i, Col_labels$label] = adjustedClusNum
			mat_labels[i, Col_labels$color] = Color_multiomics[[dsNum]]$incr

			# print(paste(vec_labels[i], dsNum, maxClusNumOfPrev, adjustedClusNum))

		}
		else{
			mat_labels[i, Col_labels$label] = vec_labels[i]
			mat_labels[i, Col_labels$color] = Color_multiomics[[dsNum]]$incr

		}

	}

	return(mat_labels)
}

#############################

getDistOfAllEvents_v3 <- function(mat_fiftyPoints, list_matrices, phosTh, dephosTh, timeMap){
	list_distributions <- list()

	for (eventNum in 1:nrow(mat_fiftyPoints)){
		# print(paste("Eventnum ", eventNum, "--------------------------------------------------------------------"))
		startTp <- mat_fiftyPoints[eventNum, cols_matFifty_v2$startTp]
		endTp <- mat_fiftyPoints[eventNum, cols_matFifty_v2$endTp]
		dist <- genDistForEvent_v2(list_matrices[[mat_fiftyPoints[eventNum,cols_matFifty_v2$clus]]], mat_fiftyPoints[eventNum, cols_matFifty_v2$dir], mat_fiftyPoints[eventNum, cols_matFifty_v2$startTp], mat_fiftyPoints[eventNum, cols_matFifty_v2$endTp], phosTh, dephosTh, timeMap)

		list_distributions[[length(list_distributions) + 1]] <-  dist
	}

	return(list_distributions)
}

genDistForEvent_v2 <- function(clusMat, dir, startTp, endTp, phosTh, dephosTh, timeMap){
	mat_distribution <- matrix(ncol=4)

	for (profNum in 1:nrow(clusMat)){

		if ((dir == 1 && clusMat[profNum, startTp] < clusMat[profNum, endTp]) || (dir == -1 && clusMat[profNum, startTp] > clusMat[profNum, endTp])){
			# direction holds; do calculation, and save.
			# print(clusMat[profNum, startTp:endTp])

			crossPt <- calcCrossing_v4(clusMat[profNum, startTp:endTp], dir, (startTp -1), phosTh, dephosTh, timeMap)

			mat_distribution <- addToMatrix(mat_distribution, profNum, crossPt[1], crossPt[2], dir)

		}
		else{
			mat_distribution <- addToMatrix(mat_distribution, profNum, NA, NA, dir)
		}
	}

	mat_distribution <- mat_distribution[-1,, drop=FALSE]
	return (mat_distribution)
}

calcCrossing_v4 <- function(region, dir, offset, phosTh, dephosTh, timeMap){

	x_50 <- -1 # initial time
	y_50 <- -1 # initial th_point

	y_max <- max(region)
	y_min <- min(region)

	if (dir == 1){
		y_10Percent <- (y_max - y_min) * phosTh
		y_50 <- y_min + y_10Percent
	}
	else{
		y_10Percent <- (y_max - y_min) * (1- dephosTh)
		y_50 <- y_min + y_10Percent
	}

	e = 0.0001 # due to calculation some round error when threshold is 0.
	# find intervals and store
	for (j in 2:length(region)){

		if (dir == 1 && ( (y_50 >= region[j-1] && y_50 <= region[j]) || abs(y_50 - region[j-1]) < e  || abs(y_50 - region[j]) < e )){
			# 50 is crossed here in phos direction
			# print(paste("Orig", (offset+j-1), " ", offset+j))
			x_50 <- getMidX_v2(timeMap[(offset+j-1)], region[j-1], timeMap[offset+j], region[j], y_50)
			# mat_fiftyPoints <- addToMatrix(mat_fiftyPoints, clusNum, x_50, y_50, 1)
		}
		else if (dir == -1 && ( (y_50 <= region[j-1] && y_50 >=region[j]) || abs(y_50 - region[j-1]) < e  || abs(y_50 - region[j]) < e ) ){
			# 50 is crossed here in dephos direction
			# getMidX()
			# print(paste("Orig", (offset+j-1), " " , offset+j))
			x_50 <- getMidX_v2(timeMap[(offset+j-1)], region[j-1], timeMap[offset+j], region[j], y_50)
			# mat_fiftyPoints <- addToMatrix(mat_fiftyPoints, clusNum, x_50, y_50, -1)

		}
	}

	return (c(x_50, y_50))
}

getMidX_v2 <- function(x1, y1, x2, y2, y_50){

	m <- (y2 - y1)/(x2 - x1)
	x_50 <- x1 + ((y_50 - y1)/m)

	# print(paste(x1, " ", x2, " ", x_50))
	return (x_50)
}


#Title: Fitting decay curve 6time
#Auther: Naoto Imamachi
#ver: 1.0.0
#Date: 2014-08-29

#Time############################
args <- commandArgs(trailingOnly = T)
filename <- args[1]
hour_list <- args[2]
#hour_list <- "0,1,2,4,8,12"
hour <- unlist(strsplit(hour_list,","))
hour <- as.numeric(hour)
first_sample <- 5 - 1
last_sample <- 5 + length(hour) - 1 - 1

fitting_optim_siRNA <- function(i){
fname <- paste(i,"_rel_normalized.fpkm_table",sep="")
output <- paste(i,"_rel_normalized_cal.fpkm_table",sep="")
all_data <- read.table(fname,row.names=1,header=T,sep="\t")
sample_id <- row.names(all_data)

cat("id","value","model1","cor1","a_1","half1_1","half1_2","AIC1","model2","cor2","a_2","b_2","half2",
      "AIC2","model3","cor3","a_3","b_3","c_3","half3","AIC3",sep="\t",file=output)
cat("\n",file=output,append=T)

for(x in sample_id){
	mRNA <- all_data[x,]
	mRNA <- as.numeric(mRNA)
	mRNA <- mRNA[first_sample:last_sample]
	dat <- data.frame(hour,mRNA)
	dat <- dat[dat$mRNA > 0,]
	dat_point <- length(dat$mRNA)
	cat(x,"\t",sep="",file=output,append=T)

   if(mRNA[1] >= 1){
	if(dat_point >= 3){
		cat("ok","\t",sep="",file=output,append=T)
		size <- length(dat[,"mRNA"])

		#model1:y = exp(-a * t)
		optim1 <- function(x){
			mRNA_exp <- exp(-x * dat[,"hour"])
			sum((dat[,"mRNA"]-mRNA_exp)^2)
		}

		out1 <- optim(1,optim1)
		min1 <- out1$value
		a_1 <- out1$par[1]
		half1_1 <- log(2) / a_1

		model1_pred <- function(x){
			mRNA_exp <- exp(-x * dat[,"hour"])
			(cor(mRNA_exp,dat[,"mRNA"],method="pearson"))^2
		}
		cor1 <- model1_pred(a_1)

		model1_half <- function(x){
			mRNA_half <-  exp(- a_1 * x)
			(mRNA_half - 0.5)^2
		}

		out1 <- optim(1,model1_half)
		half1_2 <- out1$par
		mRNA_pred <- exp(- a_1 * dat[,"hour"])
		s2 <-  sum((dat[,"mRNA"] - mRNA_pred )^2 )/ size
		AIC1 <- size * log(s2)+ 2 * 0

		cat(min1,cor1,a_1,half1_1,half1_2,AIC1,sep="\t",file=output,append=T)
		cat("\t",file=output,append=T)

		#model2:y = A * exp(-b * t) + c
		optim2 <- function(x){
			mRNA_exp <- (1.0 - x[2]) * exp(-x[1] * dat[,"hour"]) + x[2]
			sum((dat[,"mRNA"]-mRNA_exp)^2)
		}

		out2 <- optim(c(1,0),optim2)
		min2 <- out2$value
		a_2 <-  out2$par[1]
		b_2 <-  out2$par[2]

		model2_pred <- function(a,b){
			mRNA_exp <- (1- b) * exp(-a * dat[,"hour"]) + b
			(cor(mRNA_exp,dat[,"mRNA"],method="pearson"))^2
		}

		cor2 <- model2_pred(a_2,b_2)

		model2_half <- function(x){
			mRNA_half <-  (1 - b_2) * exp(- a_2 * x) + b_2
			(mRNA_half - 0.5)^2
		}

		out2 <- optim(1,model2_half)
		half2 <- out2$par

        if(b_2 >= 0.5){
         half2 <- Inf
        }

        mRNA_pred <- (1 - b_2) * exp(- a_2 * dat[,"hour"]) + b_2
        s2 <-  sum((dat[,"mRNA"] - mRNA_pred )^2 )/ size
        AIC2 <- size * log(s2)+ 2 * 1

		cat(min2,cor2,a_2,b_2,half2,AIC2,sep="\t",file=output,append=T)
		cat("\t",file=output,append=T)

		#model3:y = A * exp(-b * t) + (1 - A) * exp (-c * t)

		optim3 <- function(x){
			mRNA_exp <- x[3] * exp(-x[1] * dat[,"hour"]) + (1 - x[3]) * exp(- x[2] * dat[,"hour"])
			sum((dat[,"mRNA"]-mRNA_exp)^2)
		}

		out3 <- optim(c(1,1,0.1),optim3)
		min3 <- out3$value
		a_3 <- out3$par[1]
		b_3 <- out3$par[2]
		c_3 <- out3$par[3]

		model3_pred <- function(a,b,c){
			mRNA_exp <- c * exp(-a * dat[,"hour"]) + (1 - c) * exp(- b * dat[,"hour"])
			(cor(mRNA_exp,dat[,"mRNA"],method="pearson"))^2
		}

		cor3 <- model3_pred(a_3,b_3,c_3)

		model3_half <- function(x){
			mRNA_half <- c_3 * exp(- a_3 * x) +(1 - c_3) * exp(- b_3  * x)
			(mRNA_half - 0.5)^2
		}

		out3 <- optim(1,model3_half)
		half3 <- out3$par
		mRNA_pred <- c_3 * exp(- a_3 * dat[,"hour"]) + (1 - c_3) * exp(- b_3 * dat[,"hour"])
		s2 <-  sum((dat[,"mRNA"] - mRNA_pred )^2 )/ size
		AIC3 <- size * log(s2)+ 2 * 2

		cat(min3,cor3,a_3,b_3,c_3,half3,AIC3,sep="\t",file=output,append=T)
		cat("\n",file=output,append=T)

		} else {
			cat("few_data","\n",sep="",file=output,append=T)
			next
		}
		}else{
			cat("low_expresion","\n",sep="",file=output,append=T)
			next;
		}

}

}

fitting_optim_siRNA(filename)


" Пусть вектор w создан из значений разного типа
Выяснить правило, по которому выполняется преобразование данных разных типов,
хранящихся в векторе. Для этого последовательно создать вектора с данными одного
типа, двух типов, трех типов и т.д. Перебрать все возможные сочетания типов."

w <- c(2,TRUE, "char", 3.4)
#Правило:
#Logical -> integer -> double ->  character


#' Calculate PROGENy pathway scores from gene expression
#'
#' This function uses the linear model of pathway-responsive genes underlying
#' the PROGENy method. It transforms a gene expression matrix with HGNC/MGI gene
#' symbols in rows and sample names in columns into a pathway score matrix with
#' samples in rows and pathways in columns.
#'
#' The publication of the method is available at:
#' https://www.nature.com/articles/s41467-017-02391-6
#'
#' The supplied expression object has to contain HGNC/MGI symbols in rows. This
#' will, in most cases (and how we originally used it), be either normalized
#' gene expression of a microarray experiment or log-transformed (and
#' possible variance-stabilized) counts from an RNA-seq experiment.
#'
#' The human and mouse model matrices consists of 14 pathways and large set of
#' genes with an associated p-value (p-value per gene and pathway) that accounts
#' for the importance of each gene on each pathway upon perturbation.
#' Its coefficients are non-zero if the gene-pathway pair corresponds
#' to the top N genes (100 by default) that were up-regulated upon stimulation
#' of the pathway in a wide range of experiments. The value corresponds to the
#' fitted z-score across experiments in our model fit.
#' Only rows with at least one non-zero coefficient were included, as the rest
#' is not used to infer pathway activity.
#'
#' @param expr   A gene expression object with HGNC/MGI symbols in rows and
#'               samples in columns. In order to run PROGENy in single-cell
#'               RNAseq data, it also accepts Seurat and SingleCellExperiment
#'               object, taking the normalized counts for the computation.
#' @param scale  A logical value indicating whether to scale the scores of each
#'               pathway to have a mean of zero and a standard deviation of one.
#'               It does not apply if we use permutations.
#' @param organism The model organism - "Human" or "Mouse"

#' @param top    The top n genes for generating the model matrix according to
#'               significance (p-value)
#' @param perm   An interger detailing the number of permutations. No
#'               permutations by default (1). When Permutations larger than 1,
#'               we compute progeny pathway scores and assesses their
#'               significance using a gene sampling-based permutation strategy,
#'               for a series of experimental samples/contrasts.
#' @param verbose    A logical value indicating whether to display a message
#'                   about the number of genes used per pathway to compute
#'                   progeny scores (i.e. number of genes present in the
#'                   progeny model and in the expression dataset)
#' @param z_scores Only applies if the number of permutations is greater than 1.
#'                 A logical value. TRUE: the z-scores will be returned for
#'                 the pathway activity estimations. FALSE: the function returns
#'                 a normalized z-score value between -1 and 1.
#' @param get_nulldist Only applies if the number of permutations is greater
#'                 than 1. A logical value. TRUE: the null distributions
#'                 generated to assess the signifance of the pathways scores
#'                 is also returned.
#' @param assay_name Only applies if the input is a Seurat object. It selects the
#'               name of the assay on which Progeny will be run. Default to:
#'               RNA, i.e. normalized expression values.
#' @param return_assay Only applies if the input is a Seurat object. A logical
#'               value indicating whether to return progeny results as a new
#'               assay called Progeny in the Seurat object used as input.
#'               Default to FALSE.
#' @param ...    Additional arguments to be passed to the functions.
#'
#' @return       A matrix with samples in rows and pathways in columns. In case
#'               we run the method with permutations and the option get_nulldist
#'               to TRUE, we will get a list with two elements. The first
#'               element is the matrix with the pathway activity as before.
#'               The second elements is the null distributions that we generate
#'               to assess the signifance of the pathways scores.
#' @export
#' @seealso \code{\link{progenyPerm}}
#' @examples
#' # use example gene expression matrix here, this is just for illustration
#' gene_expression <- as.matrix(read.csv(system.file("extdata",
#' "human_input.csv", package = "progeny"), row.names = 1))
#'
#' # calculate pathway activities
#' pathways <- progeny(gene_expression, scale=TRUE,
#'     organism="Human", top = 100, perm = 1)
progeny = function(expr, scale=TRUE, organism="Human", top = 100, perm = 1,
    verbose = FALSE, z_scores = FALSE, get_nulldist = FALSE, assay_name = "RNA",
    return_assay = FALSE, ...) {
    UseMethod("progeny")
}

#' @export
progeny.ExpressionSet = function(expr, scale=TRUE, organism="Human", top = 100,
    perm = 1, verbose = FALSE, z_scores = FALSE, get_nulldist = FALSE, ...) {

    progeny(Biobase::exprs(expr), scale=scale, organism=organism, top=top,
        perm = perm, verbose = verbose,  z_scores = z_scores,
        get_nulldist = get_nulldist)
}

#' @export
progeny.Seurat = function(expr, scale=TRUE, organism="Human", top = 100,
    perm = 1, verbose = FALSE, z_scores = FALSE, get_nulldist = FALSE,
    assay_name = "RNA", return_assay = FALSE,...) {

    requireNamespace("Seurat")

    if (!is.logical(return_assay)){
        stop("return_assay should be a logical value")
    }

    if (scale & return_assay){
        warning("Scale and return_assay should not be both true.
        Please use the function Seurat::ScaleData(object, assay = \"progeny\")
        to scale PROGENy scores. Scale is set to FALSE")
        scale = FALSE
    }

    results <- progeny(as.matrix(Seurat::GetAssayData(expr, slot = "data",
        assay = assay_name)), scale=scale, organism=organism, top=top,
        perm = perm, verbose = verbose, z_scores = z_scores,
        get_nulldist = get_nulldist, assay_name = assay_name,
        return_assay = return_assay)

    if (return_assay){
        expr[['progeny']] = Seurat::CreateAssayObject(data = t(results))
        Seurat::Key(object = expr[['progeny']]) <- 'progeny_'
        return(expr)
    } else {
        return(results)
    }

}

#' @export
progeny.SingleCellExperiment =  function(expr, scale=FALSE, organism="Human",
    top = 100, perm = 1, verbose = FALSE, z_scores = FALSE,
    get_nulldist = FALSE, ...) {

    requireNamespace("SingleCellExperiment")

    progeny(as.matrix(SingleCellExperiment::normcounts(expr)), scale=scale,
        organism=organism, top=top, perm = perm, verbose = verbose,
        z_scores = z_scores, get_nulldist = get_nulldist)
}

#' @export
progeny.matrix = function(expr, scale=TRUE, organism="Human", top = 100,
    perm = 1, verbose = FALSE,  z_scores = FALSE, get_nulldist = FALSE,...) {

    if (!is.logical(scale)){
        stop("scale should be a logical value")
    }

    if (!(is.numeric(perm)) || perm < 1){
        stop("perm should be an integer value")
    }

    if (!is.logical(verbose)){
        stop("verbose should be a logical value")
    }

    if (!is.logical(z_scores)){
        stop("z_scores should be a logical value")
    }

    if (!is.logical(get_nulldist)){
        stop("get_nulldist should be a logical value")
    }

    if (perm == 1 && (z_scores || get_nulldist)){
        if (verbose){
            message("z_scores and get_nulldist are only applicable when the
                number of permutations is larger than 1.")
        }
    }

    model <- getModel(organism, top=top)
    common_genes <- intersect(rownames(expr), rownames(model))

    if (verbose){
        number_genes <- apply(model, 2, function (x) {
            sum(rownames(model)[which (x != 0)] %in% unique(rownames(expr)))
        })
        message("Number of genes used per pathway to compute progeny scores:")
        message(paste(names(number_genes),": ", number_genes, " (",
            (number_genes/top)*100,"%)",sep = "","\n"))
    }

    if (perm==1) {
        result <- t(expr[common_genes,,drop=FALSE]) %*%
            as.matrix(model[common_genes,,drop=FALSE])

        if (scale && nrow(result) > 1) {
            rn <- rownames(result)
            result <- apply(result, 2, scale)
            rownames(result) <- rn
        }

    } else if (perm > 1) {
      expr <- data.frame(names = row.names(expr), row.names = NULL, expr)
      model <- data.frame(names = row.names(model), row.names = NULL, model)
      result <- progenyPerm(expr, model, k = perm, z_scores = z_scores,
          get_nulldist = get_nulldist)
    }

    return(result)
}

#' @export
progeny.default = function(expr, scale=TRUE, organism="Human", top = 100,
    perm = 1, verbose = FALSE, z_scores = FALSE, get_nulldist = FALSE, ...) {
    stop("Do not know how to access the data matrix from class ", class(expr))
}


# Auteurs :Philippe Pieri, Benjamin Bois - INRA, Equipe Ecophysiologie et Agronomie Viticole; 71, Rue Edouard Bourlaux B.P. 81, 33 883 VILLENAVE DORNON Cedex- contact : bbois@bordeaux.inra.fr
# Traduction en langage R : Xavier Delpuech, IFV, Domaine de Donadille, 30230 Rodilhan. xavier.delpuech@vignevin.com , février 2012
# Bibliographie
# LEBON, E., DUMAS, V., PIERI, P. and SCHULTZ, H. R., 2003. Modelling the seasonal dynamics of the soil water balance of vineyards. Functional Plant Biology 30 (6).
# RIOU, C., PIERI, P. and CLECH, B. L., 1994. Water use of grapevines well supplied with water. Simplified expression of transpiration. Vitis 33 (3).
# RIOU, C., VALANCOGNE, C. and PIERI, P., 1989. Un modele simple d'interception du rayonnement solaire par la vigne. Verification experimentale. Agronomie 9 (5).
# HARGREAVES, G. H. and SAMANI, Z. A., 1982. Estimating Potential Evapotranspiration. Journal of the Irrigation and Drainage Division 108 p. 223-230.
# HARGREAVES, G. L., HARGREAVES, G. H. and RILEY, J. P., 1985. Agricultural benefits for Senegal River Basin. Journal of Irrigation and Drainage Engineering 111 p. 111-124.
# BRISSON, N., PERRIER, A. (1991) A semi-empirical model of bare soil evaporation for crop simulation models Water Resources Research 27, p.719-727
###
#### sous fonction Radiation_Interception_DI
Radiation_Interception_DI<-function(r_lat=44.5, r_longit=0, i_year=2000, i_doy=183, d_r=1.5, hf_r=1, lf_r=0.4,
az_r=0, poro_r=0.25, alb_f=0.22, alb_s=0.18, Dt=1800, r_rgi=20)
{
#Dt = 1800
#r_lat = latitude    # =44.5
#r_longit = 0
#az_r = azimut # =0   Azimut en degrés (ex: 0=NS ; 90=EW ; -45 = NW-SE )
#d_r = d      # =1.5 Distance inter-rang (en mètres)
#alb_f = 0.22
#alb_s = alb_sol  # =0.18
#i_year = n_an
#i_doy = doy   # par defaut au 1er juillet
#r_rgi = rg    # par defaut = 20
#hf_r = hautf # =1 Hauteur de feuillage (en metres)
#lf_r = largf  # =0.4 Largeur de feuillage (en metres)
#poro_r = poro   # =0.25 Porosite min en ete, de 0 à 1 (0=aucun trou dans le feuillage)

#calculates daily integrals for radiation interception by vine rows and soil in a vineyard
#parameters
rDt = Dt
rLatitude = r_lat
rLongitude = r_longit
iYear = i_year
rOrientRangs = az_r     #à l#entrée :   0 pour rangs NS, 90 pour EW et -45 pour NW-SE
    #ici en entrée, rOrientRangs  en degrés :    ( 0=NS ; 90=EW )  ( -45 = NW-SE )
    #passage direction des rangs à angle de la normale aux rangs avec la direction NS
rOrientRangs = rOrientRangs + 90                            #orientée de N à S
        #If rOrientRangs >= 180 Then rOrientRangs = rOrientRangs - 180     CORRIGE LE 31/03/98 :
if (rOrientRangs >= 90) rOrientRangs = rOrientRangs - 180
#donc angle normale = -90 pour rangs NS, 0 pour EW , 45 pour NW-SE et -45 pour NE-SW
#orientation comme angles d#azimut solaire, à partir du Sud, négatifs le matin et positifs l#après-midi
rEcartRangs = d_r
rHautRang = hf_r
rLargRang = lf_r
rPorosite = poro_r
rAlbedoFeuilles = alb_f
rAlbedoSol = alb_s

 #variables d#entree :
iSimulDay = i_doy
rRgiJour = r_rgi * 1000000               #MJ.m^-2  à  J.m^-2

# *****************************************  DEBUT  JOURNEE  ***************************************

rSJRytGlo = 0           #intialisation des intégrales journalières Rayonnement
rSJRytDif = 0
rSJRytGloVigne = 0
rSJRytGloSol = 0
rSJAlbedoVignoble = 0
rSJRgvRel = 0
rSJRgsRel = 0

iSJtot = 0                              #compteurs
iSJdiurne = 0

# *****************************************  DEBUT CALCULS  ***************************************

#    Call ParSolAnn((iYear))                 #sous programmes astronomiques annuel et journaliers
# ParSolAnn(ian) # ian as integer
#         CALCUL DES PARAMETRES SOLAIRES ANNUELS
#
#           rOmegaRadparJour, vitesse de la Terre (radian)  (par jour)              integer
#           rDoyEqui, date equinoxe (jour)
#           rLongitPerigRad, longitude perigee (radian)
#           rExentr, excentricite
#           rDoyPerig, date perigee (jour)
#           rEpsilonRad, obliquite(radian)
#
## ian=à définir
ian=iYear
rOmegaRadparJour = 2 * pi / 365.25636
rDoyEqui = 80.08 + 0.2422 * (ian - 1900) - trunc((ian - 1901) / 4)
rLongitPerigRad = -1.374953 + 0.000300051 * (ian - 1900)
rExentr = 0.016751 - 0.00000042 * (ian - 1900)
rDoyPerig = rDoyEqui + (rLongitPerigRad - 2 * rExentr * sin(rLongitPerigRad)) / rOmegaRadparJour
rEpsilonRad = 0.40932 - 0.000002271 * (ian - 1900)
ian = 1

#    Call ParSolJour((iYear), (iSimulDay)) # remplacé par le sous-programme lui-même
#ParSolJour(ian As Integer, iNJ As Integer)
#   Calcul de la LONGITUDE CELESTE, de la DECLINAISON du Soleil
#      (radians), de l'EQUATION du TEMPS (minutes) pour le jour iNJ de
#      de l'annee iAn.

#   ATTENTION
#        Ce SOUS-PROGRAMME ne peut etre executé qu'apres le SOUS-PRO-
#        GRAMME  PSOLAN(iAn, ...) qui definit les parametres solaires annuels
#
#      COMMON /PARAN/rOmegaRadparJour,rDoyEqui,rLongitPerigRad,rExentr,rDoyPerig,rEpsilonRad
#      COMMON /PARJOU/rLongitCelesteRad,rDeltaRad,rEquaTemps
ian=iYear
iNJ=iSimulDay
rNJ = iNJ + 0.5
#   LONGITUDE CELESTE du Soleil     (radians)
rLongitCelesteRad = rLongitPerigRad + rOmegaRadparJour * (rNJ - rDoyPerig) + 2 * rExentr * sin(rOmegaRadparJour * (rNJ - rDoyPerig))
#   DECLINAISON du Soleil           (radians)
rDeltaRad = asin(sin(rLongitCelesteRad) * sin(rEpsilonRad))
#   EQUATION DU TEMPS               (minutes)
rEquaTemps = 720 / pi * (atan(tan(rLongitCelesteRad) * cos(rEpsilonRad)) - rOmegaRadparJour * (rNJ - rDoyPerig) - rLongitPerigRad)
while (rEquaTemps <= -100) (rEquaTemps = rEquaTemps + 720)
### fin sous-programme

# Call ParSolJourBis((iYear), (iSimulDay)) # remplacé par le sous-programme lui-même
# ParSolJourBis(ian As Integer, iNJ As Integer)
#   Calcul de l'HEURE de PASSAGE du Soleil au MERIDIEN, de l'HEURE du
#      LEVER et du COUCHER du Soleil (h TU), de la DUREE du JOUR (h)
#
#   Calcul du RAYONNEMENT GLOBAL EXTRATERRESTRE (Joule.m-2). On a admis
#      une valeur de la constante solaire de 1353 watt.m-2
#
#   Pour passer à l'heure legale, ajouter le décalage par rapport a l'heure TU
#   (ex.: en FRANCE, +1h ou +2h selon la periode de l'annee, en GUADELOUPE, -4h, etc...)
#
#   ATTENTION
#        Avant d'utiliser ce SOUS PROGRAMME, il est indispensable
#        d'executer dans l'ordre les SOUS PROGRAMMES:
#            PSOLAN(iAn) pour definir les parametres annuels
#            PSOLJ(NJ) pour definir les parametres journaliers
#        Il faut aussi preciser le lieu en définissant
#
#Dim rNJ, rLatRad, rRefrac, X, a, b, C                               As Double
#Global rHrMidi, rDurJour, rHrLevSol, rHrCouSol, rRytGloExtraAtmJour        As Double
ian=iYear
iNJ=iSimulDay
rNJ = iNJ + 0.5
rLatRad = rLatitude * pi / 180

#HEURE DE PASSAGE du Soleil  au MERIDIEN
rHrMidi = 12 + rLongitude / 15 + rEquaTemps / 60

#Durée du jour, avec rRefrac, Correction de réfraction atmosphérique
rRefrac = -0.0106
if (abs(rLatitude)== 90) X=(rLatRad * (rRefrac - rDeltaRad) * 1000000) else X=(sin(rRefrac) - sin(rLatRad) * sin(rDeltaRad)) / cos(rLatRad) / cos(rDeltaRad)
if (X==0) rDurJour = 12
if (X<=(-1))rDurJour = 24
if (X>(-1)&(X<0)) rDurJour = 24 * (1 + atan((1 - X * X)^0.5 / X) / pi)
if (X>=1) rDurJour = 0
if ((X>0)&(X<1)) rDurJour = 24 * atan((1 - X * X)^0.5 / X) / pi

#HEURES de LEVER et de COUCHER du Soleil
rHrLevSol = rHrMidi - rDurJour / 2
rHrCouSol = rHrMidi + rDurJour / 2

#RAYONNEMENT GLOBAL EXTRATERRESTRE journalier
X = abs(rLatRad + rDeltaRad)
if (rLatRad==0) {a=cos(rDeltaRad)
    }else {if (rDeltaRad==0) {a=cos(rLatRad)
          }else {if (X>pi/2) {b = pi
                             a = b * sin(rLatRad) * sin(rDeltaRad)
                }else {if (abs(rDeltaRad-rLatRad)>pi/2) {a=0
                      }else {
                            C = (1 - (sin(rLatRad) * sin(rLatRad) + sin(rDeltaRad) * sin(rDeltaRad)))^0.5 / sin(rLatRad) / sin(rDeltaRad)
                            b = C + atan(-C)
                            if (rLatRad * rDeltaRad > 0) {b=b+pi}else{}
                            a = b * sin(rLatRad) * sin(rDeltaRad)
                            }
                      }
                }
          }
rRytGloExtraAtmJour = 37210000 * (1 + 0.033 * cos(rOmegaRadparJour * (rNJ - rDoyPerig))) * a
### fin sous-programme

if (rRytGloExtraAtmJour <= 0) print("rRytGloExtraAtmJour <= 0")

if (rHautRang>0) {  #********************  DEBUT BOUCLE rHautRang > 0  ***********************************
                    #MsgBox "rLAI >0  := " & rLAI & snl() & "jour et heure = " & iSimulDay & "  ,  " & rHr

rLatRad = rLatitude * pi / 180               #Latitude en radians
rOrientRangsRad = rOrientRangs * pi / 180    #Où rOrientRangs = ANGLE NORMALE AU RANG AVEC DIRECTION NORD-->SUD (DEGRES)

                             #Début Appel Sous-Programmes Rayonnement
#       Sub AbsDiffus()
#       ex-subroutine KDIFFU(rKdif, rKdifSol, imodel)
#       Calcul des coefficients d'interception du rayonnement diffus :
#       rKdif,  rayonnement venant du ciel et rKdifSol, rayonnement venant du sol
#       1 variante : mur poreux sauf haut et bas, ex. Vigne  (issu de MODELM.FOR)
#  c    porosité du feuillage rPorosite
#      common /ccultu/rEcartRangs,rHautTotMax,rHautRang,rLargRang,rOrientRangs,rAlbedoFeuilles,rAlbedoSol,rPorosite
#Dim rKDIF1, rKDIF2, rKDIF3  As Double          DECLARE en GLOBAL

# ... fraction du rayonnement diffus intercepté par la masse foliaire de la vigne
        #par les parties supérieures des rangs (horizontales et non poreuses)
        rKDIF1 = rLargRang / rEcartRangs
        #facteur de forme entre 2 rangs voisins : auparavant dans sub Calcul_PAR()
        rFF0 = tan(0.5 * atan(rHautRang / (rEcartRangs - rLargRang)))
        #facteur de forme entre les parois horizontales entre les rangs, supérieure et inférieure.
        rFFdif = tan(0.5 * atan((rEcartRangs - rLargRang) / rHautRang))
        #par les parois verticales (d'abord supposées non poreuses)                 'eq 16 de Riou et al., 1989
        rKDIF2 = (1 - rFFdif)
        rKDIF2 = rKDIF2 * (1 - rLargRang / rEcartRangs)
        #par les parties inférieures des rangs (horizontales et non poreuses)       'eq 20 de Riou et al., 1989
        rKDIF3 = (sin(0.5 * atan(2 * rHautRang / rLargRang))) ^ 2
        rKDIF3 = rKDIF3 - (sin(0.5 * atan(rHautRang / (rEcartRangs - rLargRang / 2)))) ^ 2
        rKDIF3 = rKDIF3 * 2 * rLargRang / rEcartRangs
        rKdif = rKDIF1 + (1 - rPorosite) * rKDIF2 + rPorosite * rKDIF3              #eq 21 de Riou et al., 1989
        rKdifSol = rKdif
##### fin

# Sub CoefAbsRytDiff()
#       ex-subroutine ARDIF (rKdif,rKdifSol,cardif,crrdif)
#       calcul des taux d'absorption (cardif) et de réflexion (crrdif) du rayt.diffus
#       common /ccultu/rEcartRangs,rHautTotMax,rHautMax,rLargMax,rOrientRangs,rAlbedoFeuilles,rAlbedoSol,rPorositeMin
rCardif = (1 - rAlbedoFeuilles) * ((1 - rAlbedoSol * rKdifSol) * rKdif + rAlbedoSol * rKdifSol)
rCrrdif = (rAlbedoFeuilles - rAlbedoSol * (1 - rKdifSol) - rAlbedoFeuilles * rAlbedoSol * rKdifSol / 2) * rKdif
rCrrdif = rCrrdif + (rAlbedoSol * (1 - rKdifSol) + rAlbedoFeuilles * rAlbedoSol * rKdifSol / 2)
# fin sub

#            Sub PosGeomLim()
#       Positions Géométriques Limites
#       ex-subroutine cbetal(rBetaLim, nbetal, imodel)
#       interception du Rayonnement Solaire Direct
#       calcul des nbetal valeurs de rBetaLim(),
#       rapports correspondant a des positions caracteristiques limites
#       (composante Horizontale du Rayt DIRECT sur composante Verticale)
      rBetaLim_1 = rLargRang / rHautRang
      rBetaLim_2 = (rEcartRangs - rLargRang) / rHautRang
      rBetaLim_3 = rEcartRangs / rHautRang
      rBetaLim_4 = (rEcartRangs + rLargRang) / rHautRang
      rBetaLim_5 = (2 * rEcartRangs - rLargRang) / rHautRang
      rBetaLim_6 = (2 * rEcartRangs) / rHautRang
      rBetaLim_7 = (3 * rEcartRangs) / rHautRang
# End Sub

   # premier indice pour boucle horaire :
   #(le temps rTempsTUFirst lu dans data_H doit être en heures TU decimales et centrées)
   j = 0                                                        #calculs à partir de 0 h

# *****************************************  DEBUT BOUCLE HORAIRE  ***************************************
   repeat
   {
   if (j >= trunc(24 / (rDt / 3600))) break()

    rHr = rDt / 3600 / 2 + j * rDt / 3600

    #MsgBox "jour et heure = " & iSimulDay & "  ,  " & rHr

# sous-programme        ParSolHor((rHr))                #paramètre rHr = Heure TU (h)
### ParSolHor
#      Calcul des rHautSol et rAzimSol du Soleil (degres) à l#heure rHr (en h TU)
#      du jour iNJ de l#annee iAn pour un lieu de Latitude rLatitude, de
#      Longitude rLongitude (degres), d#équation du temps rEquaTemps (minutes),
#      et de déclinaison du Soleil rDeltaRad (radians)
#
#      ATTENTION
#        Avant l#utilisation de ce SOUS-PROGRAMME, il faut avoir executé
#      les SOUS-PROGRAMMES ParSolAnn(iAn%) et ParSolJour(iNJ%, iAn%)
#        Il faut avoir precisé le lieu par sa rLatitude et sa rLongitude (degres)
#
rLatRad = rLatitude * pi / 180
# ... Calcul Heure en Temps Solaire Vrai, rHrTSV et Angle Horaire (radians), rHrRad
rHrTSV = rHr - 12 - rLongitude / 15 - rEquaTemps / 60
rHrRad = rHrTSV * pi / 12
# ... Calcul de la HAUTEUR du Soleil
X = sin(rLatRad) * sin(rDeltaRad) + cos(rLatRad) * cos(rDeltaRad) * cos(rHrRad)
if (X < 0) rHautSol = 0  #-99.9                    #le Soleil n#est pas levé
rHautSol=ifelse ((X==1), 90, asin(X) * 180 / pi)          # XD : vérifier les radians
# ... Calcul de l'AZIMUT du Soleil
#        codage signe: Nord    -180°
#                      Est      -90°
#                      Sud        0°
#                      Ouest     90°
#                      Nord     180°
#
X = sin(rLatRad) * cos(rHrRad) - cos(rLatRad) * tan(rDeltaRad)
if (X==0) {
b=90
a=0
          } else { if (X<0) {
                            b =180
                            } else { b=0
                            }
                   a = atan(sin(rHrRad) / X) * 180 / pi
          }

if (rHrRad==0) {
rAzimSol = 0
  }else{ if(rHrRad < 0) {
       rAzimSol = a - b
       }else{ rAzimSol = a + b
       }
  }
# fin sous-programme  ParSolHor

rHeureTSV = rHr - rLongitude / 15 - rEquaTemps / 60   #temps solaire vrai (h)
rAHDeg = (rHeureTSV - 12) * 15                        #angle horaire  (degrés)
rAHRad = rAHDeg * pi / 180                          #angle horaire  (radians)
rHautSolRad = rHautSol * pi / 180                   #hauteur soleil (radians)
rAzimSolRad = rAzimSol * pi / 180                   #azimut soleil (radians)

iSJtot = iSJtot + 1                   #compteur jour

            #Microclimat_Feuilles                         #MsgBox "Microclimat_Feuilles  Terminé"

            #rSJTleaf = rSJTleaf + rTleaf                #mise à jour des intégrales journalières microclimat
            #rSJDefSat = rSJDefSat + rDefSat

if (rHautSol>0) {        #DEBUT TEST rHautSol > 0  pour partie Ryt Solaire
#rSJTleafDiurne = rSJTleafDiurne + rTleaf    #mise à jour des intégrales journ. microclimat periode diurne
#rSJDefSatDiurne = rSJDefSatDiurne + rDefSat
iSJdiurne = iSJdiurne + 1                   #compteur periode diurne
r = 1353 * (1 + 2 * rExentr * cos(rOmegaRadparJour * iSimulDay + 0.5 - rDoyPerig))
rRytGloExtraAtm = r * sin(rHautSol * pi / 180)
#If bOption11 = False Then
rRytGlo = rRytGloExtraAtm * rRgiJour / rRytGloExtraAtmJour
#End If

                if (rRytGloExtraAtm>0) {             #Début calcul Rayonnement Diffus
                    GSG0 = rRytGlo / rRytGloExtraAtm
                    }else{GSG0 = 0
                    }

                #DSG = 1.09 - 2.6896 * GSG0 * GSG0 + 1.2843 * GSG0 * GSG0 * GSG0   # relation journalière à Bordeaux (CV)
                DSG = 1.09 - 2.44 * GSG0 * GSG0 + 1.084 * GSG0 * GSG0 * GSG0   # relation horaire à Bordeaux (CV)

                if (DSG>1) DSG = 1
                if (GSG0 >= 0.2) {
                    rRytDif = rRytGlo * DSG
                    rRytDir = rRytGlo - rRytDif
                } else {
                    rRytDif = rRytGlo
                    rRytDir = 0
                }

                if (rRytDif < 0) rRytDif = 0
                if (rRytDir < 0) rRytDir = 0

        # ... rapport composante horizontale (--> paroi verticale)
        # ... / composante verticale (--> paroi horizontale) du Ryt Direct (RDIR)
                rBeta1 = cos(rOrientRangsRad) * tan(rLatRad)
                rBeta2 = sin(rDeltaRad) * cos(rOrientRangsRad) / (sin(rHautSolRad) * cos(rLatRad))
                rBeta3 = sin(rOrientRangsRad) * cos(rDeltaRad) * sin(rAHRad) / sin(rHautSolRad)
                rBeta = abs(rBeta1 - rBeta2 + rBeta3)

# Sub AbsDirect()
#       ex-subroutine kdirec(rBetaLim, nbetal, imodel, rKdir, rBeta)
#       interception du Rayonnement Solaire Direct par le feuillage
#       rBetaLim() rapports correspondant a des valeurs caracteristiques de rBeta
#       rBeta = rapport composante Horizontale du Rayt DIRECT / composante Verticale

    if (rBeta > rBetaLim_1) {
        if (rBeta > rBetaLim_2) {
            if (rBeta > rBetaLim_3) {
                if (rBeta > rBetaLim_4) {
                    if (rBeta > rBetaLim_5) {
                        if (rBeta > rBetaLim_6) {
                            if (rBeta >= rBetaLim_7) {
                                rKdir = (rEcartRangs - rPorosite * rPorosite * rPorosite * (rEcartRangs - rLargRang)) / rEcartRangs
                            }else{
                                rKdir = (rEcartRangs - rPorosite * rPorosite * (rEcartRangs - rLargRang) + rPorosite * rPorosite * (1 - rPorosite) * (rBeta * rHautRang - 2 * rEcartRangs - rLargRang)) / rEcartRangs
                            }
                        }else{
                            rKdir = (rEcartRangs - rPorosite * rPorosite * (rBeta * rHautRang - rEcartRangs - rLargRang)) / rEcartRangs
                        }
                    }else{
                        rKdir = (rEcartRangs - rPorosite * (2 * rEcartRangs - rLargRang - rBeta * rHautRang) - rPorosite * rPorosite * (rBeta * rHautRang - rEcartRangs - rLargRang)) / rEcartRangs
                    }
                }else{
                    rKdir = (rEcartRangs - rPorosite * (2 * rEcartRangs - rLargRang - rBeta * rHautRang)) / rEcartRangs
                }
            }else{
                rKdir = (rEcartRangs - rPorosite * (rBeta * rHautRang - rLargRang)) / rEcartRangs
            }
         }else{
            rKdir = ((rBeta * rHautRang + rLargRang) - rPorosite * (rBeta * rHautRang - rLargRang)) / rEcartRangs
         }
    }else{
        rKdir = ((rBeta * rHautRang + rLargRang) / rEcartRangs)
    }
#End Sub

#Sub CoefAbsRytDir()
#       ex-subroutine ARDIR(rKdifSol, rKdir, cardir, crrdir)
#       calcul des taux d'absorption (cardir) et de de réflexion (crrdir) du rayt. direct
rCardir = (1 - rAlbedoFeuilles) * ((1 - rAlbedoSol * rKdifSol) * rKdir + rAlbedoSol * rKdifSol)
rCrrdir = (rAlbedoFeuilles - rAlbedoSol * (1 - rKdifSol) - rAlbedoFeuilles * rAlbedoSol * rKdifSol / 2) * rKdir
rCrrdir = rCrrdir + (rAlbedoSol * (1 - rKdifSol) + rAlbedoFeuilles * rAlbedoSol * rKdifSol / 2)
#End Sub

        }else{                #SUITE TEST rHautSol > 0 donc ici #If rHautSol <= 0
            rHautSol = 0            #pour partie ryt sol
            rAzimSol = 0
            rRytGloExtraAtm = 0
            rRytGlo = 0
            rRytDir = 0
            rRytDif = 0
            rCardir = 0
            rCrrdir = 0
            rBeta = 0
       }              #FIN TEST rHautSol > 0  pour partie Ryt Solaire

        rRytGloVigne = rCardir * rRytDir + rCardif * rRytDif
        rRytGloSol = (1 - rCardir - rCrrdir) * rRytDir + (1 - rCardif - rCrrdif) * rRytDif

        if (rRytGlo > 0) {
            rAlbedoVignoble = (rCrrdir * rRytDir + rCrrdif * rRytDif) / rRytGlo
            rRgvRel = rRytGloVigne / ((1 - rAlbedoVignoble) * rRytGlo)
            rRgsRel = rRytGloSol / ((1 - rAlbedoVignoble) * rRytGlo)
            }
        if (rRytGlo <= 0) {
            rAlbedoVignoble = 0
            rRgvRel = 0
            rRgsRel = 0
            }

        rSJRytGlo = rSJRytGlo + rRytGlo * rDt                 #Mise à Jour des Intégrales Journalières / Rayonnement
        rSJRytDif = rSJRytDif + rRytDif * rDt
        rSJRytGloVigne = rSJRytGloVigne + rRytGloVigne * rDt
        rSJRytGloSol = rSJRytGloSol + rRytGloSol * rDt

    j = j + 1
    }             #FIN BOUCLE HORAIRE commencee par : Do While (j < CInt(24 / (rDt / 3600)))

    # ------------------------------  mise à jour des intégrales journalières (rSJ...)  ---------------------
    #                                 et sur toute la duree du fichier d#entree (rSom...)

        if (rSJRytGlo>0){
        rSJAlbedoVignoble = 1 - (rSJRytGloVigne + rSJRytGloSol) / rSJRytGlo     #ratios journaliers / Rayonnement
        rSJRgvRel = rSJRytGloVigne / ((1 - rSJAlbedoVignoble) * rSJRytGlo)
        rSJRgsRel = rSJRytGloSol / ((1 - rSJAlbedoVignoble) * rSJRytGlo)
        }

}       #fin boucle if rHautRang > 0  (realisation calculs int ryt dans boucle horaire)

    # ------------------------------  sorties journalières  ------------------------------------
    #                           (intégrales sur la durée de la journée)
sor_ryt=data.frame(c(1:25))
sor_ryt[1,1]= iSimulDay
sor_ryt[2,1]= iYear
sor_ryt[3,1]= rLatitude
sor_ryt[4,1]= rHrLevSol
sor_ryt[5,1]= rHrCouSol
sor_ryt[6,1]= rDurJour
sor_ryt[7,1]= rRytGloExtraAtmJour / 1000000
sor_ryt[8,1]= rRgiJour / 1000000

        if (rHautRang>0){   #donc si realisation calculs int ryt (et event. photos.) dans boucle horaire
            sor_ryt[9,1] = rEcartRangs
            sor_ryt[10,1] = az_r     #comme en entrée :   0 pour rangs NS, 90 pour EW et -45 pour NW-SE
            sor_ryt[11,1] = rHautRang
            sor_ryt[12,1] = rLargRang
            sor_ryt[13,1] = rPorosite
            sor_ryt[14,1] = rPorosite
            sor_ryt[15,1] = tan(0.5 * atan(rHautRang / (rEcartRangs - rLargRang)))     #Fact de Forme entre 2 rangs

            sor_ryt[16,1] = rSJRytGlo / 1000000
            sor_ryt[17,1] = (rSJRytGlo - rSJRytDif) / 1000000
            sor_ryt[18,1] = rSJRytDif / 1000000
            sor_ryt[19,1] = rSJRytGloVigne / 1000000
            sor_ryt[20,1] = rSJRytGloSol / 1000000
            sor_ryt[21,1] = rSJAlbedoVignoble
            sor_ryt[22,1] = rSJRgvRel
            sor_ryt[23,1] = rSJRgsRel
            sor_ryt[24,1] = iSJdiurne #nb d#intervalles utilisés pour calculer les integrales SJ (jour entier)
            sor_ryt[25,1] = iSJtot     #nb d#intervalles utilisés pour calculer les integrales SJ (per. diurne)
        }else{
            for (i in 9:25) {
                sor_ryt[i,1] = 0
                 }
        }      #FIN TEST   If rHautRang > 0 Then
                                #(=test si realisation effective des calculs d#int ryt dans boucle horaire)

#résultats journaliers :
    #Cells(i_ligne, 49).Value = sor_ryt(21)                              #alb
    #Cells(i_ligne, 50).Value = sor_ryt(22)                              #k_rgv
return(sor_ryt[22,1])    # retourne en sortie le kmax de la vigne
} # fin de la fonction  Radiation_Interception_DI


# Investigating Dengue RDT sensitivity and specificty requirements
# written by Stefan Flasche using R version 3.4.4
# results published in "On the importance of sensitivity and the negative predictive value for a rapid dengue test" by S. Flasche and P.G. Smith

# load packages
require(tidyverse)

# Data --------------------------------------------------------------------

# data: cumulative incidence over 5yrs observed in the trial and its stratification into
#       seropositive and seronegative using PRNT50 with multiple imputation (in per 100).
df <- tibble(no=1:8,
             randomisation = c("vacc","vacc","control","control","vacc","vacc","control","control"),
             serostatus = c("pos","neg","pos","neg","pos","neg","pos","neg"),
             outcome = c(rep("hosp",4),rep("severe",4)),
             incidence.ph.mid = c(.375,1.571,1.883,1.093,0.075,0.404,0.48,0.174),
             incidence.ph.lo = c(.263,1.125,1.536,.526,0.034,0.218,0.335,0.036),
             incidence.ph.hi = c(.535,2.193,2.307,2.265,0.165,0.749,0.688,0.834))

# plot data
p.data <- df %>% ggplot(aes(x= serostatus, y = incidence.ph.mid, ymin = incidence.ph.lo, ymax = incidence.ph.hi,color=randomisation)) +
  geom_linerange(position=position_dodge(width = 0.5)) +
  geom_point(position=position_dodge(width = 0.5)) +
  facet_grid(.~outcome, scales = "free") +
  coord_flip() + ylab("incidence per 100") +
  labs(y = "Incidence per 100", x = "Serostatus", color = "Randomisation")
ggsave(filename = "Pics\\Fig1_Data.tiff",p.data ,unit="cm", width = 14, height = 5, compression = "lzw", dpi = 300)

# sample from lognormal distribution in which the 50%, 2.5% and 97.5% quanitles fit the observed mean, CI.lo and CI.hi respectively
LnfitSample <- function(input= c(mean=1, lo=.5, hi=2), N=10000){
  mean = input[1] %>% as.numeric()
  lo = input[2] %>% as.numeric()
  hi = input[3] %>% as.numeric()
  rlnorm(N, meanlog = log(mean), sdlog = (log(mean/lo) +  log(hi/mean))/2/1.96) %>%
    return()
}

# Population impact of test and vaccinate ---------------------------------------------

# calculate population impact of test and vaccinate strategy
## need to include resampling of incidence
CasesAverted <- function(seroPrevalence = .7, sensitivity = 1, specificity = 0,
                         cohortSize=100000, df.tmp = df, outcm = "hosp"){
  df.tmp = df.tmp %>% filter(outcome == outcm)
  Inc.SeroPos.Vacc <- df.tmp %>% filter(randomisation=="vacc" & serostatus =="pos") %>%
    select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
  Inc.SeroPos.Cont <- df.tmp %>% filter(randomisation=="control" & serostatus =="pos") %>%
    select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
  Inc.SeroNeg.Vacc <- df.tmp %>% filter(randomisation=="vacc" & serostatus =="neg") %>%
    select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
  Inc.SeroNeg.Cont <- df.tmp %>% filter(randomisation=="control" & serostatus =="neg") %>%
    select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()

  CasesAvertedSeroPos = cohortSize * seroPrevalence * sensitivity * (Inc.SeroPos.Cont - Inc.SeroPos.Vacc) / 100
  CasesAvertedSeroNeg = cohortSize * (1-seroPrevalence) * (1 - specificity) * (Inc.SeroNeg.Cont - Inc.SeroNeg.Vacc) /100

  df_res <- tibble(seroPrevalence = seroPrevalence, sensitivity = sensitivity,
                   specificity = specificity, outcome = outcm,
                   CasesAvertedSeroPos.mid = median(CasesAvertedSeroPos),
                   CasesAvertedSeroPos.lo = quantile(CasesAvertedSeroPos,.025),
                   CasesAvertedSeroPos.hi = quantile(CasesAvertedSeroPos,.975),
                   CasesAvertedSeroNeg.mid = median(CasesAvertedSeroNeg),
                   CasesAvertedSeroNeg.lo = quantile(CasesAvertedSeroNeg,.025),
                   CasesAvertedSeroNeg.hi = quantile(CasesAvertedSeroNeg,.975),
                   CasesAvertedTotal.mid =  median(CasesAvertedSeroPos + CasesAvertedSeroNeg),
                   CasesAvertedTotal.lo = quantile(CasesAvertedSeroPos + CasesAvertedSeroNeg, .025),
                   CasesAvertedTotal.hi = quantile(CasesAvertedSeroPos + CasesAvertedSeroNeg, .975))
  return(df_res)
}

# plot impact of test and vaccinate strategy
df.plt = NULL
for(seroPrevalence in c(.6,.7,.8)){
  for(specificity in c(.9,.95,.98,.99,1)){
    for(sensitivity in seq(.8,1,by=.05)){
      df.plt <- df.plt %>%
        rbind(CasesAverted(seroPrevalence = seroPrevalence, sensitivity = sensitivity, specificity = specificity))
    }
  }
}

df.plt <- df.plt %>%
  gather(key,value, -seroPrevalence, -sensitivity, -specificity, -outcome) %>%
  extract(key, c("outcome","conf"),"(.*)\\.(.*)") %>%
  spread(conf, value)

p.tandv = df.plt %>% ggplot(aes(x=sensitivity, y = mid, ymin=lo, ymax= hi, color = as.factor(seroPrevalence))) +
  geom_linerange(position = position_dodge(width = 0.04)) +
  geom_point(position = position_dodge(width = 0.04)) +
  facet_grid(outcome ~ specificity, scales = "free") +
  scale_color_discrete(name="seroprevalence") + ylab("hospitalised dengue cases averted\nin a 100,000 cohort") +
  geom_hline(yintercept = 0, color="black", lty="dashed")
ggsave(filename = "Pics\\Fig2_Impact_TandV.tiff",p.tandv ,unit="cm", width = 25, height = 14, compression = "lzw", dpi = 300)

# Impact of sensitivity --------------------------------------------------------------------

# calculate sensitivity needed to avoid chosing to vaccinate test negative
TestNegRatio <- function(seroPrevalence = .7, sensitivity = .8, specificity = .95,
                             df.tmp = df, outcm = "hosp", midonly=F){
  df.tmp = df.tmp %>% filter(outcome == outcm)
  if(midonly){
    Inc.SeroPos.Vacc <- df.tmp %>% filter(randomisation=="vacc" & serostatus =="pos") %>%
      select(incidence.ph.mid) %>% as.numeric()
    Inc.SeroPos.Cont <- df.tmp %>% filter(randomisation=="control" & serostatus =="pos") %>%
      select(incidence.ph.mid) %>% as.numeric()
    Inc.SeroNeg.Vacc <- df.tmp %>% filter(randomisation=="vacc" & serostatus =="neg") %>%
      select(incidence.ph.mid) %>% as.numeric()
    Inc.SeroNeg.Cont <- df.tmp %>% filter(randomisation=="control" & serostatus =="neg") %>%
      select(incidence.ph.mid) %>% as.numeric()
  }else{
    Inc.SeroPos.Vacc <- df.tmp %>% filter(randomisation=="vacc" & serostatus =="pos") %>%
      select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
    Inc.SeroPos.Cont <- df.tmp %>% filter(randomisation=="control" & serostatus =="pos") %>%
      select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
    Inc.SeroNeg.Vacc <- df.tmp %>% filter(randomisation=="vacc" & serostatus =="neg") %>%
      select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
    Inc.SeroNeg.Cont <- df.tmp %>% filter(randomisation=="control" & serostatus =="neg") %>%
      select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
  }

  risk.if.testNeg.vacc <- ((1-seroPrevalence) * specificity *  Inc.SeroNeg.Vacc +
    seroPrevalence * (1-sensitivity) * Inc.SeroPos.Vacc ) /
    ((1-seroPrevalence) * specificity  + seroPrevalence * (1-sensitivity) )
  risk.if.testNeg.nova <- ((1-seroPrevalence) * specificity *  Inc.SeroNeg.Cont +
    seroPrevalence * (1-sensitivity) * Inc.SeroPos.Cont ) /
    ((1-seroPrevalence) * specificity  + seroPrevalence * (1-sensitivity) )

  df_res <- tibble(seroPrevalence = seroPrevalence, sensitivity = sensitivity,
                   specificity = specificity, outcome = outcm,
                   riskiftestNegvacc.mid = median(risk.if.testNeg.vacc),
                   riskiftestNegnova.mid = median(risk.if.testNeg.nova),
                   riskiftestNegvacc.lo = quantile(risk.if.testNeg.vacc,.025),
                   riskiftestNegvacc.hi = quantile(risk.if.testNeg.vacc,.975),
                   riskiftestNegnova.lo = quantile(risk.if.testNeg.nova,.025),
                   riskiftestNegnova.hi = quantile(risk.if.testNeg.nova,.975),
                   RR.mid =  median(risk.if.testNeg.vacc / risk.if.testNeg.nova),
                   RR.lo = quantile(risk.if.testNeg.vacc / risk.if.testNeg.nova, .025),
                   RR.hi = quantile(risk.if.testNeg.vacc / risk.if.testNeg.nova, .975))
  return(df_res)
}

# analyse where test nagative vacc vs novacc risks are for a number of scenarios
df.plt = NULL
for(seroPrevalence in c(.5,.7,.9)){
  for(specificity in c(.95,1)){
    for(sensitivity in seq(.6,1,by=.1)){
      df.plt <- df.plt %>%
        rbind(TestNegRatio(seroPrevalence = seroPrevalence, sensitivity = sensitivity, specificity = specificity)) %>%
        rbind(TestNegRatio(seroPrevalence = seroPrevalence, sensitivity = sensitivity, specificity = specificity, outcm = "severe"))

    }
  }
}

p.sens <- df.plt %>%
  ggplot(aes(x=sensitivity, y = RR.mid, ymin=RR.lo, ymax= RR.hi, color=outcome)) +
  geom_linerange(position = position_dodge(width = 0.04)) +
  geom_point(position = position_dodge(width = 0.04)) +
  facet_grid(seroPrevalence ~ specificity, scales = "free") +
  scale_y_log10() + geom_hline(yintercept = 1, color="black", lty="dashed") +
  scale_color_discrete(name="outcome") +
  ylab("RR for hospitalised dengue\nin test-negative for\nvaccination vs no vaccination")
ggsave(filename = "Pics\\FigX_SensitivityImpact.tiff",p.sens ,unit="cm", width = 20, height = 12, compression = "lzw", dpi = 300)

# analyse where test nagative vacc vs novacc risks - map
df.plt2 = NULL
for(seroPrevalence in c(.5,.6,.7,.8,.9)){
  for(specificity in seq(.9,1,by=.01)){
    for(sensitivity in seq(.6,1,by=.01)){
      df.plt2 <- df.plt2 %>%
        rbind(TestNegRatio(seroPrevalence = seroPrevalence, sensitivity = sensitivity, specificity = specificity, midonly=T)) %>%
        rbind(TestNegRatio(seroPrevalence = seroPrevalence, sensitivity = sensitivity, specificity = specificity, outcm = "severe", midonly=T))

    }
  }
}

p.sens.b <- df.plt2 %>%
  ggplot(aes(x=sensitivity, y=specificity, fill = RR.mid)) +
  facet_grid(seroPrevalence ~ outcome) +
  geom_tile() +
  scale_fill_gradient2(name="RR in vaccinees\nvs controls", low = "green", mid = "yellow",
                       high = "red", midpoint = 0, breaks=round(c(.5,1/1.2,1/1.1,1,1.1,1.2,2),2),trans = "log", limits=c(1/1.21,1.2)) +
  theme_bw() +
  labs(x = "Sensitivity", y = "Specificity")
ggsave("Pics\\Fig3a_SensitivityImpactMap.tiff", p.sens.b, width = 20, height = 13, units = "cm", compression="lzw", dpi =300)

# importance of NPV ---------------------------------------------
TestNegRatio.NPV <- function(NPV = .7, df.tmp = df, outcm = "hosp"){
  df.tmp = df.tmp %>% filter(outcome == outcm)

  Inc.SeroPos.Vacc <- df.tmp %>% filter(randomisation=="vacc" & serostatus =="pos") %>%
    select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
  Inc.SeroPos.Cont <- df.tmp %>% filter(randomisation=="control" & serostatus =="pos") %>%
    select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
  Inc.SeroNeg.Vacc <- df.tmp %>% filter(randomisation=="vacc" & serostatus =="neg") %>%
    select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()
  Inc.SeroNeg.Cont <- df.tmp %>% filter(randomisation=="control" & serostatus =="neg") %>%
    select(incidence.ph.mid:incidence.ph.hi) %>% LnfitSample()

  risk.if.testNeg.vacc <- ( NPV * Inc.SeroNeg.Vacc +
                            (1-NPV) * Inc.SeroPos.Vacc )
  risk.if.testNeg.nova <- ( NPV * Inc.SeroNeg.Cont +
                            (1-NPV) * Inc.SeroPos.Cont )

  df_res <- tibble(NPV = NPV, outcome = outcm,
                   riskiftestNegvacc.mid = median(risk.if.testNeg.vacc),
                   riskiftestNegnova.mid = median(risk.if.testNeg.nova),
                   riskiftestNegvacc.lo = quantile(risk.if.testNeg.vacc,.025),
                   riskiftestNegvacc.hi = quantile(risk.if.testNeg.vacc,.975),
                   riskiftestNegnova.lo = quantile(risk.if.testNeg.nova,.025),
                   riskiftestNegnova.hi = quantile(risk.if.testNeg.nova,.975),
                   RR.mid =  median(risk.if.testNeg.vacc / risk.if.testNeg.nova),
                   RR.lo = quantile(risk.if.testNeg.vacc / risk.if.testNeg.nova, .025),
                   RR.hi = quantile(risk.if.testNeg.vacc / risk.if.testNeg.nova, .975))
  return(df_res)
}

df.plt.NPV = NULL
for( NPV in seq(.5,1,by=0.01)){
  df.plt.NPV = df.plt.NPV %>%
    rbind(TestNegRatio.NPV(NPV)) %>%
    rbind(TestNegRatio.NPV(NPV, outcm = "severe"))
}
df.plt.NPV$outcome = df.plt.NPV$outcome %>% str_replace("hosp","Hospitalised")
df.plt.NPV$outcome = df.plt.NPV$outcome %>% str_replace("severe","Severe")
df.plt.NPV %>%
  ggplot(aes(x=NPV, y=RR.mid, ymin=RR.lo, ymax=RR.hi, group=outcome, color=outcome, fill=outcome)) +
  geom_ribbon(alpha=0.2, color=NA) +
  geom_line() +
  geom_hline(yintercept = 1, color = "black", lty = "dashed") +
  #facet_grid(outcome~., scales="free") +
  scale_y_log10() +
  labs(x = "Negative predictive value", y = "RR for\nsevere or hospitalised disease \nin test-negative for\nvaccination vs no vaccination",
        fill = "Outcome", color = "Outcome") +
  theme_bw()+
  guides(group=F)
ggsave("Pics\\Fig3b_NPVimpact.tiff", width = 13, height = 7, units = "cm", compression="lzw", dpi =1000)
ggsave("Pics\\Fig3b_NPVimpact.pdf", width = 13, height = 7, units = "cm")

# calculate min sens needed ---------------------------------------------

get_PV <- function(specificity=.9, sensitivity=.7, seroprevalence=0.7 ){
  tp= sensitivity * seroprevalence
  fn= (1-sensitivity) * seroprevalence
  tn= specificity * (1-seroprevalence)
  fp= (1-specificity) * (1-seroprevalence)

  PPV = tp / (tp+fp) #prop of true positive among all pos
  NPV = tn / (tn+fn) #prop of negative positive among all negative

  df = data.frame(specificity=as.factor(specificity), sensitivity=sensitivity, seroprevalence=seroprevalence, NPV=NPV, PPV=PPV) %>%
    as.tibble()

  return(df)

}

res = NULL
for(specificity in c(.9,.95,.99)){
  for(seroprevalence in seq(0.15,1,by=0.01)){
    for(sensitivity in seq(0,1,by=0.01)){
      res = res %>%
        rbind(get_PV(specificity, sensitivity, seroprevalence))
    }
  }
}
min.PPV = .90
min.NPV = .75 # Ratio for RR forvaccinees to get hospitalised in Seropos vs Seroneg is 1.57/1.09 / 0.375/1.88
p.dat = res %>% group_by(specificity,seroprevalence) %>% mutate(PPV.based = ( PPV == min(PPV + 5*(PPV<min.PPV))),
                                                        NPV.based = ( NPV == min(NPV + 5*(NPV<min.NPV)))) %>%
  filter(PPV.based | NPV.based) %>%
  gather(criteria, value, -specificity, -sensitivity, -seroprevalence, -NPV, -PPV) %>%
  filter (value)
p.dat$criteria = p.dat$criteria %>% str_replace("V.b","V b")
p = p.dat %>%
  ggplot(aes(x=seroprevalence, y=sensitivity, color=criteria, lty = specificity)) +
  geom_line() +
  theme_bw() +
  labs(x = "Seroprevalence", y = "Minimum sensitivity", color = "Criteria", lty = "Specificity") +
  scale_x_continuous(breaks = seq(0.1,1,by=0.2)) +
  scale_y_continuous(breaks = seq(0,1,by=0.2))
ggsave("Pics/RequiredSensitivity.tiff", p, units = "cm",height = 7, width = 13, compression="lzw", dpi=1000)
ggsave("Pics/RequiredSensitivity.pdf", p, units = "cm",height = 7, width = 13)


# Read in World Ocean Atlas data
nms <- c('lat', 'lon', 'm0', 'm5', 'm10', 'm15', 'm20', 'm25', 'm30', 'm35', 'm40', 'm45', 'm50', 'm55', 'm60', 'm65', 'm70', 'm75', 'm80', 'm85', 'm90', 'm95', 'm100', 'm125', 'm150', 'm175', 'm200', 'm225', 'm250', 'm275', 'm300', 'm325', 'm350', 'm375', 'm400', 'm425', 'm450', 'm475', 'm500', 'm550', 'm600', 'm650', 'm700', 'm750', 'm800', 'm850', 'm900', 'm950', 'm1000', 'm1050', 'm1100', 'm1150', 'm1200', 'm1250', 'm1300', 'm1350', 'm1400', 'm1450', 'm1500', 'm1550', 'm1600', 'm1650', 'm1700', 'm1750', 'm1800', 'm1850', 'm1900', 'm1950', 'm2000', 'm2100', 'm2200', 'm2300', 'm2400', 'm2500', 'm2600', 'm2700', 'm2800', 'm2900', 'm3000', 'm3100', 'm3200', 'm3300', 'm3400', 'm3500', 'm3600', 'm3700', 'm3800', 'm3900', 'm4000', 'm4100', 'm4200', 'm4300', 'm4400', 'm4500', 'm4600', 'm4700', 'm4800', 'm4900', 'm5000', 'm5100', 'm5200', 'm5300', 'm5400', 'm5500')
dps <- c(0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 125, 150, 175, 200, 225, 250, 275, 300, 325, 350, 375, 400, 425, 450, 475, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700, 1750, 1800, 1850, 1900, 1950, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, 4000, 4100, 4200, 4300, 4400, 4500, 4600, 4700, 4800, 4900, 5000, 5100, 5200, 5300, 5400, 5500) # the depths associated with each column (after lat/lon)

woa <- read.csv('data_dl/woa/woa13_decav_t00an01v2.csv', skip=2, row.names=NULL, header=FALSE, col.names=nms) # use col.names to force all columns to be read (file doesn't have trailing ,s for blank columns)

# Initial plot (slow)

col = rgb(0,0,0,0.01)
plot(dps, woa[1,3:ncol(woa)], type='l', ylab='temperature', xlab='depth (m)', ylim=c(-2,30), col=col, xlim=c(0,1000))
for(i in 2:nrow(woa)){
	lines(dps, woa[i,3:ncol(woa)], col=col)
}

###########################################
# average temperature within lat bands
###########################################
woalat <- aggregate(list(m0=woa$m0, m5=woa$m5, m10=woa$m10, m15=woa$m15, m20=woa$m20, m25=woa$m25, m30=woa$m30, m35=woa$m35, m40=woa$m40, m45=woa$m45, m50=woa$m50, m55=woa$m55, m60=woa$m60, m65=woa$m65, m70=woa$m70, m75=woa$m75, m80=woa$m80, m85=woa$m85, m90=woa$m90, m95=woa$m95, m100=woa$m100, m125=woa$m125, m150=woa$m150, m175=woa$m175, m200=woa$m200, m225=woa$m225, m250=woa$m250, m275=woa$m275, m300=woa$m300, m325=woa$m325, m350=woa$m350, m375=woa$m375, m400=woa$m400, m425=woa$m425, m450=woa$m450, m475=woa$m475, m500=woa$m500, m550=woa$m550, m600=woa$m600, m650=woa$m650, m700=woa$m700, m750=woa$m750, m800=woa$m800, m850=woa$m850, m900=woa$m900, m950=woa$m950, m1000=woa$m1000, m1050=woa$m1050, m1100=woa$m1100, m1150=woa$m1150, m1200=woa$m1200, m1250=woa$m1250, m1300=woa$m1300, m1350=woa$m1350, m1400=woa$m1400, m1450=woa$m1450, m1500=woa$m1500, m1550=woa$m1550, m1600=woa$m1600, m1650=woa$m1650, m1700=woa$m1700, m1750=woa$m1750, m1800=woa$m1800, m1850=woa$m1850, m1900=woa$m1900, m1950=woa$m1950, m2000=woa$m2000, m2100=woa$m2100, m2200=woa$m2200, m2300=woa$m2300, m2400=woa$m2400, m2500=woa$m2500, m2600=woa$m2600, m2700=woa$m2700, m2800=woa$m2800, m2900=woa$m2900, m3000=woa$m3000, m3100=woa$m3100, m3200=woa$m3200, m3300=woa$m3300, m3400=woa$m3400, m3500=woa$m3500, m3600=woa$m3600, m3700=woa$m3700, m3800=woa$m3800, m3900=woa$m3900, m4000=woa$m4000, m4100=woa$m4100, m4200=woa$m4200, m4300=woa$m4300, m4400=woa$m4400, m4500=woa$m4500, m4600=woa$m4600, m4700=woa$m4700, m4800=woa$m4800, m4900=woa$m4900, m5000=woa$m5000, m5100=woa$m5100, m5200=woa$m5200, m5300=woa$m5300, m5400=woa$m5400, m5500=woa$m5500), by=list(lat=woa$lat), FUN=mean, na.rm=TRUE)

# plot lat averages, color by lat
#col = rgb(0,0,0,0.1)
cols <- rainbow(nrow(woalat))
plot(dps, woalat[1,2:ncol(woalat)], type='l', ylab='temperature', xlab='depth (m)', ylim=c(-2,30), col=cols[1], xlim=c(0,1000))
for(i in 2:nrow(woalat)){
	lines(dps, woalat[i,2:ncol(woalat)], col=cols[i])
}

abline(v=100, lty=2)

# plot SST vs. lat
plot(woalat$lat, woalat$m0, type='l')
abline(v=5)

# plot all profiles at 0.5°
inds <- which(woa$lat==0.5)
cols <- rainbow(length(inds))
plot(dps, woa[inds[1],3:ncol(woa)], type='l', ylab='temperature', xlab='depth (m)', ylim=c(-2,30), col=cols[1], xlim=c(0,1000))
for(i in 2:length(inds)){
	lines(dps, woa[inds[i],3:ncol(woa)], col=cols[i])
}

# plot all profiles where depth < 1000
inds <- which(is.na(woa$m1050))
col = rgb(0,0,0,0.1)
plot(dps, woa[inds[1],3:ncol(woa)], type='l', ylab='temperature', xlab='depth (m)', ylim=c(-2,30), col=col, xlim=c(0,1000))
for(i in 2:length(inds)){
	lines(dps, woa[inds[i],3:ncol(woa)], col=col)
}

##################
# Average all
##################

woaave <- apply(woa[,3:ncol(woa)], MARGIN=2, FUN=mean, na.rm=TRUE)

plot(dps, woaave, type='l')

plot(dps, woaave, type='l', xlim=c(0,300))

woaave['m50'] - woaave['m0']
woaave['m300'] - woaave['m0']

#######################
# Average change in temperature
#######################

mean(woa$m50 - woa$m0, na.rm=TRUE)
mean(woa$m300 - woa$m0, na.rm=TRUE)
mean(woa$m1000 - woa$m0, na.rm=TRUE)


## Usage: Rscript this.r <output_prefix> <in1_foreground_prefix> <in2_background_prefix> [pos_range]

options(stringsAsFactors=FALSE)

library(HDInterval)

`%.%` <- function(x,y) paste0(x,y)

join = function(sep, vec, ...) paste(collapse=sep, c(vec, ...))
cat0 = function(...) cat(sep="", ...)

echo_str <- function(x, sep=" =\t", collapse=", ") deparse(substitute(x)) %.% sep %.% join(collapse, x)
echo <- function(x, sep=" =\t", collapse=", ") cat0(deparse(substitute(x)), sep, join(collapse, x), "\n");

str_trim_left = function(str, trimLen){
	strlen = nchar(str)
	start = pmin(strlen, trimLen) + 1
	end = strlen
	substr(str, start, end)
}
str_trim_right = function(str, trimLen){
	strlen = nchar(str)
	start = 1
	end = pmax(0, strlen - trimLen)
	substr(str, start, end)
}
str_left = function(str, len){
	strlen = nchar(str)
	start = 1
	end = pmin(len, strlen)
	substr(str, start, end)
}
str_right = function(str, len){
	strlen = nchar(str)
	start = pmax(1, strlen - len + 1)
	end = strlen
	substr(str, start, end)
}

### ref: http://varianceexplained.org/r/bayesian_fdr_baseball/
cummean = function(vec){
	cumsum(vec) / (1:length(vec))
}
PEP_to_qvalues = function(PEP_vec){
	order_vec = order(PEP_vec)
	ans = rep(NA, length(PEP_vec))
	PEP_ordered = PEP_vec[order_vec]
	qvalue_ordered = cummean(PEP_ordered)
	ans[order_vec] = qvalue_ordered
	ans
}

if(interactive()==FALSE){
	args = commandArgs(TRUE)
}
if(length(args) < 3){
	stop("Usage: Rscript this.r <output_prefix> <in1_foreground_prefix> <in2_background_prefix> [pos_range]")
}

output_prefix = args[1]
input_foreground_prefix = args[2]
input_background_prefix = args[3]

pos_range = NULL
if(length(args) >= 4){
	pos_range = args[4]
	tmp = as.integer(strsplit(pos_range, "[:-]")[[1]])
	if(length(tmp)==1){
		# good, do nothing
		# 2019-08-21, Yyx debug, pos_range will be character without converting
		pos_range = as.integer(tmp[1])
	}else if(length(tmp)==2){
		pos_range = tmp[1]:tmp[2]
	}else{
		stop("Cannot recognize pos_range = " %.% pos_range)
	}
}

input_foreground_stat_DF = read.delim(input_foreground_prefix %.% ".all.stat.txt")
echo(dim(input_foreground_stat_DF))
input_background_stat_DF = read.delim(input_background_prefix %.% ".all.stat.txt")
echo(dim(input_background_stat_DF))
stopifnot(nrow(input_foreground_stat_DF)==nrow(input_background_stat_DF))

names(input_foreground_stat_DF) = "in1." %.% names(input_foreground_stat_DF)
names(input_background_stat_DF) = "in2." %.% names(input_background_stat_DF)   # there is a bug in previous version, and debugged on 2019-08-29
input_DF = cbind(input_foreground_stat_DF, input_background_stat_DF)
echo(dim(input_DF))

input_DF$in1.simu_num = NA
input_DF$in1.mu_mean = NA
input_DF$in1.mu_LB = NA
input_DF$in1.mu_UB = NA
input_DF$in2.simu_num = NA
input_DF$in2.mu_mean = NA
input_DF$in2.mu_LB = NA
input_DF$in2.mu_UB = NA
input_DF$muDiff.simu_num = NA
input_DF$muDiff_mean = NA
input_DF$muDiff_LB = NA
input_DF$muDiff_UB = NA
input_DF$muDiff_gt0_posterior = NA
input_DF$muDiff_gt0_01_posterior = NA
input_DF$muDiff_gt0_05_posterior = NA
input_DF$muDiff_gt0_1_posterior = NA

real_pos_range = 1:nrow(input_DF)
if(!is.null(pos_range)){
	real_pos_range = pos_range[pos_range %in% 1:nrow(input_DF)]
}

for(i in real_pos_range){
	echo(i)
	try({
	mcmc_1 = read.delim(input_foreground_prefix %.% ".site_" %.% i %.% ".mcmc_rlt.tsv")
	input_DF$in1.simu_num[i] = nrow(mcmc_1)
	input_DF$in1.mu_mean[i] = mean(mcmc_1$mu)
	tmp = hdi(mcmc_1$mu)
	input_DF$in1.mu_LB[i] = tmp[1]
	input_DF$in1.mu_UB[i] = tmp[2]
	})

	try({
	mcmc_2 = read.delim(input_background_prefix %.% ".site_" %.% i %.% ".mcmc_rlt.tsv")
	input_DF$in2.simu_num[i] = nrow(mcmc_2)
	input_DF$in2.mu_mean[i] = mean(mcmc_2$mu)
	tmp = hdi(mcmc_2$mu)
	input_DF$in2.mu_LB[i] = tmp[1]
	input_DF$in2.mu_UB[i] = tmp[2]
	})

	try({
	NS = min(c(nrow(mcmc_1), nrow(mcmc_2)))
	muDiff_vec = mcmc_1$mu[1:NS] - mcmc_2$mu[1:NS]
	input_DF$muDiff.simu_num[i] = NS
	input_DF$muDiff_mean[i] = mean(muDiff_vec)
	tmp = hdi(muDiff_vec)
	input_DF$muDiff_LB[i] = tmp[1]
	input_DF$muDiff_UB[i] = tmp[2]
	input_DF$muDiff_gt0_posterior[i] = mean(muDiff_vec > 0)
	input_DF$muDiff_gt0_01_posterior[i] = mean(muDiff_vec > 0.01)
	input_DF$muDiff_gt0_05_posterior[i] = mean(muDiff_vec > 0.05)
	input_DF$muDiff_gt0_1_posterior[i] = mean(muDiff_vec > 0.1)
	})
}
write.table(input_DF[real_pos_range,], file=output_prefix %.% ".final_" %.% min(pos_range) %.% "_" %.% max(pos_range) %.% ".stat.txt", row.names=FALSE, sep="\t", quote=FALSE)

for(gt_str in c("0", "0_01", "0_05", "0_1")){
	input_DF[["muDiff_gt" %.% gt_str %.% "_PEP"]] = 1 - input_DF[["muDiff_gt" %.% gt_str %.% "_posterior"]]
	input_DF[["muDiff_gt" %.% gt_str %.% "_FDR"]] = PEP_to_qvalues(input_DF[["muDiff_gt" %.% gt_str %.% "_PEP"]])
}
write.table(input_DF[real_pos_range,], file=output_prefix %.% ".final_" %.% min(pos_range) %.% "_" %.% max(pos_range) %.% ".stat.txt", row.names=FALSE, sep="\t", quote=FALSE)


#!/usr/bin/Rscript

## icdiff.r -- Calculate information content difference for
## fastphase-formatted genotype file

## Author: David Eccles (gringer), 2008 <programming@gringer.org>

usage <- function(){
  cat("usage: ./icdiff.r","<input file> <output file>\n");
  cat("\nOther Options:\n");
  cat("-help               : Only display this help message\n");
  cat("-hapmap3            : Hapmap phase 3 formatted Files\n");
  cat("\n");
}

infile.name <- FALSE;
outfile.name <- FALSE;
hapmap3 <- FALSE;

argLoc <- 1;
while(!is.na(commandArgs(TRUE)[argLoc])){
  if(file.exists(commandArgs(TRUE)[argLoc])){ # file existence check
    if(infile.name == FALSE){
      infile.name <- commandArgs(TRUE)[argLoc];
    } else {
      cat("Error: More than one existing [input] file specified\n");
      usage();
      quit(save = "no", status=1);
    }
  } else {
    if(commandArgs(TRUE)[argLoc] == "-help"){
      usage();
      quit(save = "no", status=0);
    } else if(commandArgs(TRUE)[argLoc] == "-hapmap3"){
      hapmap3 <- TRUE;
    } else {
      outfile.name <- commandArgs(TRUE)[argLoc];
    }
  }
  argLoc <- argLoc + 1;
}

if((infile.name == FALSE) || (outfile.name == FALSE)){
  cat("Error: No valid input/output file name given\n\n");
  usage();
  quit(save = "no", status=1);
}

## max(table(apply(head(gt.df,33), 2, paste, collapse = ""))) == 1;

## # show heatmap of first 33 genotypes (at start of chromosome 21)
## heatmap(t(head(gt.df,33)), scale = "none", Colv = NA);

## dist.ind <- as.matrix(dist(t(gt.df), method = "manhattan"))
## diag(dist.ind) <- NA;

## ## because of recombination, bits of one parent will be scattered
## ## through each chromosome, so the differences will even out over
## ## large stretches of the chromosome, so differences between each
## ## homologous chromosome and chromosomes from other people will
## ## balance out.
## heatmap(as.matrix(dist.ind), col = topo.colors(100), symm = TRUE)

## information content of some split with counts A1,A2,An:
## let P(An) = An / Sum(A1..An)
## Ic = Sum(-P(An) * log(An,2))
## [Russell, pages 659-660]

## What I want is the difference between the maximum split and the
## actual split. Sum that, and it should give an indication of the
## prevalence of particular haplotypes over others (i.e. extended
## haplotype homozygosity).

## Need to make sure it continues for at least log(n) iterations,
## because until then, we don't know if a haplotype is more prevalent
## than expected in the random case.

## this spreads out in both directions, averaging one choosing to go
## left first and one choosing to go right first

icDiffSum <- function(genotype.matrix, location, constrain = TRUE){
  if(is.null(dim(genotype.matrix))){
    dim(genotype.matrix) <- c(length(genotype.matrix),1);
  }
  ic.target <- log(dim(genotype.matrix)[1],2);
  num.haplotypes <- dim(genotype.matrix)[1];
  ic.diffs.left <- NULL;
  lengths.left <- NULL;
  ic.diffs.right <- NULL;
  lengths.right <- NULL;
  for(leftBias in c(TRUE, FALSE)){
    goLeft <- leftBias;
    diffpos <- 1;
    ic.value <- 0;
    loc.left <- location;
    loc.right <- location;
    while(ic.value < ic.target){
      if(constrain){
        ## constrain information content to maximum possible with
        ## given number of haplotypes
        ic.max <- min(((loc.right - loc.left) + 1), ic.target);
      } else {
        ic.max <- (loc.right - loc.left) + 1;
      }
      ## warning: null genotypes appear as genotype "NA"
      if(loc.right != loc.left){
        prob.hap <- table(apply(genotype.matrix[,loc.left:loc.right],
                                1, paste, collapse = "")) / num.haplotypes;
      } else {
        prob.hap <- table(genotype.matrix[,loc.left]) / num.haplotypes;
      }
      ic.value <- sum(-prob.hap * log(prob.hap,2));
      ##print(paste(leftBias, " -> ", ic.value));
      if(leftBias == TRUE){
        ic.diffs.left[diffpos] <- (ic.max - ic.value) / ic.max;
        lengths.left[diffpos] <- (loc.right-loc.left) + 1;
      } else {
        ic.diffs.right[diffpos] <- (ic.max - ic.value) / ic.max;
        lengths.right[diffpos] <- (loc.right-loc.left) + 1;
      }
      diffpos <- diffpos + 1;
      ## Extra logic to make sure it doesn't duplicate results by
      ## hanging in the same place for two iterations. These two
      ## 'goLeft' cases could be combined, but it makes the code less
      ## clear.
      if(goLeft){
        goLeft <- !goLeft; # i.e. goLeft <- FALSE
        if(loc.left > 1){
          loc.left <- max(1,loc.left - 1);
        } else {
          loc.right <- min(dim(genotype.matrix)[2],loc.right + 1);
        }
      } else {
        goLeft <- !goLeft; # i.e. goLeft <- TRUE
        if(loc.right < dim(genotype.matrix)[2]){
          loc.right <- min(dim(genotype.matrix)[2],loc.right + 1);
        } else {
          loc.left <- max(1,loc.left - 1);
        }
      }
      if((loc.left == 1) && (loc.right == dim(genotype.matrix)[2])){
        ## if the entire chromosome is covered, do no more
        ic.value <- ic.target;
      }
    }
  }
  ## print(rbind(round(lengths.left,5),round(ic.diffs.left,5)));
  ## print(rbind(round(lengths.right,5),round(ic.diffs.right,5)));
  return((sum(ic.diffs.left) + sum(ic.diffs.right))/2);
}

oldicDiffSum <- function(genotype.matrix){
  ic.diffs <- NULL;
  ic.diff <- 1;
  ic.value <- 0;
  x <- 1;
  if(is.null(dim(genotype.matrix))){
    dim(genotype.matrix) <- c(1,length(genotype.matrix));
  }
  ic.target <- log(dim(genotype.matrix)[2],2);
  while((ic.value < ic.target) && (x <= dim(genotype.matrix)[1])){
    ic.max <- min(x,ic.target);
    counts.hap <- table(apply(head(genotype.matrix,x), 2, paste, collapse = ""));
    prob.hap <- counts.hap / sum(counts.hap);
    ic.value <- sum(-prob.hap * log(prob.hap,2));
    ic.diff <- ((ic.max - ic.value) / ic.max);
    ic.diffs <- c(ic.diffs,ic.diff);
    x <- x+1;
  }
  return(sum(ic.diffs));
}

gtval <- function(x){
  if((is.matrix(x)) || (is.data.frame(x))){
    apply(x,2,function(data){
      as.numeric(sub("A|T",1,sub("G|C",2,data)));
    });
  } else if(is.vector(x)) {
    as.numeric(sub("A|T",1,sub("G|C",2,x)));
  } else {
    if((x = "A") || (x = "T")){
      1;
    } else if((x = "C") || (x = "G")){
      2;
    } else {
      0;
    }
  }
}

## ## The following test suggests that this algorithm is tractable and
## ## shouldn't need further optimisations:

## ## 1) It is linear in complexity for number of markers [O(n)]

## system.time(for(x in 1:10){oldicDiffSum(gt.df[-(1:x),])})
## ##   user  system elapsed
## ##  2.120   0.028   2.267
## system.time(for(x in 1:100){oldicDiffSum(gt.df[-(1:x),])})
## ##   user  system elapsed
## ## 17.393   0.240  17.688

## ## 2) Estimated runtime for chromosome 21 is less than half an
## ##    hour (actually, 16 minutes, 5435 markers)

## ## > (5435/100 * 17.393) / 60
## ## [1] 15.75516

## ## [Estimated runtime for chromosome 1 is about 1.5 hours, 23062
## ## markers]

cat("Retrieving data for chromosome ...");
inFile <- gzfile(infile.name);
open(inFile);
lineRead <- "";
if(!hapmap3){
  while(lineRead != "BEGINGENOTYPES"){ # read until genotype start
    lineRead <- paste(scan(inFile, nlines = 1,
                           what = character(0),
                           quiet = TRUE)[1:2], collapse = "");
  }
  lineRead <- "";
  person.id <- "";
  gt.df <- NULL;
  while(lineRead != "END GENOTYPES"){ # read until genotype end
    lineRead <- readLines(inFile, n = 1, warn = FALSE);
    if(substr(lineRead,3,4) == "id"){
      person.id <- substr(lineRead,6,nchar(lineRead));
      hap.1 <- scan(inFile, nlines = 1, quiet = TRUE);
      hap.2 <- scan(inFile, nlines = 1, quiet = TRUE);
      new.df <- cbind(hap.1, hap.2);
      colnames(new.df) <- paste(person.id,c(1,2), sep = ".");
      gt.df <- cbind(gt.df,new.df);
    }
  }
  colnames(gt.df) <- sub("0+([0-9][0-9]\\.)","\\1",
                         colnames(gt.df), perl=TRUE);
  gt.df <- t(gt.df);
} else { # if hapmap3-formatted input (but no header)
  gt.df <- read.table(inFile, row.names = 1, header = FALSE);
  gt.df <- gt.df[,-1];
  marker.names <- rownames(gt.df);
  gt.df <- data.frame(t(gt.df));
}
close(inFile);
cat("done\n");
cat("Calculating distance matrix to eliminate identical chromosomes...");
if(hapmap3){
  dist.ind <- as.matrix(dist(gtval(gt.df), method = "manhattan"));
} else {
  dist.ind <- as.matrix(dist(gt.df), method = "manhattan");
}
remove.columns <- NULL;
for(haplotype in 1:(dim(gt.df)[1])){
  ## if fewer than 20 differences, treat as the same chromosome
  ## this allows for some genotyping error
  if(length(which(which(dist.ind[haplotype,] < 20) > haplotype) > 0)){
    remove.columns <- c(remove.columns, (which(dist.ind[haplotype,] < 20))
                        [which(dist.ind[haplotype,] < 20) > haplotype]);
  }
}
if(length(remove.columns) > 0){
  gt.df <- gt.df[,-remove.columns];
}
cat("done (",length(unique(remove.columns))," columns removed)\n",sep="");
outFile <- file(outfile.name);
open(outFile, open = "w");
for(marker in 1:(dim(gt.df)[2])){
  cat(colnames(gt.df)[marker]," ",icDiffSum(gt.df, marker),
      "\n", file = outFile, sep = "");
}
close(outFile);