diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -2,7 +2,14 @@
 # Changelog for ELynx
 
 
-## Version 0.3.1; in development
+## Version 0.3.2; in development
+
+
+## Version 0.3.1
+
+-   Use Attoparsec.
+-   Use ByteString consistently.
+-   Remove elynx-tools dependency from libaries.
 
 
 ## Version 0.3.0
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
 
 # The ELynx Suite
 
-Version: 0.3.0.
+Version: 0.3.1.
 Reproducible evolution made easy.
 
 <p align="center"><img src="https://travis-ci.org/dschrempf/elynx.svg?branch=master"/></p>
@@ -90,9 +90,9 @@
 
     slynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] 
                  [-f|--force] COMMAND
@@ -136,9 +136,9 @@
 
     slynx concatenate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx concatenate (-a|--alphabet NAME) INPUT-FILE
       Concatenate sequences found in input files.
@@ -157,9 +157,9 @@
 
     slynx examine --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx examine (-a|--alphabet NAME) INPUT-FILE [--per-site]
       Examine sequences. If data is a multi sequence alignment, additionally analyze columns.
@@ -179,9 +179,9 @@
 
     slynx filter-rows --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx filter-rows (-a|--alphabet NAME) INPUT-FILE [--longer-than LENGTH] 
                              [--shorter-than LENGTH] [--standard-characters]
@@ -202,9 +202,9 @@
 
     slynx filter-columns --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx filter-columns (-a|--alphabet NAME) INPUT-FILE 
                                 [--standard-chars DOUBLE]
@@ -226,9 +226,9 @@
 
     slynx simulate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx simulate (-t|--tree-file Name) [-s|--substitution-model MODEL] 
                           [-m|--mixture-model MODEL] [-e|--edm-file NAME] 
@@ -305,9 +305,9 @@
 
     slynx sub-sample --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx sub-sample (-a|--alphabet NAME) INPUT-FILE
                             (-n|--number-of-sites INT)
@@ -335,9 +335,9 @@
 
     slynx translate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: slynx translate (-a|--alphabet NAME) INPUT-FILE (-r|--reading-frame INT)
                            (-u|--universal-code CODE)
@@ -360,9 +360,9 @@
 
     tlynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] 
                  [-f|--force] COMMAND
@@ -399,9 +399,9 @@
 
     tlynx compare --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx compare [-n|--normalize] [-b|--bipartitions] [-t|--intersect] 
                          [-f|--newick-format FORMAT] NAMES
@@ -428,9 +428,9 @@
 
     tlynx examine --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx examine INPUT-FILE [-f|--newick-format FORMAT]
       Compute summary statistics of phylogenetic trees.
@@ -452,9 +452,9 @@
 
     tlynx simulate --help
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: tlynx simulate [-t|--nTrees INT] [-n|--nLeaves INT] [-H|--height DOUBLE] 
                           [-M|--condition-on-mrca] [-l|--lambda DOUBLE] 
@@ -491,9 +491,9 @@
 
     elynx --help | head -n -16
 
-    ELynx Suite version 0.3.0.
+    ELynx Suite version 0.3.1.
     Developed by Dominik Schrempf.
-    Compiled on July 30, 2020, at 12:40 pm, UTC.
+    Compiled on August 3, 2020, at 12:12 pm, UTC.
     
     Usage: elynx COMMAND
       Validate and redo past ELynx analyses
diff --git a/slynx.cabal b/slynx.cabal
--- a/slynx.cabal
+++ b/slynx.cabal
@@ -4,10 +4,10 @@
 --
 -- see: https://github.com/sol/hpack
 --
--- hash: 826b98c0606c81f3576251bedb9ae6aa528a2afeb1a782a01a6f17578ce698af
+-- hash: 286f8b4edbcbe74a920bfa98bfeb769b685b7591ba79d26c1a024faa2889e888
 
 name:           slynx
-version:        0.3.0
+version:        0.3.1
 synopsis:       Handle molecular sequences
 description:    Examine, modify, and simulate molecular sequences in a reproducible way. Please see the README on GitHub at <https://github.com/dschrempf/elynx>.
 category:       Bioinformatics
@@ -54,6 +54,7 @@
   ghc-options: -Wall -fllvm
   build-depends:
       async
+    , attoparsec
     , base >=4.7 && <5
     , bytestring
     , containers
@@ -62,11 +63,9 @@
     , elynx-tools
     , elynx-tree
     , hmatrix
-    , megaparsec
     , monad-logger
     , mwc-random
     , optparse-applicative
-    , scientific
     , text
     , transformers
     , vector
@@ -81,7 +80,5 @@
   ghc-options: -Wall -fllvm -threaded -rtsopts -with-rtsopts=-N
   build-depends:
       base >=4.7 && <5
-    , elynx-seq
-    , elynx-tools
     , slynx
   default-language: Haskell2010
diff --git a/src/SLynx/Examine/Examine.hs b/src/SLynx/Examine/Examine.hs
--- a/src/SLynx/Examine/Examine.hs
+++ b/src/SLynx/Examine/Examine.hs
@@ -20,7 +20,7 @@
 
 import Control.Monad.Logger
 import Control.Monad.Trans.Reader (ask)
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Lazy.Char8 as BL
 import qualified Data.Set as S
 import qualified ELynx.Data.Alphabet.Alphabet as A
 import qualified ELynx.Data.Alphabet.Character as C
@@ -31,53 +31,53 @@
 import SLynx.Tools
 import Text.Printf
 
-pRow :: String -> String -> L.ByteString
+pRow :: String -> String -> BL.ByteString
 pRow name val = alignLeft 50 n <> alignRight 10 v
   where
-    n = L.pack name
-    v = L.pack val
+    n = BL.pack name
+    v = BL.pack val
 
-examineAlignment :: Bool -> M.Alignment -> L.ByteString
+examineAlignment :: Bool -> M.Alignment -> BL.ByteString
 examineAlignment perSiteFlag a =
-  L.unlines
-    [ L.pack
+  BL.unlines
+    [ BL.pack
         "Sequences have equal length (multi sequence alignment, or single sequence).",
       pRow "Total number of columns in alignment:" $ show (M.length a),
       pRow "Number of columns without gaps:" $ show (M.length aNoGaps),
       pRow "Number of columns with standard characters only:" $
         show (M.length aOnlyStd),
-      L.empty,
+      BL.empty,
       pRow "Total number of characters:" $ show nTot,
       pRow "Standard (i.e., not extended IUPAC) characters:" $
         show (nTot - nIUPAC - nGaps - nUnknowns),
       pRow "Extended IUPAC characters:" $ show nIUPAC,
       pRow "Gaps:" $ show nGaps,
       pRow "Unknowns:" $ show nUnknowns,
-      L.empty,
+      BL.empty,
       pRow "Percentage of standard characters:" $
         printf "%2.2f" (100.0 - percentIUPAC - percentGaps - percentUnknowns),
       pRow "Percentage of extended IUPAC characters:" $
         printf "%2.2f" percentIUPAC,
       pRow "Percentage of gaps:" $ printf "%2.2f" percentGaps,
       pRow "Percentage of unknowns:" $ printf "%2.2f" percentUnknowns,
-      L.empty,
-      L.pack "Distribution of characters:",
+      BL.empty,
+      BL.pack "Distribution of characters:",
       -- Holy crap.
-      L.pack $
+      BL.pack $
         concatMap ((: "     ") . C.toChar) $
           S.toList $
             A.std $
               A.alphabetSpec $
                 M.alphabet a,
-      L.pack $ unwords $ map (printf "%.3f") charFreqs,
-      L.empty,
-      L.pack "Mean effective number of states (measured using entropy):",
+      BL.pack $ unwords $ map (printf "%.3f") charFreqs,
+      BL.empty,
+      BL.pack "Mean effective number of states (measured using entropy):",
       pRow "Across whole alignment:" $ printf "%.3f" kEffMean,
       pRow "Across columns without gaps:" $ printf "%.3f" kEffMeanNoGaps,
       pRow "Across columns without extended IUPAC characters:" $
         printf "%.3f" kEffMeanOnlyStd,
-      L.empty,
-      L.pack "Mean effective number of states (measured using homoplasy):",
+      BL.empty,
+      BL.pack "Mean effective number of states (measured using homoplasy):",
       pRow "Across whole alignment:" $ printf "%.3f" kEffMeanHomo,
       pRow "Across columns without gaps:" $ printf "%.3f" kEffMeanNoGapsHomo,
       pRow "Across columns without extended IUPAC characters:" $
@@ -113,17 +113,17 @@
     perSiteBS =
       if perSiteFlag
         then
-          L.unlines
-            [ L.pack "Effective number of used states per site:",
-              L.pack . show $ kEffs
+          BL.unlines
+            [ BL.pack "Effective number of used states per site:",
+              BL.pack . show $ kEffs
             ]
-        else L.empty
+        else BL.empty
 
-examine :: Bool -> [Seq.Sequence] -> L.ByteString
+examine :: Bool -> [Seq.Sequence] -> BL.ByteString
 examine perSiteFlag ss =
   Seq.summarizeSequences ss <> case M.fromSequences ss of
-    Left _ -> L.empty
-    Right a -> L.pack "\n" <> examineAlignment perSiteFlag a
+    Left _ -> BL.empty
+    Right a -> BL.pack "\n" <> examineAlignment perSiteFlag a
 
 -- | Examine sequences.
 examineCmd :: ELynx ExamineArguments ()
diff --git a/src/SLynx/Filter/Filter.hs b/src/SLynx/Filter/Filter.hs
--- a/src/SLynx/Filter/Filter.hs
+++ b/src/SLynx/Filter/Filter.hs
@@ -21,7 +21,7 @@
 import Control.Monad (when)
 import Control.Monad.Logger
 import Control.Monad.Trans.Reader (ask)
-import qualified Data.ByteString.Lazy.Char8 as L
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.Maybe (fromMaybe)
 import qualified Data.Text as T
 import qualified ELynx.Data.Sequence.Alignment as M
@@ -31,7 +31,7 @@
 import SLynx.Filter.Options
 import SLynx.Tools
 
-filterRows :: Maybe Int -> Maybe Int -> Bool -> [S.Sequence] -> L.ByteString
+filterRows :: Maybe Int -> Maybe Int -> Bool -> [S.Sequence] -> BL.ByteString
 filterRows ml ms std ss = sequencesToFasta $ compose filters ss
   where
     filters' =
@@ -62,7 +62,7 @@
   let result = filterRows long short std ss
   out "filtered sequences" result ".fasta"
 
-filterCols :: Maybe Double -> [S.Sequence] -> L.ByteString
+filterCols :: Maybe Double -> [S.Sequence] -> BL.ByteString
 filterCols ms ss = sequencesToFasta . M.toSequences $ compose filters a
   where
     a = either error id (M.fromSequences ss)
diff --git a/src/SLynx/Simulate/PhyloModel.hs b/src/SLynx/Simulate/PhyloModel.hs
--- a/src/SLynx/Simulate/PhyloModel.hs
+++ b/src/SLynx/Simulate/PhyloModel.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE OverloadedStrings #-}
+
 -- |
 -- Module      :  SLynx.Simulate.PhyloModel
 -- Description :  Parse and interpret the model string
@@ -14,14 +16,13 @@
   )
 where
 
+import Control.Applicative
 import Control.Monad (when)
-import qualified Data.ByteString.Lazy.Char8 as L
+import Data.Attoparsec.ByteString.Char8
+import qualified Data.ByteString.Char8 as BS
 import Data.Either (rights)
 import Data.List.NonEmpty (fromList)
 import Data.Maybe
-import Data.Scientific hiding (scientific)
-import Data.Void
-import Data.Word (Word8)
 import ELynx.Data.MarkovProcess.AminoAcid
 import ELynx.Data.MarkovProcess.CXXModels
 import qualified ELynx.Data.MarkovProcess.MixtureModel as M
@@ -38,15 +39,7 @@
     size,
     vector,
   )
-import Text.Megaparsec
-import Text.Megaparsec.Byte
-import Text.Megaparsec.Byte.Lexer
 
-type Parser = Parsec Void L.ByteString
-
-bs :: String -> L.ByteString
-bs = L.pack
-
 nNuc :: Int
 -- nNuc = length (alphabet :: [Nucleotide])
 nNuc = 4
@@ -56,53 +49,42 @@
 nAA = 20
 
 -- Model parameters between square brackets.
-paramsStart :: Word8
-paramsStart = c2w '['
+paramsStart :: Char
+paramsStart = '['
 
-paramsEnd :: Word8
-paramsEnd = c2w ']'
+paramsEnd :: Char
+paramsEnd = ']'
 
 -- Stationary distribution between curly brackets.
-sdStart :: Word8
-sdStart = c2w '{'
+sdStart :: Char
+sdStart = '{'
 
-sdEnd :: Word8
-sdEnd = c2w '}'
+sdEnd :: Char
+sdEnd = '}'
 
 -- Mixture model components between round brackets.
-mmStart :: Word8
-mmStart = c2w '('
+mmStart :: Char
+mmStart = '('
 
-mmEnd :: Word8
-mmEnd = c2w ')'
+mmEnd :: Char
+mmEnd = ')'
 
-separator :: Word8
-separator = c2w ','
+separator :: Char
+separator = ','
 
 name :: Parser String
 name =
-  L.unpack
-    <$> takeWhile1P
-      (Just "Model name")
-      ( `notElem` [paramsStart, paramsEnd, sdStart, sdEnd, mmStart, mmEnd, separator]
-      )
+  BS.unpack
+    <$> takeWhile1 (notInClass [paramsStart, paramsEnd, sdStart, sdEnd, mmStart, mmEnd, separator])
 
 params :: Parser [Double]
-params =
-  map toRealFloat
-    <$> between
-      (char paramsStart)
-      (char paramsEnd)
-      (sepBy1 scientific (char separator))
+params = char paramsStart *> double `sepBy1` char separator <* char paramsEnd
 
 stationaryDistribution :: Parser StationaryDistribution
 stationaryDistribution = do
-  f <-
-    vector . map toRealFloat
-      <$> between
-        (char sdStart)
-        (char sdEnd)
-        (sepBy1 scientific (char separator))
+  _ <- char sdStart
+  f <- vector <$> double `sepBy1` char separator
+  _ <- char sdEnd
   if nearlyEq (norm_1 f) 1.0
     then return f
     else
@@ -172,7 +154,7 @@
 
 edmModel :: [EDMComponent] -> Maybe [M.Weight] -> Parser M.MixtureModel
 edmModel cs mws = do
-  _ <- chunk (bs "EDM")
+  _ <- string "EDM"
   _ <- char mmStart
   n <- name
   mps <- optional params
@@ -192,13 +174,13 @@
 
 cxxModel :: Maybe [M.Weight] -> Parser M.MixtureModel
 cxxModel mws = do
-  _ <- char (c2w 'C')
+  _ <- char 'C'
   n <- decimal :: Parser Int
   return $ cxx n mws
 
 standardMixtureModel :: [M.Weight] -> Parser M.MixtureModel
 standardMixtureModel ws = do
-  _ <- chunk (bs "MIXTURE")
+  _ <- string "MIXTURE"
   _ <- char mmStart
   sms <- parseSubstitutionModel `sepBy1` char separator
   _ <- char mmEnd
@@ -233,7 +215,6 @@
   Right $
     P.SubstitutionModel $
       parseStringWith
-        "Substitution model string"
         parseSubstitutionModel
         s
 getPhyloModel (Just _) Nothing (Just _) _ =
@@ -245,6 +226,5 @@
   Right $
     P.MixtureModel $
       parseStringWith
-        "Mixture model string"
         (mixtureModel mcs mws)
         m
diff --git a/src/SLynx/Simulate/Simulate.hs b/src/SLynx/Simulate/Simulate.hs
--- a/src/SLynx/Simulate/Simulate.hs
+++ b/src/SLynx/Simulate/Simulate.hs
@@ -28,8 +28,8 @@
 import Control.Monad.Logger
 import Control.Monad.Trans.Class
 import Control.Monad.Trans.Reader (ask)
-import qualified Data.ByteString.Lazy as L
-import qualified Data.ByteString.Lazy.Char8 as LC
+import qualified Data.ByteString.Builder as BB
+import qualified Data.ByteString.Lazy.Char8 as BL
 import Data.List.NonEmpty (toList)
 import Data.Maybe
 import qualified Data.Set as Set
@@ -48,9 +48,7 @@
   )
 import ELynx.Data.Tree
 import ELynx.Export.Sequence.Fasta
-import ELynx.Import.MarkovProcess.EDMModelPhylobayes hiding
-  ( Parser,
-  )
+import ELynx.Import.MarkovProcess.EDMModelPhylobayes
 import ELynx.Import.MarkovProcess.SiteprofilesPhylobayes
 import ELynx.Import.Tree.Newick
 import ELynx.Simulate.MarkovProcessAlongTree
@@ -62,6 +60,7 @@
 import SLynx.Simulate.Options
 import SLynx.Simulate.PhyloModel
 import System.Random.MWC
+import Text.Printf
 
 -- Simulate a 'Alignment' for a given phylogenetic model,
 -- phylogenetic tree, and alignment length.
@@ -110,9 +109,9 @@
   return $ either error id $ A.fromSequences sequences
 
 -- Summarize EDM components; line to be printed to screen or log.
-summarizeEDMComponents :: [EDMComponent] -> L.ByteString
+summarizeEDMComponents :: [EDMComponent] -> BL.ByteString
 summarizeEDMComponents cs =
-  LC.pack $
+  BL.pack $
     "Empiricial distribution mixture model with "
       ++ show (length cs)
       ++ " components."
@@ -128,8 +127,88 @@
       $(logInfo)
         "No output file provided; omit writing machine-readable phylogenetic model."
     Just _ ->
-      out "model definition (machine readable)" (bShow m <> "\n") ".model.gz"
+      out "model definition (machine readable)" (BL.pack (show m) <> "\n") ".model.gz"
 
+pretty :: BranchLength -> String
+pretty = printf "%.5f"
+
+prettyRow :: String -> String -> BL.ByteString
+prettyRow name val = alignLeft 33 n <> alignRight 8 v
+  where
+    n = BL.pack name
+    v = BL.pack val
+
+-- | Examine branches of a tree.
+summarizeBranchLengths :: Measurable e => Tree e a -> BL.ByteString
+summarizeBranchLengths t =
+  BL.intercalate
+    "\n"
+    [ prettyRow "Origin height: " $ pretty h,
+      prettyRow "Average distance origin to leaves: " $ pretty h',
+      prettyRow "Total branch length: " $ pretty b
+    ]
+  where
+    n = length $ leaves t
+    h = height t
+    h' = sum (distancesOriginLeaves t) / fromIntegral n
+    b = totalBranchLength t
+
+-- Summarize a substitution model; lines to be printed to screen or log.
+summarizeSM :: SM.SubstitutionModel -> [BL.ByteString]
+summarizeSM sm =
+  map BL.pack $
+    (show (SM.alphabet sm) ++ " substitution model: " ++ SM.name sm ++ ".") :
+    ["Parameters: " ++ show (SM.params sm) ++ "." | not (null (SM.params sm))]
+      ++ case SM.alphabet sm of
+        DNA ->
+          [ "Stationary distribution: "
+              ++ dispv precision (SM.stationaryDistribution sm)
+              ++ ".",
+            "Exchangeability matrix:\n"
+              ++ dispmi 2 precision (SM.exchangeabilityMatrix sm)
+              ++ ".",
+            "Scale: " ++ show (roundN precision $ SM.totalRate sm) ++ "."
+          ]
+        Protein ->
+          [ "Stationary distribution: "
+              ++ dispv precision (SM.stationaryDistribution sm)
+              ++ ".",
+            "Scale: " ++ show (roundN precision $ SM.totalRate sm) ++ "."
+          ]
+        _ ->
+          error
+            "Extended character sets are not supported with substitution models."
+
+-- Summarize a mixture model component; lines to be printed to screen or log.
+summarizeMMComponent :: M.Component -> [BL.ByteString]
+summarizeMMComponent c =
+  BL.pack "Weight: "
+    <> (BB.toLazyByteString . BB.doubleDec $ M.weight c) :
+  summarizeSM (M.substModel c)
+
+-- Summarize a mixture model; lines to be printed to screen or log.
+summarizeMM :: M.MixtureModel -> [BL.ByteString]
+summarizeMM m =
+  [ BL.pack $ "Mixture model: " ++ M.name m ++ ".",
+    BL.pack $ "Number of components: " ++ show n ++ "."
+  ]
+    ++ detail
+  where
+    n = length $ M.components m
+    detail =
+      if n <= 100
+        then
+          concat
+            [ BL.pack ("Component " ++ show i ++ ":") : summarizeMMComponent c
+              | (i, c) <- zip [1 :: Int ..] (toList $ M.components m)
+            ]
+        else []
+
+-- Summarize a phylogenetic model; lines to be printed to screen or log.
+summarizePM :: P.PhyloModel -> [BL.ByteString]
+summarizePM (P.MixtureModel mm) = summarizeMM mm
+summarizePM (P.SubstitutionModel sm) = summarizeSM sm
+
 -- | Simulate sequences.
 simulateCmd :: ELynx SimulateArguments ()
 simulateCmd = do
@@ -139,6 +218,7 @@
   $(logInfo) $ T.pack $ "Read tree from file '" ++ treeFile ++ "'."
   tree <- liftIO $ parseFileWith (newick Standard) treeFile
   let t' = either error id $ phyloToLengthTree tree
+  $(logInfo) $ T.pack $ "Number of leaves: " ++ show (length $ leaves t')
   $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $ summarizeBranchLengths t'
   let edmFile = argsEDMFile l
   let sProfileFiles = argsSiteprofilesFiles l
@@ -185,21 +265,21 @@
       $(logInfo) $
         LT.toStrict $
           LT.decodeUtf8 $
-            LC.unlines $
-              P.summarize
+            BL.unlines $
+              summarizePM
                 phyloModel'
       return phyloModel'
     Just (n, alpha) -> do
       $(logInfo) $
         LT.toStrict $
           LT.decodeUtf8 $
-            LC.intercalate "\n" $
-              P.summarize phyloModel'
+            BL.intercalate "\n" $
+              summarizePM phyloModel'
       $(logInfo) ""
       $(logInfo) $
         LT.toStrict $
           LT.decodeUtf8 $
-            LC.intercalate "\n" $
+            BL.intercalate "\n" $
               summarizeGammaRateHeterogeneity n alpha
       return $ expand n alpha phyloModel'
   -- -- XXX: Do not report possibly huge empirical distribution mixture models
diff --git a/src/SLynx/Tools.hs b/src/SLynx/Tools.hs
--- a/src/SLynx/Tools.hs
+++ b/src/SLynx/Tools.hs
@@ -26,9 +26,7 @@
 import qualified Data.Text as T
 import ELynx.Data.Alphabet.Alphabet
 import ELynx.Data.Sequence.Sequence
-import ELynx.Import.Sequence.Fasta hiding
-  ( Parser,
-  )
+import ELynx.Import.Sequence.Fasta
 import ELynx.Tools
 import Options.Applicative
 
