{-# LANGUAGE OverloadedStrings #-}

module Poseidon.CLI.Genoconvert where

import           Poseidon.EntityTypes       (HasNameAndVersion (..))
import           Poseidon.GenotypeData      (GenoDataSource (..),
                                             GenotypeDataSpec (..),
                                             GenotypeFileSpec (..),
                                             loadGenotypeData,
                                             printSNPCopyProgress)
import           Poseidon.Janno             (jannoRows2EigenstratIndEntries)
import           Poseidon.Package           (PackageReadOptions (..),
                                             PoseidonPackage (..),
                                             defaultPackageReadOptions,
                                             makePseudoPackageFromGenotypeData,
                                             readPoseidonPackageCollection,
                                             writePoseidonPackage)
import           Poseidon.Utils             (PoseidonException (..), PoseidonIO,
                                             envErrorLength, envLogAction,
                                             logError, logInfo, logWarning)

import           Control.Exception          (catch, throwIO)
import           Control.Monad              (unless, when)
import           Data.List                  ((\\))
import           Data.Maybe                 (isJust)
import           Data.Time                  (getCurrentTime)
import           Pipes                      (MonadIO (liftIO), runEffect, (>->))
import           Pipes.Safe                 (runSafeT)
import           SequenceFormats.Eigenstrat (writeEigenstrat)
import           SequenceFormats.Plink      (PlinkPopNameMode,
                                             eigenstratInd2PlinkFam, writePlink)
import           System.Directory           (createDirectoryIfMissing,
                                             doesFileExist, removeFile,
                                             renameFile)
import           System.Exit                (ExitCode (..), exitWith)
import           System.FilePath            (dropTrailingPathSeparator, (<.>),
                                             (</>))

-- | A datatype representing command line options for the validate command
data GenoconvertOptions = GenoconvertOptions
    { GenoconvertOptions -> [GenoDataSource]
_genoconvertGenoSources     :: [GenoDataSource]
    , GenoconvertOptions -> [Char]
_genoConvertOutFormat       :: String
    , GenoconvertOptions -> Maybe [Char]
_genoMaybeOutPackagePath    :: Maybe FilePath
    , GenoconvertOptions -> Bool
_genoconvertRemoveOld       :: Bool
    , GenoconvertOptions -> PlinkPopNameMode
_genoconvertOutPlinkPopMode :: PlinkPopNameMode
    , GenoconvertOptions -> Bool
_genoconvertOnlyLatest      :: Bool
    , GenoconvertOptions -> Bool
_genoconvertOutZip          :: Bool
    }

runGenoconvert :: GenoconvertOptions -> PoseidonIO ()
runGenoconvert :: GenoconvertOptions -> PoseidonIO ()
runGenoconvert (GenoconvertOptions [GenoDataSource]
genoSources [Char]
outFormat Maybe [Char]
outPath
                Bool
removeOld PlinkPopNameMode
outPlinkPopMode Bool
onlyLatest Bool
outZip) = do
    let pacReadOpts :: PackageReadOptions
pacReadOpts = PackageReadOptions
defaultPackageReadOptions {
          _readOptIgnoreChecksums :: Bool
_readOptIgnoreChecksums  = Bool
True
        , _readOptIgnoreGeno :: Bool
_readOptIgnoreGeno       = Bool
False
        , _readOptGenoCheck :: Bool
_readOptGenoCheck        = Bool
True
        , _readOptOnlyLatest :: Bool
_readOptOnlyLatest       = Bool
onlyLatest
    }
    -- load packages
    [PoseidonPackage]
properPackages <- PackageReadOptions -> [[Char]] -> PoseidonIO [PoseidonPackage]
readPoseidonPackageCollection PackageReadOptions
pacReadOpts ([[Char]] -> PoseidonIO [PoseidonPackage])
-> [[Char]] -> PoseidonIO [PoseidonPackage]
forall a b. (a -> b) -> a -> b
$
        [GenoDataSource -> [Char]
getPacBaseDir GenoDataSource
x | x :: GenoDataSource
x@PacBaseDir {} <- [GenoDataSource]
genoSources]
    [PoseidonPackage]
pseudoPackages <- (GenotypeDataSpec -> ReaderT Env IO PoseidonPackage)
-> [GenotypeDataSpec] -> PoseidonIO [PoseidonPackage]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM GenotypeDataSpec -> ReaderT Env IO PoseidonPackage
makePseudoPackageFromGenotypeData
        [GenoDataSource -> GenotypeDataSpec
getGenoDirect GenoDataSource
x | x :: GenoDataSource
x@GenoDirect {} <- [GenoDataSource]
genoSources]

    [Char] -> PoseidonIO ()
logInfo ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Unpackaged genotype data files loaded: " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ Int -> [Char]
forall a. Show a => a -> [Char]
show ([PoseidonPackage] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [PoseidonPackage]
pseudoPackages)
    -- convert
    (PoseidonPackage -> PoseidonIO ())
-> [PoseidonPackage] -> PoseidonIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ([Char]
-> Bool
-> Maybe [Char]
-> Bool
-> PlinkPopNameMode
-> Bool
-> PoseidonPackage
-> PoseidonIO ()
convertGenoTo [Char]
outFormat Bool
False Maybe [Char]
outPath Bool
removeOld PlinkPopNameMode
outPlinkPopMode Bool
outZip) [PoseidonPackage]
properPackages
    (PoseidonPackage -> PoseidonIO ())
-> [PoseidonPackage] -> PoseidonIO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ ([Char]
-> Bool
-> Maybe [Char]
-> Bool
-> PlinkPopNameMode
-> Bool
-> PoseidonPackage
-> PoseidonIO ()
convertGenoTo [Char]
outFormat Bool
True Maybe [Char]
outPath Bool
removeOld PlinkPopNameMode
outPlinkPopMode Bool
outZip) [PoseidonPackage]
pseudoPackages

convertGenoTo :: String -> Bool -> Maybe FilePath -> Bool ->
    PlinkPopNameMode -> Bool -> PoseidonPackage -> PoseidonIO ()
convertGenoTo :: [Char]
-> Bool
-> Maybe [Char]
-> Bool
-> PlinkPopNameMode
-> Bool
-> PoseidonPackage
-> PoseidonIO ()
convertGenoTo [Char]
outFormat Bool
onlyGeno Maybe [Char]
outPath Bool
removeOld PlinkPopNameMode
outPlinkPopMode Bool
outZip PoseidonPackage
pac = do
    -- start message
    [Char] -> PoseidonIO ()
logInfo ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$
        [Char]
"Converting genotype data in "
        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ PacNameAndVersion -> [Char]
forall a. Show a => a -> [Char]
show (PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion PoseidonPackage
pac)
        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" to format "
        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
forall a. Show a => a -> [Char]
show [Char]
outFormat
        [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ if Bool
outZip then [Char]
" (gzipped):" else [Char]
":"

    -- compile new relative file names
    let outName :: [Char]
outName = PacNameAndVersion -> [Char]
forall a. HasNameAndVersion a => a -> [Char]
getPacName (PacNameAndVersion -> [Char])
-> (PoseidonPackage -> PacNameAndVersion)
-> PoseidonPackage
-> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion (PoseidonPackage -> [Char]) -> PoseidonPackage -> [Char]
forall a b. (a -> b) -> a -> b
$ PoseidonPackage
pac
    let gz :: [Char]
gz = if Bool
outZip then [Char]
"gz" else [Char]
""
    ([Char]
outIrel, [Char]
outSrel, [Char]
outGrel) <- case [Char]
outFormat of
            [Char]
"EIGENSTRAT" -> ([Char], [Char], [Char]) -> ReaderT Env IO ([Char], [Char], [Char])
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
                ([Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
".ind", [Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
".snp" [Char] -> [Char] -> [Char]
<.> [Char]
gz, [Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
".geno" [Char] -> [Char] -> [Char]
<.> [Char]
gz)
            [Char]
"PLINK" -> ([Char], [Char], [Char]) -> ReaderT Env IO ([Char], [Char], [Char])
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
                ([Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
".fam", [Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
".bim" [Char] -> [Char] -> [Char]
<.> [Char]
gz, [Char]
outName [Char] -> [Char] -> [Char]
<.> [Char]
".bed" [Char] -> [Char] -> [Char]
<.> [Char]
gz)
            [Char]
_                     -> IO ([Char], [Char], [Char])
-> ReaderT Env IO ([Char], [Char], [Char])
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ([Char], [Char], [Char])
 -> ReaderT Env IO ([Char], [Char], [Char]))
-> ([Char] -> IO ([Char], [Char], [Char]))
-> [Char]
-> ReaderT Env IO ([Char], [Char], [Char])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonException -> IO ([Char], [Char], [Char])
forall e a. Exception e => e -> IO a
throwIO (PoseidonException -> IO ([Char], [Char], [Char]))
-> ([Char] -> PoseidonException)
-> [Char]
-> IO ([Char], [Char], [Char])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> PoseidonException
PoseidonGenericException ([Char] -> ReaderT Env IO ([Char], [Char], [Char]))
-> [Char] -> ReaderT Env IO ([Char], [Char], [Char])
forall a b. (a -> b) -> a -> b
$
                [Char]
"Illegal outFormat " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
outFormat [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
                [Char]
". Only Outformats EIGENSTRAT or PLINK are allowed at the moment"

    -- compile new absolute genotype file names
    [Char]
newBaseDir <- case Maybe [Char]
outPath of
        Just [Char]
x -> do
            -- create new directory
            [Char] -> PoseidonIO ()
logInfo ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Writing to directory (will be created if missing): " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
x
            IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ Bool -> [Char] -> IO ()
createDirectoryIfMissing Bool
True ([Char] -> [Char]
dropTrailingPathSeparator [Char]
x)
            [Char] -> ReaderT Env IO [Char]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [Char]
x
        Maybe [Char]
Nothing -> [Char] -> ReaderT Env IO [Char]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char] -> ReaderT Env IO [Char])
-> [Char] -> ReaderT Env IO [Char]
forall a b. (a -> b) -> a -> b
$ PoseidonPackage -> [Char]
posPacBaseDir PoseidonPackage
pac
    let ([Char]
outGabs, [Char]
outSabs, [Char]
outIabs) = ([Char]
newBaseDir [Char] -> [Char] -> [Char]
</> [Char]
outGrel, [Char]
newBaseDir [Char] -> [Char] -> [Char]
</> [Char]
outSrel, [Char]
newBaseDir [Char] -> [Char] -> [Char]
</> [Char]
outIrel)

    -- check whether anything needs doing at all
    Bool
allExists <- [Bool] -> Bool
forall (t :: * -> *). Foldable t => t Bool -> Bool
and ([Bool] -> Bool) -> ReaderT Env IO [Bool] -> ReaderT Env IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([Char] -> ReaderT Env IO Bool)
-> [[Char]] -> ReaderT Env IO [Bool]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
mapM [Char] -> ReaderT Env IO Bool
checkFile [[Char]
outGabs, [Char]
outSabs, [Char]
outIabs]
    if Bool
allExists
    then do
        if Bool
onlyGeno
        then do
            [Char] -> PoseidonIO ()
logError ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"No files were created or overwritten for " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ PacNameAndVersion -> [Char]
forall a. Show a => a -> [Char]
show (PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion PoseidonPackage
pac)
            IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ ExitCode -> IO ()
forall a. ExitCode -> IO a
exitWith (Int -> ExitCode
ExitFailure Int
1)
        else
            [Char] -> PoseidonIO ()
logWarning ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Package already in desired file-type, skipping genotype conversion for " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
                PacNameAndVersion -> [Char]
forall a. Show a => a -> [Char]
show (PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion PoseidonPackage
pac)
    else do
        -- Convert!
        [Char] -> PoseidonIO ()
logInfo [Char]
"Processing SNPs..."
        LogA
logA <- PoseidonIO LogA
envLogAction
        UTCTime
currentTime <- IO UTCTime -> ReaderT Env IO UTCTime
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO UTCTime
getCurrentTime
        ErrorLength
errLength <- PoseidonIO ErrorLength
envErrorLength
        let eigenstratIndEntries :: [EigenstratIndEntry]
eigenstratIndEntries = JannoRows -> [EigenstratIndEntry]
jannoRows2EigenstratIndEntries (JannoRows -> [EigenstratIndEntry])
-> (PoseidonPackage -> JannoRows)
-> PoseidonPackage
-> [EigenstratIndEntry]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonPackage -> JannoRows
posPacJanno (PoseidonPackage -> [EigenstratIndEntry])
-> PoseidonPackage -> [EigenstratIndEntry]
forall a b. (a -> b) -> a -> b
$ PoseidonPackage
pac
        let zipEnding :: [Char]
zipEnding = if Bool
outZip then [Char]
".gz" else [Char]
"" -- we need this to trigger the zipping
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (
            SafeT IO () -> IO ()
forall (m :: * -> *) r.
(MonadMask m, MonadIO m) =>
SafeT m r -> m r
runSafeT (SafeT IO () -> IO ()) -> SafeT IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
eigenstratProd <- [Char]
-> GenotypeDataSpec
-> SafeT IO (Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ())
forall (m :: * -> *).
MonadSafe m =>
[Char]
-> GenotypeDataSpec
-> m (Producer (EigenstratSnpEntry, GenoLine) m ())
loadGenotypeData (PoseidonPackage -> [Char]
posPacBaseDir PoseidonPackage
pac) (PoseidonPackage -> GenotypeDataSpec
posPacGenotypeData PoseidonPackage
pac)
                let outConsumer :: Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
outConsumer = case [Char]
outFormat of
                        [Char]
"EIGENSTRAT" -> [Char]
-> [Char]
-> [Char]
-> [EigenstratIndEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall (m :: * -> *).
MonadSafe m =>
[Char]
-> [Char]
-> [Char]
-> [EigenstratIndEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) m ()
writeEigenstrat ([Char]
outGabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
zipEnding)
                                                        ([Char]
outSabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
zipEnding)
                                                        ([Char]
outIabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert")
                                                        [EigenstratIndEntry]
eigenstratIndEntries
                        [Char]
"PLINK"      -> [Char]
-> [Char]
-> [Char]
-> [PlinkFamEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall (m :: * -> *).
MonadSafe m =>
[Char]
-> [Char]
-> [Char]
-> [PlinkFamEntry]
-> Consumer (EigenstratSnpEntry, GenoLine) m ()
writePlink ([Char]
outGabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
zipEnding)
                                                   ([Char]
outSabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
zipEnding)
                                                   ([Char]
outIabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert")
                                                   ((EigenstratIndEntry -> PlinkFamEntry)
-> [EigenstratIndEntry] -> [PlinkFamEntry]
forall a b. (a -> b) -> [a] -> [b]
map (PlinkPopNameMode -> EigenstratIndEntry -> PlinkFamEntry
eigenstratInd2PlinkFam PlinkPopNameMode
outPlinkPopMode) [EigenstratIndEntry]
eigenstratIndEntries)
                        [Char]
_  -> IO () -> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall a.
IO a -> Proxy () (EigenstratSnpEntry, GenoLine) () X (SafeT IO) a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ())
-> ([Char] -> IO ())
-> [Char]
-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonException -> IO ()
forall e a. Exception e => e -> IO a
throwIO (PoseidonException -> IO ())
-> ([Char] -> PoseidonException) -> [Char] -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> PoseidonException
PoseidonGenericException ([Char] -> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ())
-> [Char] -> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall a b. (a -> b) -> a -> b
$
                            [Char]
"Illegal outFormat " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
outFormat [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
                            [Char]
". Only Outformats EIGENSTRAT or PLINK are allowed at the moment"
                Effect (SafeT IO) () -> SafeT IO ()
forall (m :: * -> *) r. Monad m => Effect m r -> m r
runEffect (Effect (SafeT IO) () -> SafeT IO ())
-> Effect (SafeT IO) () -> SafeT IO ()
forall a b. (a -> b) -> a -> b
$ Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
eigenstratProd Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
-> Proxy
     ()
     (EigenstratSnpEntry, GenoLine)
     ()
     (EigenstratSnpEntry, GenoLine)
     (SafeT IO)
     ()
-> Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> LogA
-> UTCTime
-> Proxy
     ()
     (EigenstratSnpEntry, GenoLine)
     ()
     (EigenstratSnpEntry, GenoLine)
     (SafeT IO)
     ()
forall (m :: * -> *) a.
MonadIO m =>
LogA -> UTCTime -> Pipe a a m ()
printSNPCopyProgress LogA
logA UTCTime
currentTime Producer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
-> Effect (SafeT IO) ()
forall (m :: * -> *) a' a b r c' c.
Functor m =>
Proxy a' a () b m r -> Proxy () b c' c m r -> Proxy a' a c' c m r
>-> Consumer (EigenstratSnpEntry, GenoLine) (SafeT IO) ()
outConsumer
            ) (PoseidonException -> IO ()
forall e a. Exception e => e -> IO a
throwIO (PoseidonException -> IO ())
-> (SomeException -> PoseidonException) -> SomeException -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ErrorLength -> SomeException -> PoseidonException
PoseidonGenotypeExceptionForward ErrorLength
errLength)
        -- the following will just overwrite if the file already exists, which is OK
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> IO ()
renameFile ([Char]
outGabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
zipEnding) [Char]
outGabs
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> IO ()
renameFile ([Char]
outSabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
zipEnding) [Char]
outSabs
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> IO ()
renameFile ([Char]
outIabs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
".gconvert") [Char]
outIabs
        [Char] -> PoseidonIO ()
logInfo [Char]
"Done"

    -- overwrite genotype data field in POSEIDON.yml file (using relative paths)
    Bool -> PoseidonIO () -> PoseidonIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool
onlyGeno Bool -> Bool -> Bool
|| Maybe [Char] -> Bool
forall a. Maybe a -> Bool
isJust Maybe [Char]
outPath) (PoseidonIO () -> PoseidonIO ()) -> PoseidonIO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ do
        GenotypeFileSpec
gFileSpec <- case [Char]
outFormat of
                [Char]
"EIGENSTRAT" -> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec)
-> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a b. (a -> b) -> a -> b
$
                    [Char]
-> Maybe [Char]
-> [Char]
-> Maybe [Char]
-> [Char]
-> Maybe [Char]
-> GenotypeFileSpec
GenotypeEigenstrat [Char]
outGrel Maybe [Char]
forall a. Maybe a
Nothing [Char]
outSrel Maybe [Char]
forall a. Maybe a
Nothing [Char]
outIrel Maybe [Char]
forall a. Maybe a
Nothing
                [Char]
"PLINK"      -> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec)
-> GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a b. (a -> b) -> a -> b
$
                    [Char]
-> Maybe [Char]
-> [Char]
-> Maybe [Char]
-> [Char]
-> Maybe [Char]
-> GenotypeFileSpec
GenotypePlink      [Char]
outGrel Maybe [Char]
forall a. Maybe a
Nothing [Char]
outSrel Maybe [Char]
forall a. Maybe a
Nothing [Char]
outIrel Maybe [Char]
forall a. Maybe a
Nothing
                [Char]
_  -> IO GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO GenotypeFileSpec -> ReaderT Env IO GenotypeFileSpec)
-> ([Char] -> IO GenotypeFileSpec)
-> [Char]
-> ReaderT Env IO GenotypeFileSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonException -> IO GenotypeFileSpec
forall e a. Exception e => e -> IO a
throwIO (PoseidonException -> IO GenotypeFileSpec)
-> ([Char] -> PoseidonException) -> [Char] -> IO GenotypeFileSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> PoseidonException
PoseidonGenericException ([Char] -> ReaderT Env IO GenotypeFileSpec)
-> [Char] -> ReaderT Env IO GenotypeFileSpec
forall a b. (a -> b) -> a -> b
$
                    [Char]
"Illegal outFormat " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
outFormat [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++
                    [Char]
". Only Outformats EIGENSTRAT or PLINK are allowed at the moment"
        let newGenotypeData :: GenotypeDataSpec
newGenotypeData = GenotypeFileSpec -> Maybe SNPSetSpec -> GenotypeDataSpec
GenotypeDataSpec GenotypeFileSpec
gFileSpec (GenotypeDataSpec -> Maybe SNPSetSpec
genotypeSnpSet (GenotypeDataSpec -> Maybe SNPSetSpec)
-> (PoseidonPackage -> GenotypeDataSpec)
-> PoseidonPackage
-> Maybe SNPSetSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonPackage -> GenotypeDataSpec
posPacGenotypeData (PoseidonPackage -> Maybe SNPSetSpec)
-> PoseidonPackage -> Maybe SNPSetSpec
forall a b. (a -> b) -> a -> b
$ PoseidonPackage
pac)
            newPac :: PoseidonPackage
newPac = PoseidonPackage
pac { posPacGenotypeData :: GenotypeDataSpec
posPacGenotypeData = GenotypeDataSpec
newGenotypeData }
        [Char] -> PoseidonIO ()
logInfo ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Adjusting POSEIDON.yml for " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ PacNameAndVersion -> [Char]
forall a. Show a => a -> [Char]
show (PoseidonPackage -> PacNameAndVersion
posPacNameAndVersion PoseidonPackage
pac)
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ()) -> IO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ PoseidonPackage -> IO ()
writePoseidonPackage PoseidonPackage
newPac
        -- delete now replaced input genotype data
    Bool -> PoseidonIO () -> PoseidonIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
removeOld (PoseidonIO () -> PoseidonIO ()) -> PoseidonIO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ do
        let oldBaseDir :: [Char]
oldBaseDir = PoseidonPackage -> [Char]
posPacBaseDir PoseidonPackage
pac
        [[Char]]
oldGenoFiles <- case GenotypeDataSpec -> GenotypeFileSpec
genotypeFileSpec (GenotypeDataSpec -> GenotypeFileSpec)
-> (PoseidonPackage -> GenotypeDataSpec)
-> PoseidonPackage
-> GenotypeFileSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PoseidonPackage -> GenotypeDataSpec
posPacGenotypeData (PoseidonPackage -> GenotypeFileSpec)
-> PoseidonPackage -> GenotypeFileSpec
forall a b. (a -> b) -> a -> b
$ PoseidonPackage
pac of
                GenotypeEigenstrat [Char]
g Maybe [Char]
_ [Char]
s Maybe [Char]
_ [Char]
i Maybe [Char]
_ -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
g, [Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
s, [Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
i]
                GenotypePlink      [Char]
g Maybe [Char]
_ [Char]
s Maybe [Char]
_ [Char]
i Maybe [Char]
_ -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
g, [Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
s, [Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
i]
                GenotypeVCF        [Char]
g Maybe [Char]
_         -> [[Char]] -> ReaderT Env IO [[Char]]
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [[Char]
oldBaseDir [Char] -> [Char] -> [Char]
</> [Char]
g]
        let newGenoFiles :: [[Char]]
newGenoFiles = [[Char]
outGabs, [Char]
outSabs, [Char]
outIabs]
        let filesToDelete :: [[Char]]
filesToDelete = [[Char]]
oldGenoFiles [[Char]] -> [[Char]] -> [[Char]]
forall a. Eq a => [a] -> [a] -> [a]
\\ [[Char]]
newGenoFiles
        IO () -> PoseidonIO ()
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> PoseidonIO ())
-> ([[Char]] -> IO ()) -> [[Char]] -> PoseidonIO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> IO ()) -> [[Char]] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ [Char] -> IO ()
removeFile ([[Char]] -> PoseidonIO ()) -> [[Char]] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [[Char]]
filesToDelete
  where
    checkFile :: FilePath -> PoseidonIO Bool
    checkFile :: [Char] -> ReaderT Env IO Bool
checkFile [Char]
fn = do
        Bool
fe <- IO Bool -> ReaderT Env IO Bool
forall a. IO a -> ReaderT Env IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Bool -> ReaderT Env IO Bool) -> IO Bool -> ReaderT Env IO Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> IO Bool
doesFileExist [Char]
fn
        Bool -> PoseidonIO () -> PoseidonIO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
fe (PoseidonIO () -> PoseidonIO ()) -> PoseidonIO () -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char] -> PoseidonIO ()
logWarning ([Char] -> PoseidonIO ()) -> [Char] -> PoseidonIO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"File " [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
fn [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" exists"
        Bool -> ReaderT Env IO Bool
forall a. a -> ReaderT Env IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
fe