diff --git a/exec/00_gp_slurm_job_wrapper-LUCERNE.sh b/exec/00_gp_slurm_job_wrapper-LUCERNE.sh new file mode 100755 index 0000000..f84ef8d --- /dev/null +++ b/exec/00_gp_slurm_job_wrapper-LUCERNE.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +### Load the conda environment +module load Miniconda3/22.11.1-1 +conda init bash +source ~/.bashrc +conda activate genomic_selection + +################################################################ +### TOP-LEVEL SLURM ARRAY JOB SUBMISSION SCRIPT +### Please edit the input variables below to match your dataset: +################################################################ + +### Input variables (use the absolute path to files to be precise) +### (1) R matrix object with n rows corresponding to samples, and p columns corresponding to the markers or loci. +### Should have no missing data or else will be imputed via mean value imputation. +GENOTYPE_DATA_RDS='/group/pasture/Jeff/lucerne/workdir/FINAL-IMPUTED-noTrailingAllele-filteredSNPlist.Rds' +### (2) Tab-delimited phenotype file where column 1: sample names, column 2: population name, columns 3 and so on refers to the phenotype values of one trait per column. +### Headers for the columns should be named appropriately, e.g. ID, POP, TRAIT1, TRAIT2, etc. +### Missing values are allowed for samples whose phenotypes will be predicted by the best model identified within the population they belong to. +### Missing values may be coded as empty cells, -, NA, na, NaN, missing, and/or MISSING. +PHENOTYPE_DATA_TSV='/group/pasture/Jeff/lucerne/workdir/Lucerne_PhenomicsDB_2024-05-27-BiomassPredicted.tsv' +### (3) Number of folds for k-fold cross-validation. +KFOLDS=5 +### (4) Number of replications of the k-fold cross-validation each representing a random sorting of the samples hence yielding different ways of partitioning the data. +NREPS=5 +### (5) Full path to the location of the executable Rscript gp.R +DIR='/group/pasture/Jeff/gp/exec' + +### Check if the genotype file exists +if [ ! -f $GENOTYPE_DATA_RDS ] +then + echo "Error: The genotype file: $GENOTYPE_DATA_RDS does not exist. Are you specifying the full path? Is the name correct?" + exit 101 +fi +### Check if the phenotype file exists +if [ ! -f $PHENOTYPE_DATA_TSV ] +then + echo "Error: The phenotype file: $PHENOTYPE_DATA_TSV does not exist. Are you specifying the full path? Is the name correct?" + exit 102 +fi +### Check if the genotype file is a valid Rds file +echo 'args = commandArgs(trailingOnly=TRUE) +geno = suppressWarnings(tryCatch(readRDS(args[1]), error=function(e){print("Error loading genotype file.")})) +' > test_geno_rds.R +if [ $(Rscript test_geno_rds.R $GENOTYPE_DATA_RDS | grep -i "error" | wc -l) -eq 1 ] +then + echo "Error: The genotype file: $GENOTYPE_DATA_RDS is not an Rds file." + exit 103 +fi +rm test_geno_rds.R +### Check if the phenotype file is formatted according to the required specifications +echo 'args = commandArgs(trailingOnly=TRUE) +pheno = suppressWarnings(tryCatch(read.delim(args[1], sep="\t", header=TRUE), error=function(e){print("Error loading phenotype file.")})) +' > test_pheno_rds.R +if [ $(Rscript test_pheno_rds.R $PHENOTYPE_DATA_TSV | grep -i "error" | wc -l) -eq 1 ] +then + echo "Error: The phenotype file: $GENOTYPE_DATA_RDS is not formatted according to specifications. It should be tab-delimited and a header line must be present." + exit 104 +fi +rm test_pheno_rds.R +### Check if the genomic_selection repo folder exists +if [ ! -d $DIR ] +then + echo "Error: The genotype_selection directory: $DIR does not exist. Are you specifying the full path? Is the name correct?" + exit 105 +fi +### Check if the genomic_selection repo belongs to the user +if [ ! -w $DIR ] +then + echo "Error: You do not have permission to write in the genotype_selection directory: $DIR. Did you clone the genomic_selection repository into a directory you have write-access to?" + exit 106 +fi +### Check if the genomic_selection repo has contains the slurm array job submission script +if [ ! -f ${DIR}/01_gp_slurm_job.sh ] +then + echo "Error: The genotype_selection directory: $DIR does not contain the script: 01_gp_slurm_job.sh. Are you sure this is the genomic_selection repo directory?" + exit 107 +fi +### Initialise the output directory which will contain all the output Rds files across populations and traits +if [ ! -d ${DIR}/output ] +then + mkdir ${DIR}/output +fi +### Submit an array of jobs equivalent to the number of traits in the phenotype file +cd $DIR/ +N_TRAITS=$(echo $(head -n1 $PHENOTYPE_DATA_TSV | awk '{print NF}') - 2 | bc) +N_POPS=$(tail -n+2 $PHENOTYPE_DATA_TSV | cut -f2 - | sort | uniq | wc -l) +sbatch --array 1-$(echo "${N_TRAITS} * ${N_POPS}" | bc) \ + 01_gp_slurm_job-LUCERNE.sh \ + ${GENOTYPE_DATA_RDS} \ + ${PHENOTYPE_DATA_TSV} \ + ${KFOLDS} \ + ${NREPS} \ + ${DIR} diff --git a/exec/00_gp_slurm_job_wrapper-RYEGRASS.sh b/exec/00_gp_slurm_job_wrapper-RYEGRASS.sh new file mode 100755 index 0000000..574382e --- /dev/null +++ b/exec/00_gp_slurm_job_wrapper-RYEGRASS.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +### Load the conda environment +module load Miniconda3/22.11.1-1 +conda init bash +source ~/.bashrc +conda activate genomic_selection + +################################################################ +### TOP-LEVEL SLURM ARRAY JOB SUBMISSION SCRIPT +### Please edit the input variables below to match your dataset: +################################################################ + +### Input variables (use the absolute path to files to be precise) +### (1) R matrix object with n rows corresponding to samples, and p columns corresponding to the markers or loci. +### Should have no missing data or else will be imputed via mean value imputation. +GENOTYPE_DATA_RDS='/group/pasture/Jeff/ryegrass/workdir/STR_NUE_WUE_HS-1717536141.3435302.3200855812-IMPUTED.Rds' +### (2) Tab-delimited phenotype file where column 1: sample names, column 2: population name, columns 3 and so on refers to the phenotype values of one trait per column. +### Headers for the columns should be named appropriately, e.g. ID, POP, TRAIT1, TRAIT2, etc. +### Missing values are allowed for samples whose phenotypes will be predicted by the best model identified within the population they belong to. +### Missing values may be coded as empty cells, -, NA, na, NaN, missing, and/or MISSING. +PHENOTYPE_DATA_TSV='/group/pasture/Jeff/ryegrass/workdir/STR_NUE_WUE_PhenomicsDB_2024-05-20-BiomassPredictedAndGroudtruth.tsv' +### (3) Number of folds for k-fold cross-validation. +KFOLDS=5 +### (4) Number of replications of the k-fold cross-validation each representing a random sorting of the samples hence yielding different ways of partitioning the data. +NREPS=5 +### (5) Full path to the location of the executable Rscript gp.R +DIR='/group/pasture/Jeff/gp/exec' + +### Check if the genotype file exists +if [ ! -f $GENOTYPE_DATA_RDS ] +then + echo "Error: The genotype file: $GENOTYPE_DATA_RDS does not exist. Are you specifying the full path? Is the name correct?" + exit 101 +fi +### Check if the phenotype file exists +if [ ! -f $PHENOTYPE_DATA_TSV ] +then + echo "Error: The phenotype file: $PHENOTYPE_DATA_TSV does not exist. Are you specifying the full path? Is the name correct?" + exit 102 +fi +### Check if the genotype file is a valid Rds file +echo 'args = commandArgs(trailingOnly=TRUE) +geno = suppressWarnings(tryCatch(readRDS(args[1]), error=function(e){print("Error loading genotype file.")})) +' > test_geno_rds.R +if [ $(Rscript test_geno_rds.R $GENOTYPE_DATA_RDS | grep -i "error" | wc -l) -eq 1 ] +then + echo "Error: The genotype file: $GENOTYPE_DATA_RDS is not an Rds file." + exit 103 +fi +rm test_geno_rds.R +### Check if the phenotype file is formatted according to the required specifications +echo 'args = commandArgs(trailingOnly=TRUE) +pheno = suppressWarnings(tryCatch(read.delim(args[1], sep="\t", header=TRUE), error=function(e){print("Error loading phenotype file.")})) +' > test_pheno_rds.R +if [ $(Rscript test_pheno_rds.R $PHENOTYPE_DATA_TSV | grep -i "error" | wc -l) -eq 1 ] +then + echo "Error: The phenotype file: $GENOTYPE_DATA_RDS is not formatted according to specifications. It should be tab-delimited and a header line must be present." + exit 104 +fi +rm test_pheno_rds.R +### Check if the genomic_selection repo folder exists +if [ ! -d $DIR ] +then + echo "Error: The genotype_selection directory: $DIR does not exist. Are you specifying the full path? Is the name correct?" + exit 105 +fi +### Check if the genomic_selection repo belongs to the user +if [ ! -w $DIR ] +then + echo "Error: You do not have permission to write in the genotype_selection directory: $DIR. Did you clone the genomic_selection repository into a directory you have write-access to?" + exit 106 +fi +### Check if the genomic_selection repo has contains the slurm array job submission script +if [ ! -f ${DIR}/01_gp_slurm_job.sh ] +then + echo "Error: The genotype_selection directory: $DIR does not contain the script: 01_gp_slurm_job.sh. Are you sure this is the genomic_selection repo directory?" + exit 107 +fi +### Initialise the output directory which will contain all the output Rds files across populations and traits +if [ ! -d ${DIR}/output ] +then + mkdir ${DIR}/output +fi +### Submit an array of jobs equivalent to the number of traits in the phenotype file +cd $DIR/ +N_TRAITS=$(echo $(head -n1 $PHENOTYPE_DATA_TSV | awk '{print NF}') - 2 | bc) +N_POPS=$(tail -n+2 $PHENOTYPE_DATA_TSV | cut -f2 - | sort | uniq | wc -l) +sbatch --array 1-$(echo "${N_TRAITS} * ${N_POPS}" | bc) \ + 01_gp_slurm_job-RYEGRASS.sh \ + ${GENOTYPE_DATA_RDS} \ + ${PHENOTYPE_DATA_TSV} \ + ${KFOLDS} \ + ${NREPS} \ + ${DIR} diff --git a/exec/01_gp_slurm_job-LUCERNE.sh b/exec/01_gp_slurm_job-LUCERNE.sh new file mode 100755 index 0000000..f646369 --- /dev/null +++ b/exec/01_gp_slurm_job-LUCERNE.sh @@ -0,0 +1,120 @@ +#!/bin/bash +#SBATCH --job-name="GS" +#SBATCH --account="dbiopast2" ### EDIT ME: Pick the appropriate account name, e.g. dbiopast1 or dbiopast2 +#SBATCH --ntasks=1 ### LEAVE ME:Request a single task as we will be submitting this as an array job where each job corresponds to a trait +#SBATCH --cpus-per-task=32 ### EDIT ME: Parallelisation across replications, folds and models (more cpu means faster execution time but probably longer time to wait for the Slurm scheduler to find resources to allocate to the job) +#SBATCH --mem=400G ### EDIT ME: Proportional to the input data (will need to test the appropriate memory required, hint use `seff ${JOBID}`) +#SBATCH --time=7-0:0:00 ### EDIT ME: Proportional to the input data, number of folds, replications, and models to be used +################################################################################################### +### Edit the Slurm settings above to match your requirements. +################################################################################################### + +################################################################################################### +### The variables below will be exported from `00_gs_slurm_job_wrapper.sh`: +################################################################################################### +### Input variables (use the absolute path to files to be precise) +### (1) R matrix object with n rows corresponding to samples, and p columns corresponding to the markers or loci. +### Should have no missing data or else will be imputed via mean value imputation. +# GENOTYPE_DATA_RDS='/group/pasture/Jeff/genomic_selection/tests/grape.rds' +GENOTYPE_DATA_RDS=$1 +### (2) Tab-delimited phenotype file where column 1: sample names, column 2: population name, columns 3 and so on refers to the phenotype values of one trait per column. +### Headers for the columns should be named appropriately, e.g. ID, POP, TRAIT1, TRAIT2, etc. +### Missing values are allowed for samples whose phenotypes will be predicted by the best model identified within the population they belong to. +### Missing values may be coded as empty cells, -, NA, na, NaN, missing, and/or MISSING. +# PHENOTYPE_DATA_TSV='/group/pasture/Jeff/genomic_selection/tests/grape_pheno.txt' +PHENOTYPE_DATA_TSV=$2 +### (3) Number of folds for k-fold cross-validation. +# KFOLDS=5 +KFOLDS=$3 +### (4) Number of replications of the k-fold cross-validation each representing a random sorting of the samples hence yielding different ways of partitioning the data. +# NREPS=3 +NREPS=$4 +### (5) Full path to the location of the executable Rscript gp.R +# DIR='/group/pasture/Jeff/gp/exec' +DIR=$5 +################################################################################################### +### Edit the code below, if and only if you have read the documentation or familiar with `src/*.R`: +################################################################################################### +### Define the trait and population to include +N_POPS=$(tail -n+2 $PHENOTYPE_DATA_TSV | cut -f2 - | sort | uniq | wc -l) +TRAIT_IDX=$(echo "((${SLURM_ARRAY_TASK_ID}-1) / ${N_POPS}) + 1" | bc) +POP_IDX=$(echo "${SLURM_ARRAY_TASK_ID} % ${N_POPS}" | bc) +if [ "${POP_IDX}" -eq 0 ] +then + POP_IDX=${N_POPS} +fi +COLUMN_ID=$(echo 2 + ${TRAIT_IDX} | bc) +TRAIT=$(head -n1 $PHENOTYPE_DATA_TSV | cut -f${COLUMN_ID}) +POP=$(tail -n+2 $PHENOTYPE_DATA_TSV | cut -f2 - | sort | uniq | head -n${POP_IDX} | tail -n1) +### Skip leave-one-population-out cross-validation if there is only one population +if [ "${N_POPS}" -eq 1 ] +then + BOOL_ACROSS=FALSE +else + if [ "${POP_IDX}" -eq 1 ] + then + BOOL_ACROSS=TRUE + else + BOOL_ACROSS=FALSE + fi +fi +### Output directories +DIR_OUT_MAIN=${DIR}/output +DIR_OUT=${DIR_OUT_MAIN}/output-${TRAIT}-${POP} +mkdir $DIR_OUT +### Log messages +echo JOB_${SLURM_ARRAY_TASK_ID}-TRAIT_${TRAIT}-POP_${POP} > ${DIR_OUT}/job_info-${TRAIT}-${POP}.log +echo "========================================== +------------------------------------------- + Job Info +------------------------------------------- +SLURM_JOB_ID = $SLURM_JOB_ID +SLURM_JOB_NAME = $SLURM_JOB_NAME +SLURM_JOB_NODELIST = $SLURM_JOB_NODELIST +SLURM_SUBMIT_HOST = $SLURM_SUBMIT_HOST +SLURM_SUBMIT_DIR = $SLURM_SUBMIT_DIR +SLURM_NTASKS = $SLURM_NTASKS +SLURM_ARRAY_TASK_ID = $SLURM_ARRAY_TASK_ID +SLURM_MEM_PER_NODE = $(echo "$SLURM_MEM_PER_NODE / (2^10)" | bc) GB +SLURM_CPUS_PER_TASK = $SLURM_CPUS_PER_TASK +------------------------------------------- + Variables +------------------------------------------- +GENOTYPE_DATA_RDS : $GENOTYPE_DATA_RDS +PHENOTYPE_DATA_TSV : $PHENOTYPE_DATA_TSV +KFOLDS : $KFOLDS +NREPS : $NREPS +TRAIT : $TRAIT +POPULATION : $POP +------------------------------------------- + Output directory +------------------------------------------- +${DIR_OUT} +==========================================" >> ${DIR_OUT}/job_info-${TRAIT}-${POP}.log + +### Load the conda environment +module load Miniconda3/22.11.1-1 +conda init bash +source ~/.bashrc +conda activate genomic_selection + +### Run within and across population replicated k-fold cross-validation and prediction of missing phenotypes +time \ +Rscript ${DIR}/gp.R \ + --fname-geno $GENOTYPE_DATA_RDS \ + --fname-pheno $PHENOTYPE_DATA_TSV \ + --population $POP \ + --dir-output $DIR_OUT \ + --pheno-idx-col-y $COLUMN_ID \ + --bool-within TRUE \ + --bool-across $BOOL_ACROSS \ + --n-folds $KFOLDS \ + --n-reps $NREPS \ + --bool-parallel TRUE \ + --max-mem-Gb $(echo "$SLURM_MEM_PER_NODE / (2^10)" | bc) \ + --n-threads $SLURM_CPUS_PER_TASK \ + --verbose TRUE >> ${DIR_OUT}/job_info-${TRAIT}-${POP}.log +### Clean-up +mv ${DIR_OUT}/GENOMIC_PREDICTIONS_OUTPUT-*.Rds ${DIR_OUT_MAIN} +mv ${DIR_OUT}/job_info-${TRAIT}-${POP}.log ${DIR_OUT_MAIN} +rm -R ${DIR_OUT} diff --git a/exec/01_gp_slurm_job-RYEGRASS.sh b/exec/01_gp_slurm_job-RYEGRASS.sh new file mode 100755 index 0000000..5a32a1e --- /dev/null +++ b/exec/01_gp_slurm_job-RYEGRASS.sh @@ -0,0 +1,117 @@ +#!/bin/bash +#SBATCH --job-name="GS" +#SBATCH --account="dbiopast1" ### EDIT ME: Pick the appropriate account name, e.g. dbiopast1 or dbiopast2 +#SBATCH --ntasks=1 ### LEAVE ME:Request a single task as we will be submitting this as an array job where each job corresponds to a trait +#SBATCH --cpus-per-task=32 ### EDIT ME: Parallelisation across replications, folds and models (more cpu means faster execution time but probably longer time to wait for the Slurm scheduler to find resources to allocate to the job) +#SBATCH --mem=250G ### EDIT ME: Proportional to the input data (will need to test the appropriate memory required, hint use `seff ${JOBID}`) +#SBATCH --time=5-0:0:00 ### EDIT ME: Proportional to the input data, number of folds, replications, and models to be used +################################################################################################### +### Edit the Slurm settings above to match your requirements. +################################################################################################### + +################################################################################################### +### The variables below will be exported from `00_gs_slurm_job_wrapper.sh`: +################################################################################################### +### Input variables (use the absolute path to files to be precise) +### (1) R matrix object with n rows corresponding to samples, and p columns corresponding to the markers or loci. +### Should have no missing data or else will be imputed via mean value imputation. +# GENOTYPE_DATA_RDS='/group/pasture/Jeff/genomic_selection/tests/grape.rds' +GENOTYPE_DATA_RDS=$1 +### (2) Tab-delimited phenotype file where column 1: sample names, column 2: population name, columns 3 and so on refers to the phenotype values of one trait per column. +### Headers for the columns should be named appropriately, e.g. ID, POP, TRAIT1, TRAIT2, etc. +### Missing values are allowed for samples whose phenotypes will be predicted by the best model identified within the population they belong to. +### Missing values may be coded as empty cells, -, NA, na, NaN, missing, and/or MISSING. +# PHENOTYPE_DATA_TSV='/group/pasture/Jeff/genomic_selection/tests/grape_pheno.txt' +PHENOTYPE_DATA_TSV=$2 +### (3) Number of folds for k-fold cross-validation. +# KFOLDS=5 +KFOLDS=$3 +### (4) Number of replications of the k-fold cross-validation each representing a random sorting of the samples hence yielding different ways of partitioning the data. +# NREPS=3 +NREPS=$4 +### (5) Full path to the location of the executable Rscript gp.R +# DIR='/group/pasture/Jeff/gp/exec' +DIR=$5 +################################################################################################### +### Edit the code below, if and only if you have read the documentation or familiar with `src/*.R`: +################################################################################################### +### Define the trait and population to include +N_POPS=$(tail -n+2 $PHENOTYPE_DATA_TSV | cut -f2 - | sort | uniq | wc -l) +TRAIT_IDX=$(echo "((${SLURM_ARRAY_TASK_ID}-1) / ${N_POPS}) + 1" | bc) +POP_IDX=$(echo "${SLURM_ARRAY_TASK_ID} % ${N_POPS}" | bc) +if [ "${POP_IDX}" -eq 0 ] +then + POP_IDX=${N_POPS} +fi +COLUMN_ID=$(echo 2 + ${TRAIT_IDX} | bc) +TRAIT=$(head -n1 $PHENOTYPE_DATA_TSV | cut -f${COLUMN_ID}) +POP=$(tail -n+2 $PHENOTYPE_DATA_TSV | cut -f2 - | sort | uniq | head -n${POP_IDX} | tail -n1) +### Skip leave-one-population-out cross-validation if there is only one population +if [ "${N_POPS}" -eq 1 ] +then + BOOL_ACROSS=FALSE +else + if [ "${POP_IDX}" -eq 1 ] + then + BOOL_ACROSS=TRUE + else + BOOL_ACROSS=FALSE + fi +fi +### Output directories +DIR_OUT_MAIN=${DIR}/output +DIR_OUT=${DIR_OUT_MAIN}/output-${TRAIT}-${POP} +mkdir $DIR_OUT +### Log messages +echo JOB_${SLURM_ARRAY_TASK_ID}-TRAIT_${TRAIT}-POP_${POP} > ${DIR_OUT}/job_info-${TRAIT}-${POP}.log +echo "========================================== +------------------------------------------- + Job Info +------------------------------------------- +SLURM_JOB_ID = $SLURM_JOB_ID +SLURM_JOB_NAME = $SLURM_JOB_NAME +SLURM_JOB_NODELIST = $SLURM_JOB_NODELIST +SLURM_SUBMIT_HOST = $SLURM_SUBMIT_HOST +SLURM_SUBMIT_DIR = $SLURM_SUBMIT_DIR +SLURM_NTASKS = $SLURM_NTASKS +SLURM_ARRAY_TASK_ID = $SLURM_ARRAY_TASK_ID +------------------------------------------- + Variables +------------------------------------------- +GENOTYPE_DATA_RDS : $GENOTYPE_DATA_RDS +PHENOTYPE_DATA_TSV : $PHENOTYPE_DATA_TSV +KFOLDS : $KFOLDS +NREPS : $NREPS +TRAIT : $TRAIT +------------------------------------------- + Output directory +------------------------------------------- +${DIR_OUT} +==========================================" >> ${DIR_OUT}/job_info-${TRAIT}-${POP}.log + +### Load the conda environment +module load Miniconda3/22.11.1-1 +conda init bash +source ~/.bashrc +conda activate genomic_selection + +### Run within and across population replicated k-fold cross-validation and prediction of missing phenotypes +time \ +Rscript ${DIR}/gp.R \ + --fname-geno $GENOTYPE_DATA_RDS \ + --fname-pheno $PHENOTYPE_DATA_TSV \ + --population $POP \ + --dir-output $DIR_OUT \ + --pheno-idx-col-y $COLUMN_ID \ + --bool-within TRUE \ + --bool-across $BOOL_ACROSS \ + --n-folds $KFOLDS \ + --n-reps $NREPS \ + --bool-parallel TRUE \ + --max-mem-Gb $SLURM_MEM_PER_NODE \ + --n-threads $SLURM_CPUS_PER_TASK \ + --verbose TRUE >> ${DIR_OUT}/job_info-${TRAIT}-${POP}.log +### Clean-up +mv ${DIR_OUT}/GENOMIC_PREDICTIONS_OUTPUT-*.Rds ${DIR_OUT_MAIN} +mv ${DIR_OUT}/job_info-${TRAIT}-${POP}.log ${DIR_OUT_MAIN} +rm -R ${DIR_OUT} diff --git a/exec/tests/grape.Rds b/exec/tests/grape.Rds new file mode 100644 index 0000000..af372fb Binary files /dev/null and b/exec/tests/grape.Rds differ diff --git a/exec/tests/grape_pheno.tsv b/exec/tests/grape_pheno.tsv new file mode 100644 index 0000000..1c54973 --- /dev/null +++ b/exec/tests/grape_pheno.tsv @@ -0,0 +1,78 @@ +entry group dummy_phenotype dummy_phenotype_with_10_missing +Grape1:MERGE g_1 23.5381374964476 NA +Grape10:MERGE g_1 24.9505720936119 NA +Grape11:MERGE g_1 15.7444879989717 NA +Grape12:MERGE g_3 -8.8343125638148 NA +Grape13:MERGE g_1 -11.284077978673 NA +Grape14:MERGE g_3 -37.3410707860039 NA +Grape15:MERGE g_1 -1.18212393031896 NA +Grape17:MERGE g_1 12.3516621535621 NA +Grape18:MERGE g_3 -10.8056228420199 NA +Grape19:MERGE g_3 -11.7909281333106 NA +Grape20:MERGE g_2 10.48317064716 9.4001503902491 +Grape21:MERGE g_2 23.6551276315743 22.2187556729557 +Grape22:MERGE g_1 14.6029702123532 14.0372493658364 +Grape25:MERGE g_1 2.8072056841089 2.33220395060562 +Grape26:MERGE g_2 3.7270643827174 5.50198554606952 +Grape27:MERGE g_3 -20.6208074511543 -19.4892609942684 +Grape28:MERGE g_2 20.422323694328 20.9825637100559 +Grape29:MERGE g_3 -33.2413126506808 -32.9697239867334 +Grape30:MERGE g_1 16.5638297556618 16.1186110404052 +Grape31:MERGE g_1 -7.10375239741587 -4.6403711079849 +Grape32:MERGE g_1 0.476191573415302 0.806247548928381 +Grape33:MERGE g_3 -20.3610942590788 -19.3197573910514 +Grape34:MERGE g_3 -1.34859340149026 0.379198167724654 +Grape35:MERGE g_2 22.3661507357147 22.0708946325877 +Grape36:MERGE g_3 26.9938827278852 25.5617171711754 +Grape37:MERGE g_3 -27.4729421545443 -27.0436487491887 +Grape39:MERGE g_3 -27.7195074206229 -26.9231772902085 +Grape40:MERGE g_3 -17.6988813540433 -17.7301851620682 +Grape41:MERGE g_1 -32.2424066439846 -32.8796564586587 +Grape42:MERGE g_3 -0.967561756212053 -1.79107514329331 +Grape43:MERGE g_3 -9.15299047869434 -9.16703243533913 +Grape44:MERGE g_1 31.853190869054 31.954228258615 +Grape46:MERGE g_3 -6.41719697490732 -7.50964492695065 +Grape48:MERGE g_3 -8.31118727319531 -8.83553546107298 +Grape49:MERGE g_2 24.3663357347868 23.8613712460964 +Grape50:MERGE g_1 -23.4341187873299 -23.2404551626634 +Grape51:MERGE g_1 -11.4992708226544 -10.7563901387753 +Grape52:MERGE g_2 22.373253229066 22.7557855519618 +Grape53:MERGE g_3 -27.1507616278279 -27.7742428017575 +Grape54:MERGE g_3 -1.54733323054998 -0.291318202295207 +Grape55:MERGE g_3 -15.9786029255577 -15.9026641699913 +Grape56:MERGE g_1 9.33095922525655 10.1150489547282 +Grape57:MERGE g_3 2.55775066919576 2.83343376676098 +Grape58:MERGE g_3 -8.09163225225368 -8.8147000677584 +Grape59:MERGE g_1 0.56961338698426 -0.151881036361276 +Grape6:MERGE g_1 1.97264560331551 1.27725033862341 +Grape60:MERGE g_2 -4.6523292012708 -4.80815516483193 +Grape61:MERGE g_3 19.02553332324 17.5577571486201 +Grape62:MERGE g_3 5.88985405364896 5.32928266218876 +Grape63:MERGE g_3 -34.2937223684746 -33.8649083386099 +Grape64:MERGE g_3 -18.0263552536873 -20.24300860618 +Grape65:MERGE g_3 -8.0207977603204 -8.76610998881978 +Grape66:MERGE g_3 -29.1846929821102 -30.0502534438325 +Grape67:MERGE g_2 25.1040393385362 24.2893367981688 +Grape68:MERGE g_2 10.1165418631329 10.3972309725717 +Grape69:MERGE g_2 -7.88224633095993 -7.87403903207285 +Grape7:MERGE g_1 19.4824353747125 20.2255653900461 +Grape70:MERGE g_2 -25.6976364833835 -25.5965710238528 +Grape71:MERGE g_1 2.81878293988589 2.43511194607758 +Grape72:MERGE g_3 -7.40346626250736 -8.56397859721165 +Grape73:MERGE g_2 -6.01540741082493 -4.42950012584943 +Grape74:MERGE g_3 -17.2218594103819 -16.3104089105095 +Grape76:MERGE g_2 -7.73653912111139 -7.60728785534578 +Grape77:MERGE g_3 15.7098023079321 14.68283469026 +Grape78:MERGE g_3 -37.4150884849509 -38.4335205568808 +Grape81:MERGE g_1 -0.974746633551515 0.0804291000092735 +Grape82:MERGE g_2 0.601595206707301 -0.450001264212616 +Grape83:MERGE g_3 -4.68263476495642 -4.66306993654109 +Grape84:MERGE g_1 -17.1410904504135 -16.9154353983312 +Grape86:MERGE g_3 -2.58196632267392 -3.09016256286464 +Grape88:MERGE g_2 -18.0221099828036 -18.0599542703923 +Grape89:MERGE g_3 -19.2395785475012 -19.9079522501793 +Grape9:MERGE g_3 -32.5585104928072 -32.215564536882 +Grape91:MERGE g_2 18.5913047145126 18.3214670018996 +Grape92:MERGE g_3 14.9985431863512 15.0413089451049 +Grape93:MERGE g_3 -5.69969950790176 -6.85431361620004 +Grape95:MERGE g_1 -4.52066738467827 -3.88032575399918