diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,10 +1,10 @@
 
 # Table of Contents
 
-1.  [Changelog for ELynx](#org9916021)
+1.  [Changelog for ELynx](#org263dcac)
 
 
-<a id="org9916021"></a>
+<a id="org263dcac"></a>
 
 # Changelog for ELynx
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,33 +2,33 @@
 
 # The ELynx Suite
 
-Version: 0.0.1.
+Version: 0.1.0.
 Reproducible evolution made easy.
 
 The ELynx Suite is a Haskell library and a tool set for computational biology.
 The goal of the ELynx Suite is reproducible research. Evolutionary sequences and
 phylogenetic trees can be read, viewed, modified and simulated. Exact
 specification of all options is necessary, and nothing is assumed about the data
-(e.g., the type of code). The command line with all arguments is consistently,
-and automatically logged. The work overhead in the beginning usually pays off in
-the end.
+(e.g., the type of the genetic code). The command line with all arguments is
+consistently, and automatically logged. The work overhead in the beginning
+usually pays off in the end.
 
 The Elynx Suite consists of three library packages and two executables providing
 a range of sub commands.
 
 The library packages are:
 
--   **elynx-seq:** Handle evolutionary sequences and multi sequence alignments;
--   **elynx-tree:** Handle phylogenetic trees;
--   **elynx-tools:** Tools for the provided executables;
+-   **elynx-seq:** Handle evolutionary sequences and multi sequence alignments.
+-   **elynx-tree:** Handle phylogenetic trees.
+-   **elynx-tools:** Tools for the provided executables.
 
 The executables are:
 
--   **SLynx:** Analyze, modify, and simulate evolutionary sequences (FASTA format);
--   **TLynx:** Analyze, modify, and simulate phylogenetic trees (Newick format).
+-   **slynx:** Analyze, modify, and simulate evolutionary sequences (FASTA format).
+-   **tlynx:** Analyze, modify, and simulate phylogenetic trees (Newick format).
 
-**ELynx is still under development. We happily receive comments, ideas, feature
-requests, or pull requests!**
+**ELynx is actively developed. We happily receive comments, ideas, feature
+requests, and pull requests!**
 
 
 # Installation
@@ -57,8 +57,8 @@
     
         stack install
     
-    The binaries are installed into `~/.local/bin/` which has to be added [PATH](https://en.wikipedia.org/wiki/PATH_(variable)).
-    Then, they can be used directly.
+    The binaries are installed into `~/.local/bin/` which has to be added to the
+    [PATH](https://en.wikipedia.org/wiki/PATH_(variable)) environment variable. Then, they can be used directly.
 
 
 # SLynx
@@ -67,8 +67,8 @@
 
     slynx --help
 
-    ELynx Suite version 0.5.1. Developed by Dominik Schrempf. Compiled on September
-    9, 2019, at 10:48 am, UTC.
+    ELynx Suite version 0.1.0. Developed by Dominik Schrempf. Compiled on January
+    30, 2020, at 09:18 am, UTC.
     
     Usage: slynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] COMMAND
       Analyze, and simulate multi sequence alignments.
@@ -82,17 +82,14 @@
                                Specify base name of output file
     
     Available commands:
-      concatenate              
-      examine                  If data is a multi sequence alignment, additionally
-                               analyze columns.
-      filter-rows              
-      filter-columns           
-      simulate                 
-      sub-sample               Create a given number of multi sequence alignments,
-                               each of which containing a given number of random
-                               sites drawn from the original multi sequence
-                               alignment.
-      translate                
+      concatenate              Concatenate sequences found in input files.
+      examine                  Examine sequences. If data is a multi sequence
+                               alignment, additionally analyze columns.
+      filter-rows              Filter rows (or sequences) found in input files.
+      filter-columns           Filter columns of multi-sequence alignments.
+      simulate                 Simulate multi sequence alignments.
+      sub-sample               Sub-sample columns from multi sequence alignments.
+      translate                Translate from DNA to Protein or DNAX to ProteinX.
     
     File formats:
       - FASTA
@@ -106,15 +103,20 @@
       - ProteinS (amino acids; including gaps, and translation stops)
       - ProteinI (amino acids; including gaps, translation stops, and IUPAC codes)
     
-    The ELynx Suite.
+    The ELynx Suite
+    ---------------
     A Haskell library and a tool set for computational biology. The goal of the
     ELynx Suite is reproducible research. Evolutionary sequences and phylogenetic
     trees can be read, viewed, modified and simulated. Exact specification of all
     options is necessary, and nothing is assumed about the data (e.g., the type of
     code). The command line with all arguments is consistently, and automatically
-    logged. The work overhead in the beginning usually pays off in the end.
+    logged.
+    
     slynx     Analyze, modify, and simulate evolutionary sequences.
     tlynx     Analyze, modify, and simulate phylogenetic trees.
+    
+    Get help for specific commands:
+      slynx examine --help
 
 
 ## Concatenate
@@ -123,9 +125,8 @@
 
     slynx concatenate --help
 
-    Concatenate sequences found in input files.
-    
     Usage: slynx concatenate (-a|--alphabet NAME) INPUT-FILE
+      Concatenate sequences found in input files.
     
     Available options:
       -a,--alphabet NAME       Specify alphabet type NAME
@@ -139,10 +140,9 @@
 
     slynx examine --help
 
-    Examine sequences.
-    
     Usage: slynx examine (-a|--alphabet NAME) [INPUT-FILE] [--per-site]
-      If data is a multi sequence alignment, additionally analyze columns.
+      Examine sequences. If data is a multi sequence alignment, additionally analyze
+      columns.
     
     Available options:
       -a,--alphabet NAME       Specify alphabet type NAME
@@ -157,26 +157,27 @@
 
     slynx filter-rows --help
 
-    Filter rows (or sequences) found in input files.
-    
     Usage: slynx filter-rows (-a|--alphabet NAME) [INPUT-FILE]
                              [--longer-than LENGTH] [--shorter-than LENGTH]
+                             [--standard-characters]
+      Filter rows (or sequences) found in input files.
     
     Available options:
       -a,--alphabet NAME       Specify alphabet type NAME
       INPUT-FILE               Read sequences from INPUT-FILE
       --longer-than LENGTH     Only keep sequences longer than LENGTH
       --shorter-than LENGTH    Only keep sequences shorter than LENGTH
+      --standard-characters    Only keep sequences containing at least one standard
+                               (i.e., non-IUPAC) character
       -h,--help                Show this help text
 
 Filter columns of multi sequence alignments with `filter-columns`.
 
     slynx filter-columns --help
 
-    Filter columns of multi-sequence alignments.
-    
     Usage: slynx filter-columns (-a|--alphabet NAME) [INPUT-FILE]
                                 [--standard-chars DOUBLE]
+      Filter columns of multi-sequence alignments.
     
     Available options:
       -a,--alphabet NAME       Specify alphabet type NAME
@@ -192,13 +193,13 @@
 
     slynx simulate --help
 
-    Simulate multi sequence alignments.
-    
     Usage: slynx simulate (-t|--tree-file Name) [-s|--substitution-model MODEL]
                           [-m|--mixture-model MODEL] [-e|--edm-file NAME]
+                          [-p|--siteprofile-files NAMES]
                           [-w|--mixture-model-weights "[DOUBLE,DOUBLE,...]"]
                           [-g|--gamma-rate-heterogeneity "(NCAT,SHAPE)"]
                           (-l|--length NUMBER) [-S|--seed [INT]]
+      Simulate multi sequence alignments.
     
     Available options:
       -t,--tree-file Name      Read trees from file NAME
@@ -210,6 +211,8 @@
                                are shown below (mutually exclusive with -s option)
       -e,--edm-file NAME       Empirical distribution model file NAME in Phylobayes
                                format
+      -p,--siteprofile-files NAMES
+                               File names of site profiles in Phylobayes format
       -w,--mixture-model-weights "[DOUBLE,DOUBLE,...]"
                                Weights of mixture model components
       -g,--gamma-rate-heterogeneity "(NCAT,SHAPE)"
@@ -257,8 +260,7 @@
     Usage: slynx sub-sample (-a|--alphabet NAME) [INPUT-FILE]
                             (-n|--number-of-sites INT)
                             (-m|--number-of-alignments INT) [-S|--seed [INT]]
-      Create a given number of multi sequence alignments, each of which containing a
-      given number of random sites drawn from the original multi sequence alignment.
+      Sub-sample columns from multi sequence alignments.
     
     Available options:
       -a,--alphabet NAME       Specify alphabet type NAME
@@ -269,6 +271,9 @@
       -S,--seed [INT]          Seed for random number generator; list of 32 bit
                                integers with up to 256 elements (default: random)
       -h,--help                Show this help text
+    
+    Create a given number of multi sequence alignments, each of which contains a
+    given number of random sites drawn from the original multi sequence alignment.
 
 
 ## Translate
@@ -277,10 +282,9 @@
 
     slynx translate --help
 
-    Translate from DNA to Protein or DNAX to ProteinX.
-    
     Usage: slynx translate (-a|--alphabet NAME) [INPUT-FILE]
                            (-r|--reading-frame INT) (-u|--universal-code CODE)
+      Translate from DNA to Protein or DNAX to ProteinX.
     
     Available options:
       -a,--alphabet NAME       Specify alphabet type NAME
@@ -297,8 +301,8 @@
 
     tlynx --help
 
-    ELynx Suite version 0.5.1. Developed by Dominik Schrempf. Compiled on September
-    9, 2019, at 10:48 am, UTC.
+    ELynx Suite version 0.1.0. Developed by Dominik Schrempf. Compiled on January
+    30, 2020, at 09:18 am, UTC.
     
     Usage: tlynx [-v|--verbosity VALUE] [-o|--output-file-basename NAME] COMMAND
       Compare, examine, and simulate phylogenetic trees.
@@ -312,26 +316,34 @@
                                Specify base name of output file
     
     Available commands:
-      compare                  
-      examine                  
-      simulate                 Simulate reconstructed trees using the point process.
-                               See Gernhard, T. (2008). The conditioned
-                               reconstructed process. Journal of Theoretical
-                               Biology, 253(4), 769–778.
-                               http://doi.org/10.1016/j.jtbi.2008.04.005
+      distance                 Compute distances between many phylogenetic trees.
+      examine                  Compute summary statistics of phylogenetic trees.
+      simulate                 Simulate phylogenetic trees using birth and death
+                               processes.
+      compare                  Compare two phylogenetic trees (compute distances and
+                               branch-wise differences).
+      connect                  Connect two phylogenetic trees in all ways (possibly
+                               honoring constraints).
+      shuffle                  Shuffle a phylogenetic tree (keep coalescent times,
+                               but shuffle topology and leaves).
     
     File formats:
       - Newick
     
-    The ELynx Suite.
+    The ELynx Suite
+    ---------------
     A Haskell library and a tool set for computational biology. The goal of the
     ELynx Suite is reproducible research. Evolutionary sequences and phylogenetic
     trees can be read, viewed, modified and simulated. Exact specification of all
     options is necessary, and nothing is assumed about the data (e.g., the type of
     code). The command line with all arguments is consistently, and automatically
-    logged. The work overhead in the beginning usually pays off in the end.
+    logged.
+    
     slynx     Analyze, modify, and simulate evolutionary sequences.
     tlynx     Analyze, modify, and simulate phylogenetic trees.
+    
+    Get help for specific commands:
+      slynx examine --help
 
 
 ## Compare
@@ -340,24 +352,18 @@
 
     tlynx compare --help
 
-    Compute distances between phylogenetic trees.
-    
-    Usage: tlynx compare (-d|--distance MEASURE) [-s|--summary-statistics]
-                         [INPUT-FILES]
+    Usage: tlynx compare [-n|--normalize] [-b|--bipartitions] [-i|--newick-iqtree]
+                         NAME
+      Compare two phylogenetic trees (compute distances and branch-wise
+      differences).
     
     Available options:
-      -d,--distance MEASURE    Type of distance to calculate (available distance
-                               measures are listed below)
-      -s,--summary-statistics  Report summary statistics only
-      INPUT-FILES              Read tree(s) from INPUT-FILES; if more files are
-                               given, one tree is expected per file
+      -n,--normalize           Normalize trees before comparison
+      -b,--bipartitions        Print common and missing bipartitions
+      -i,--newick-iqtree       Use IQ-TREE Newick format (internal node labels are
+                               branch support values)
+      NAME                     Tree file
       -h,--help                Show this help text
-    
-    Available distance measures:
-      Symmetric distance: -d symmetric
-      Incompatible split distance: -d incompatible-split[VAL]
-        Collapse branches with support less than VAL before distance calculation;
-        in this way, only well supported difference contribute to the distance measure.
 
 
 ## Examine
@@ -366,12 +372,13 @@
 
     tlynx examine --help
 
-    Compute summary statistics of phylogenetic trees.
-    
-    Usage: tlynx examine [INPUT-FILE]
+    Usage: tlynx examine [INPUT-FILE] [-i|--newick-iqtree]
+      Compute summary statistics of phylogenetic trees.
     
     Available options:
       INPUT-FILE               Read trees from INPUT-FILE
+      -i,--newick-iqtree       Use IQ-TREE Newick format (internal node labels are
+                               branch support values)
       -h,--help                Show this help text
 
 
@@ -381,15 +388,11 @@
 
     tlynx simulate --help
 
-    Simulate phylogenetic trees using birth and death processes.
-    
     Usage: tlynx simulate [-t|--nTrees INT] [-n|--nLeaves INT] [-H|--height DOUBLE]
                           [-M|--condition-on-mrca] [-l|--lambda DOUBLE]
                           [-m|--mu DOUBLE] [-r|--rho DOUBLE] [-u|--sub-sample]
                           [-s|--summary-statistics] [-S|--seed [INT]]
-      Simulate reconstructed trees using the point process. See Gernhard, T. (2008).
-      The conditioned reconstructed process. Journal of Theoretical Biology, 253(4),
-      769–778. http://doi.org/10.1016/j.jtbi.2008.04.005
+      Simulate phylogenetic trees using birth and death processes.
     
     Available options:
       -t,--nTrees INT          Number of trees (default: 10)
@@ -409,9 +412,16 @@
     Height of Trees: if no tree height is given, the heights will be randomly drawn from the expected distribution given the number of leaves, the birth and the death rate.
     Summary statistics only: only print (NumberOfExtantChildren BranchLength) pairs for each branch of each tree. The trees are separated by a newline character.
     Sub-sampling: simulate one big tree with n'=round(n/rho), n'>=n, leaves, and randomly sample sub-trees with n leaves. Hence, with rho=1.0, the same tree is reported over and over again.
+    Gernhard, T. (2008). The conditioned reconstructed process. Journal of Theoretical Biology, 253(4), 769–778. http://doi.org/10.1016/j.jtbi.2008.04.005
 
 
 # ELynx
 
-Documentation of the library can be found on Hackage.
+Documentation of the library can be found on [Hackage](https://hackage.haskell.org/):
+
+-   [elynx-seq](https://hackage.haskell.org/package/elynx-seq)
+-   [elynx-tree](https://hackage.haskell.org/package/elynx-tree)
+-   [elynx-tools](https://hackage.haskell.org/package/elynx-tools)
+-   [slynx](https://hackage.haskell.org/package/slynx)
+-   [tlynx](https://hackage.haskell.org/package/tlynx)
 
diff --git a/app/Main.hs b/app/Main.hs
--- a/app/Main.hs
+++ b/app/Main.hs
@@ -35,10 +35,10 @@
       lvl = verbosity g
       lf  = (++ ".log") <$> fn
   case c of
-    Concatenate a -> runReaderT   (eLynxWrapper lvl lf concatenateHeader   $ concatenateCmd fn) a
-    Examine a -> runReaderT       (eLynxWrapper lvl lf examineHeader       $ examineCmd fn) a
-    FilterRows a -> runReaderT    (eLynxWrapper lvl lf filterRowsHeader    $ filterRowsCmd fn) a
-    FilterColumns a -> runReaderT (eLynxWrapper lvl lf filterColumnsHeader $ filterColumnsCmd fn) a
-    Simulate a -> runReaderT      (eLynxWrapper lvl lf simulateHeader      $ simulateCmd fn) a
-    SubSample a -> runReaderT     (eLynxWrapper lvl lf subSampleHeader     $ subSampleCmd fn) a
-    Translate a -> runReaderT     (eLynxWrapper lvl lf translateHeader     $ translateCmd fn) a
+    Concatenate a -> runReaderT (eLynxWrapper lvl lf concatenateDescription   $ concatenateCmd fn) a
+    Examine a     -> runReaderT (eLynxWrapper lvl lf examineDescription       $ examineCmd fn) a
+    FilterRows a  -> runReaderT (eLynxWrapper lvl lf filterRowsDescription    $ filterRowsCmd fn) a
+    FilterCols a  -> runReaderT (eLynxWrapper lvl lf filterColumnsDescription $ filterColsCmd fn) a
+    Simulate a    -> runReaderT (eLynxWrapper lvl lf simulateDescription      $ simulateCmd fn) a
+    SubSample a   -> runReaderT (eLynxWrapper lvl lf subSampleDescription     $ subSampleCmd fn) a
+    Translate a   -> runReaderT (eLynxWrapper lvl lf translateDescription     $ translateCmd fn) a
diff --git a/app/Options.hs b/app/Options.hs
--- a/app/Options.hs
+++ b/app/Options.hs
@@ -16,13 +16,13 @@
   ( Arguments (..)
   , CommandArguments (..)
   , parseArguments
-  , concatenateHeader
-  , examineHeader
-  , filterRowsHeader
-  , filterColumnsHeader
-  , simulateHeader
-  , subSampleHeader
-  , translateHeader
+  , concatenateDescription
+  , examineDescription
+  , filterRowsDescription
+  , filterColumnsDescription
+  , simulateDescription
+  , subSampleDescription
+  , translateDescription
   ) where
 
 import           Options.Applicative
@@ -37,65 +37,69 @@
 
 import           ELynx.Data.Alphabet.Alphabet
 import           ELynx.Tools.Options
+-- TODO: Removed reproducibility stuff for now, have to work on that.
+-- import           ELynx.Tools.Reproduction
 
 data CommandArguments =
   Concatenate ConcatenateArguments
   | Examine ExamineArguments
   | FilterRows FilterRowsArguments
-  | FilterColumns FilterColumnsArguments
+  | FilterCols FilterColsArguments
   | Simulate SimulateArguments
   | SubSample SubSampleArguments
   | Translate TranslateArguments
 
-concatenateHeader, examineHeader, filterRowsHeader, filterColumnsHeader, simulateHeader, subSampleHeader, translateHeader :: String
-concatenateHeader   = "Concatenate sequences found in input files."
-examineHeader       = "Examine sequences."
-filterRowsHeader    =  "Filter rows (or sequences) found in input files."
-filterColumnsHeader = "Filter columns of multi-sequence alignments."
-simulateHeader      = "Simulate multi sequence alignments."
-subSampleHeader     =  "Sub-sample columns from multi sequence alignments."
-translateHeader     =  "Translate from DNA to Protein or DNAX to ProteinX."
+-- instance Reproducible CommandArguments where
+--   inFiles (Concatenate a) = inFiles a
 
+concatenateDescription, examineDescription, filterRowsDescription, filterColumnsDescription, simulateDescription, subSampleDescription, translateDescription :: String
+concatenateDescription   = "Concatenate sequences found in input files."
+examineDescription       = "Examine sequences. If data is a multi sequence alignment, additionally analyze columns."
+filterRowsDescription    =  "Filter rows (or sequences) found in input files."
+filterColumnsDescription = "Filter columns of multi-sequence alignments."
+simulateDescription      = "Simulate multi sequence alignments."
+subSampleDescription     =  "Sub-sample columns from multi sequence alignments."
+translateDescription     =  "Translate from DNA to Protein or DNAX to ProteinX."
+
 concatenateCommand :: Mod CommandFields CommandArguments
 concatenateCommand = command "concatenate" $
                      info (Concatenate <$> concatenateArguments)
-                     $ header concatenateHeader
+                     $ progDesc concatenateDescription
 
 examineCommand :: Mod CommandFields CommandArguments
 examineCommand = command "examine" $
                      info (Examine <$> examineArguments)
                      ( fullDesc
-                       <> header examineHeader
-                       <> progDesc "If data is a multi sequence alignment, additionally analyze columns." )
+                       <> progDesc examineDescription )
 
 filterRowsCommand :: Mod CommandFields CommandArguments
 filterRowsCommand = command "filter-rows" $
                      info (FilterRows <$> filterRowsArguments)
-                     $ header filterRowsHeader
+                     $ progDesc filterRowsDescription
 
 filterColumnsCommand :: Mod CommandFields CommandArguments
 filterColumnsCommand = command "filter-columns" $
-                     info (FilterColumns <$> filterColumnsArguments)
-                     $ header filterColumnsHeader
+                     info (FilterCols <$> filterColsArguments)
+                     $ progDesc filterColumnsDescription
 
 simulateCommand :: Mod CommandFields CommandArguments
 simulateCommand = command "simulate" $
                   info (Simulate <$> simulateArguments)
                   (fullDesc
-                   <> header simulateHeader
+                   <> progDesc simulateDescription
                    <> footerDoc (Just $ pretty simulateFooter) )
 
 subSampleCommand :: Mod CommandFields CommandArguments
 subSampleCommand = command "sub-sample" $
                    info (SubSample <$> subSampleArguments)
                    ( fullDesc
-                     <> header subSampleHeader
-                     <> progDesc "Create a given number of multi sequence alignments, each of which containing a given number of random sites drawn from the original multi sequence alignment." )
+                     <> progDesc subSampleDescription
+                     <> footer "Create a given number of multi sequence alignments, each of which contains a given number of random sites drawn from the original multi sequence alignment." )
 
 translateCommand :: Mod CommandFields CommandArguments
 translateCommand = command "translate" $
                    info (Translate <$> translateArguments)
-                   $ header translateHeader
+                   $ progDesc translateDescription
 
 commandArguments :: Parser CommandArguments
 commandArguments = hsubparser $
@@ -107,15 +111,8 @@
                    <> subSampleCommand
                    <> translateCommand
 
-data Arguments = Arguments
-  { globalArgs :: GlobalArguments
-  , cmdArgs    :: CommandArguments }
-
-parseArguments :: IO Arguments
-parseArguments = parseArgumentsWith desc ftr $
-                 Arguments
-                 <$> globalArguments
-                 <*> commandArguments
+parseArguments :: IO (Arguments CommandArguments)
+parseArguments = parseArgumentsWith desc ftr commandArguments
 
 desc :: [String]
 desc = [ "Analyze, and simulate multi sequence alignments." ]
@@ -126,4 +123,4 @@
   where
     toListItem = ("  - " ++)
     fs = map toListItem ["FASTA"]
-    as = map (toListItem . alphabetNameVerbose) [(minBound :: Alphabet) ..]
+    as = map (toListItem . description) [(minBound :: Alphabet) ..]
diff --git a/slynx.cabal b/slynx.cabal
--- a/slynx.cabal
+++ b/slynx.cabal
@@ -1,6 +1,6 @@
 cabal-version: 1.12
 name: slynx
-version: 0.0.1
+version: 0.1.0
 license: GPL-3
 license-file: LICENSE
 copyright: Dominik Schrempf (2019)
@@ -41,20 +41,19 @@
     other-modules:
         Paths_slynx
     default-language: Haskell2010
-    ghc-options: -Wall
+    ghc-options: -Wall -O2
     build-depends:
         async >=2.2.2 && <2.3,
         base >=4.12.0.0 && <4.13,
         bytestring >=0.10.8.2 && <0.11,
         containers >=0.6.0.1 && <0.7,
         data-memocombinators >=0.5.1 && <0.6,
-        elynx-seq >=0.0.1 && <0.1,
-        elynx-tools >=0.0.1 && <0.1,
-        elynx-tree >=0.0.1 && <0.1,
+        elynx-seq >=0.1.0 && <0.2,
+        elynx-tools >=0.1.0 && <0.2,
+        elynx-tree >=0.1.0 && <0.2,
         hmatrix >=0.20.0.0 && <0.21,
         integration >=0.2.1 && <0.3,
-        lens >=4.17.1 && <4.18,
-        math-functions >=0.3.1.0 && <0.4,
+        math-functions >=0.3.2.1 && <0.4,
         matrices >=0.5.0 && <0.6,
         megaparsec >=7.0.5 && <7.1,
         monad-logger >=0.3.30 && <0.4,
@@ -76,19 +75,19 @@
         Options
         Paths_slynx
     default-language: Haskell2010
-    ghc-options: -Wall -eventlog -threaded -rtsopts -with-rtsopts=-N
+    ghc-options: -Wall -O2 -eventlog -threaded -rtsopts
+                 -with-rtsopts=-N
     build-depends:
         async >=2.2.2 && <2.3,
         base >=4.12.0.0 && <4.13,
         bytestring >=0.10.8.2 && <0.11,
         containers >=0.6.0.1 && <0.7,
         data-memocombinators >=0.5.1 && <0.6,
-        elynx-seq >=0.0.1 && <0.1,
-        elynx-tools >=0.0.1 && <0.1,
+        elynx-seq >=0.1.0 && <0.2,
+        elynx-tools >=0.1.0 && <0.2,
         hmatrix >=0.20.0.0 && <0.21,
         integration >=0.2.1 && <0.3,
-        lens >=4.17.1 && <4.18,
-        math-functions >=0.3.1.0 && <0.4,
+        math-functions >=0.3.2.1 && <0.4,
         matrices >=0.5.0 && <0.6,
         megaparsec >=7.0.5 && <7.1,
         monad-logger >=0.3.30 && <0.4,
diff --git a/src/Concatenate/Concatenate.hs b/src/Concatenate/Concatenate.hs
--- a/src/Concatenate/Concatenate.hs
+++ b/src/Concatenate/Concatenate.hs
@@ -27,7 +27,7 @@
 import           Concatenate.Options
 import           Tools
 
-import           ELynx.Data.Sequence.Sequence
+import qualified ELynx.Data.Sequence.Sequence as S
 import           ELynx.Export.Sequence.Fasta
 import           ELynx.Tools.InputOutput
 
@@ -37,7 +37,7 @@
   $(logInfo) "Command: Concatenate sequences."
   ConcatenateArguments al fps <- lift ask
   sss <- mapM (readSeqs al . Just) fps
-  let result      = sequencesToFasta $ concatenateSeqs sss
+  let result      = sequencesToFasta $ S.concatSequences sss
   let outFilePath = (++ ".fasta") <$> outFileBaseName
-  io "concatenated multi sequence alignment " result outFilePath
+  out "concatenated multi sequence alignment " result outFilePath
 
diff --git a/src/Concatenate/Options.hs b/src/Concatenate/Options.hs
--- a/src/Concatenate/Options.hs
+++ b/src/Concatenate/Options.hs
@@ -26,11 +26,16 @@
 import           Tools
 
 import           ELynx.Data.Alphabet.Alphabet
+import           ELynx.Tools.Reproduction
 
 -- | Arguments needed to concatenate multi sequence alignments.
 data ConcatenateArguments = ConcatenateArguments
     { ccAlphabet :: Alphabet
     , ccInFiles  :: [FilePath] }
+
+instance Reproducible ConcatenateArguments where
+  inFiles  = ccInFiles
+  parser _ = concatenateArguments
 
 -- | Logger and Reader type.
 type Concatenate = LoggingT (ReaderT ConcatenateArguments IO)
diff --git a/src/Examine/Examine.hs b/src/Examine/Examine.hs
--- a/src/Examine/Examine.hs
+++ b/src/Examine/Examine.hs
@@ -24,24 +24,28 @@
 import           Control.Monad.Logger
 import           Control.Monad.Trans.Class
 import           Control.Monad.Trans.Reader
-import qualified Data.ByteString.Lazy.Char8                 as L
+import qualified Data.ByteString.Lazy.Char8    as L
+import qualified Data.Set                      as S
 import           Text.Printf
 
 import           Examine.Options
 import           Tools
 
-import           ELynx.Data.Sequence.MultiSequenceAlignment
-import           ELynx.Data.Sequence.Sequence
+import qualified ELynx.Data.Alphabet.Alphabet  as A
+import qualified ELynx.Data.Alphabet.Character as C
+import qualified ELynx.Data.Sequence.Alignment as M
+import qualified ELynx.Data.Sequence.Sequence  as Seq
 import           ELynx.Tools.InputOutput
 
-examineMSA :: Bool -> MultiSequenceAlignment -> L.ByteString
-examineMSA perSiteFlag msa =
-  L.unlines [ L.pack $ "Total number of columns in alignment: "
-              ++ show (msaLength msa)
+examineAlignment :: Bool -> M.Alignment -> L.ByteString
+examineAlignment perSiteFlag a =
+  L.unlines [ L.pack "Sequences have equal length (multi sequence alignment, or single sequence)."
+            , L.pack $ "Total number of columns in alignment: "
+              ++ show (M.length a)
             , L.pack $ "Number of columns without gaps: "
-              ++ show (msaLength msaNoGaps)
+              ++ show (M.length aNoGaps)
             , L.pack $ "Number of columns with standard characters only: "
-              ++ show (msaLength msaOnlyStd)
+              ++ show (M.length aOnlyStd)
             , L.empty
             , L.pack $ "Total number of characters: " ++ show nTot
             , L.pack $ "Standard (i.e., not extended IUPAC) characters: "
@@ -58,6 +62,12 @@
             , L.pack $ "Percentage of unknowns: "
               ++ printf "%.3f" percentageUnknowns
             , L.empty
+            , L.pack "Distribution of characters:"
+              -- Holy crap.
+            , L.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):"
             , L.pack "Across whole alignment: "
               <> L.pack (printf "%.3f" kEffMean)
@@ -68,18 +78,20 @@
             ]
   <> perSiteBS
   where
-    nTot                = msaLength msa * msaNSequences msa
-    nIUPAC              = countIUPACChars msa
-    nGaps               = countGaps msa
-    nUnknowns           = countUnknowns msa
+    nTot                = M.length a * M.nSequences a
+    nIUPAC              = M.countIUPACChars a
+    nGaps               = M.countGaps a
+    nUnknowns           = M.countUnknowns a
     percentageIUPAC     = fromIntegral nIUPAC    / fromIntegral nTot :: Double
     percentageGaps      = fromIntegral nGaps     / fromIntegral nTot :: Double
     percentageUnknowns  = fromIntegral nUnknowns / fromIntegral nTot :: Double
-    msaNoGaps           = filterColumnsNoGaps msa
-    msaOnlyStd          = filterColumnsOnlyStd msaNoGaps
-    kEffs               = kEffEntropy . toFrequencyData $ msa
-    kEffsNoGaps         = kEffEntropy . toFrequencyData $ msaNoGaps
-    kEffsOnlyStd        = kEffEntropy . toFrequencyData $ msaOnlyStd
+    aNoGaps             = M.filterColsNoGaps a
+    aOnlyStd            = M.filterColsOnlyStd aNoGaps
+    charFreqsPerSite    = M.toFrequencyData a
+    charFreqs           = M.distribution charFreqsPerSite
+    kEffs               = M.kEffEntropy charFreqsPerSite
+    kEffsNoGaps         = M.kEffEntropy . M.toFrequencyData $ aNoGaps
+    kEffsOnlyStd        = M.kEffEntropy . M.toFrequencyData $ aOnlyStd
     kEffMean            = sum kEffs / fromIntegral (length kEffs)
     kEffMeanNoGaps      = sum kEffsNoGaps  / fromIntegral (length kEffsNoGaps)
     kEffMeanOnlyStd     = sum kEffsOnlyStd / fromIntegral (length kEffsOnlyStd)
@@ -89,11 +101,11 @@
                                          ]
                           else L.empty
 
-examine :: Bool -> [Sequence] -> L.ByteString
-examine perSiteFlag ss = summarizeSequenceList ss <>
-  case fromSequenceList ss of
-    Left _    -> L.empty
-    Right msa -> L.pack "\n" <> examineMSA perSiteFlag msa
+examine :: Bool -> [Seq.Sequence] -> L.ByteString
+examine perSiteFlag ss = Seq.summarizeSequences ss <>
+  case M.fromSequences ss of
+    Left  _ -> L.empty
+    Right a -> L.pack "\n" <> examineAlignment perSiteFlag a
 
 -- | Examine sequences.
 examineCmd :: Maybe FilePath -> Examine ()
@@ -103,4 +115,4 @@
   ss <- readSeqs al inFile
   let result = examine perSiteFlag ss
   let outFilePath = (++ ".out") <$> outFileBaseName
-  io "result of examination" result outFilePath
+  out "result of examination" result outFilePath
diff --git a/src/Examine/Options.hs b/src/Examine/Options.hs
--- a/src/Examine/Options.hs
+++ b/src/Examine/Options.hs
@@ -18,20 +18,29 @@
   , examineArguments
   ) where
 
-import           Control.Applicative
+import           Control.Applicative          (optional)
 import           Control.Monad.Logger
 import           Control.Monad.Trans.Reader
+import           Data.Maybe                   (fromJust)
 import           Options.Applicative
 
 import           Tools
 
 import           ELynx.Data.Alphabet.Alphabet
+import           ELynx.Tools.Reproduction
 
 -- | Arguments needed to examine sequences.
 data ExamineArguments = ExamineArguments
     { exAlphabet :: Alphabet
     , exInFile   :: Maybe FilePath
     , exPerSite  :: Bool }
+
+instance Reproducible ExamineArguments where
+  -- TODO: How do I combine optional input files with reproducibility? The
+  -- answer is: use checksums! Also other input files have to be checked with
+  -- check sums. StdIO can also be checked in the same way.
+  inFiles  = pure . fromJust . exInFile
+  parser _ = examineArguments
 
 -- | Logger and Reader type.
 type Examine = LoggingT (ReaderT ExamineArguments IO)
diff --git a/src/Filter/Filter.hs b/src/Filter/Filter.hs
--- a/src/Filter/Filter.hs
+++ b/src/Filter/Filter.hs
@@ -17,60 +17,64 @@
 
 module Filter.Filter
   ( filterRowsCmd
-  , filterColumnsCmd
+  , filterColsCmd
   )
   where
 
+import           Control.Monad                 (when)
 import           Control.Monad.Logger
 import           Control.Monad.Trans.Class
 import           Control.Monad.Trans.Reader
-import qualified Data.ByteString.Lazy.Char8                 as L
-import           Data.Maybe                                 (fromMaybe)
-import qualified Data.Text                                  as T
+import qualified Data.ByteString.Lazy.Char8    as L
+import           Data.Maybe                    (fromMaybe)
+import qualified Data.Text                     as T
 
 import           Filter.Options
 import           Tools
 
-import           ELynx.Data.Sequence.MultiSequenceAlignment
-import           ELynx.Data.Sequence.Sequence
+import qualified ELynx.Data.Sequence.Alignment as M
+import qualified ELynx.Data.Sequence.Sequence  as S
 import           ELynx.Export.Sequence.Fasta
 import           ELynx.Tools.InputOutput
 import           ELynx.Tools.Misc
 
-filterRows :: Maybe Int -> Maybe Int -> [Sequence] -> L.ByteString
-filterRows ml ms ss = sequencesToFasta $ compose filters ss
-  where filters = map (fromMaybe id) [filterLongerThan <$> ml, filterShorterThan <$> ms]
+filterRows :: Maybe Int -> Maybe Int -> Bool -> [S.Sequence] -> L.ByteString
+filterRows ml ms std ss = sequencesToFasta $ compose filters ss
+  where filters' = map (fromMaybe id) [S.filterLongerThan <$> ml, S.filterShorterThan <$> ms]
+        filters  = if std then S.filterStandard : filters'  else filters'
 
 -- | Filter sequences.
 filterRowsCmd :: Maybe FilePath -> FilterRows ()
 filterRowsCmd outFileBaseName = do
   $(logInfo) "Command: Filter sequences of a list of sequences."
-  FilterRowsArguments al inFile long short <- lift ask
+  FilterRowsArguments al inFile long short std <- lift ask
   maybe (return ())
     (\val -> $(logInfo) $ T.pack $ "  Keep sequences longer than " <> show val <> ".") long
   maybe (return ())
     (\val -> $(logInfo) $ T.pack $ "  Keep sequences shorter than " <> show val <> ".") short
+  when std $
+    $(logInfo) "  Keep sequences containing at least one standard (i.e., non-IUPAC) character."
   ss <- readSeqs al inFile
-  let result      = filterRows long short ss
+  let result      = filterRows long short std ss
   let outFilePath = (++ ".fasta") <$> outFileBaseName
-  io "filtered sequences" result outFilePath
+  out "filtered sequences" result outFilePath
 
-filterColumns :: Maybe Double -> [Sequence] -> L.ByteString
-filterColumns ms ss = sequencesToFasta . toSequenceList $ compose filters msa
-  where msa = either error id (fromSequenceList ss)
-        filters = map (fromMaybe id) [ filterColumnsStd <$> ms ]
+filterCols :: Maybe Double -> [S.Sequence] -> L.ByteString
+filterCols ms ss = sequencesToFasta . M.toSequences $ compose filters a
+  where a = either error id (M.fromSequences ss)
+        filters = map (fromMaybe id) [ M.filterColsStd <$> ms ]
 
 -- | Filter columns.
-filterColumnsCmd :: Maybe FilePath -> FilterColumns ()
-filterColumnsCmd outFileBaseName = do
+filterColsCmd :: Maybe FilePath -> FilterCols ()
+filterColsCmd outFileBaseName = do
   $(logInfo) "Command: Filter columns of a multi sequence alignment."
-  FilterColumnsArguments al inFile standard <- lift ask
+  FilterColsArguments al inFile standard <- lift ask
   case standard of
     Nothing -> return ()
     Just p -> $(logInfo) $ T.pack $
         "  Keep columns with a proportion of standard (non-IUPAC) characters larger than "
         ++ show p ++ "."
   ss <- readSeqs al inFile
-  let result      = filterColumns standard ss
+  let result      = filterCols standard ss
   let outFilePath = (++ ".fasta") <$> outFileBaseName
-  io "filtered sequences" result outFilePath
+  out "filtered sequences" result outFilePath
diff --git a/src/Filter/Options.hs b/src/Filter/Options.hs
--- a/src/Filter/Options.hs
+++ b/src/Filter/Options.hs
@@ -14,11 +14,11 @@
 
 module Filter.Options
   ( FilterRowsArguments (..)
-  , FilterColumnsArguments (..)
+  , FilterColsArguments (..)
   , FilterRows
-  , FilterColumns
+  , FilterCols
   , filterRowsArguments
-  , filterColumnsArguments
+  , filterColsArguments
   ) where
 
 import           Control.Applicative
@@ -35,10 +35,11 @@
   { frAlphabet :: Alphabet
   , frInFile   :: Maybe FilePath
   , frLonger   :: Maybe Int
-  , frShorter  :: Maybe Int }
+  , frShorter  :: Maybe Int
+  , frStandard :: Bool }
 
 -- | Arguments needed for filtering columns of a multi sequence alignment.
-data FilterColumnsArguments = FilterColumnsArguments
+data FilterColsArguments = FilterColsArguments
   { fcAlphabet :: Alphabet
   , fcInFile   :: Maybe FilePath
   , fcStandard :: Maybe Double }
@@ -47,7 +48,7 @@
 type FilterRows = LoggingT (ReaderT FilterRowsArguments IO)
 
 -- | Logger and Reader for column filtering.
-type FilterColumns = LoggingT (ReaderT FilterColumnsArguments IO)
+type FilterCols = LoggingT (ReaderT FilterColsArguments IO)
 
 -- | Command line parser.
 filterRowsArguments :: Parser FilterRowsArguments
@@ -56,6 +57,7 @@
               <*> optional inFileArg
               <*> filterLongerThanOpt
               <*> filterShorterThanOpt
+              <*> filterStandardChars
 
 filterLongerThanOpt :: Parser (Maybe Int)
 filterLongerThanOpt = optional $ option auto $
@@ -69,9 +71,14 @@
   metavar "LENGTH" <>
   help "Only keep sequences shorter than LENGTH"
 
+filterStandardChars :: Parser Bool
+filterStandardChars = switch $
+  long "standard-characters" <>
+  help "Only keep sequences containing at least one standard (i.e., non-IUPAC) character"
+
 -- | Command line parser.
-filterColumnsArguments :: Parser FilterColumnsArguments
-filterColumnsArguments = FilterColumnsArguments
+filterColsArguments :: Parser FilterColsArguments
+filterColsArguments = FilterColsArguments
                  <$> alphabetOpt
                  <*> optional inFileArg
                  <*> filterStandardOpt
diff --git a/src/Simulate/Options.hs b/src/Simulate/Options.hs
--- a/src/Simulate/Options.hs
+++ b/src/Simulate/Options.hs
@@ -46,8 +46,12 @@
 import           Control.Monad.Logger
 import           Control.Monad.Trans.Reader
 import           Data.List
+import           Data.String                (words)
+-- import           Data.Void
 import           Data.Word
 import           Options.Applicative
+-- import           Text.Megaparsec            (Parsec, takeWhile1P)
+-- import           Text.Megaparsec.Char       (space)
 
 import           ELynx.Tools.Options
 
@@ -60,6 +64,7 @@
   , argsSubstitutionModelString :: Maybe String
   , argsMixtureModelString      :: Maybe String
   , argsEDMFile                 :: Maybe FilePath
+  , argsSiteprofilesFiles       :: Maybe [FilePath]
   , argsMixtureWeights          :: Maybe [Double]
   , argsGammaParams             :: Maybe GammaRateHeterogeneityParams
   , argsLength                  :: Int
@@ -76,6 +81,7 @@
   <*> phyloSubstitutionModelOpt
   <*> phyloMixtureModelOpt
   <*> maybeEDMFileOpt
+  <*> maybeSiteprofilesFilesOpt
   <*> maybeMixtureWeights
   <*> maybeGammaParams
   <*> lengthOpt
@@ -108,6 +114,20 @@
     <> short 'e'
     <> metavar "NAME"
     <> help "Empirical distribution model file NAME in Phylobayes format" )
+
+-- fn :: Parsec Void String FilePath
+-- fn = space *> takeWhile1P () <* space
+
+-- fns :: Parsec Void String [FilePath]
+-- fns = do
+--   many string
+
+maybeSiteprofilesFilesOpt :: Parser (Maybe [FilePath])
+maybeSiteprofilesFilesOpt = optional $ words <$> strOption
+  ( long "siteprofile-files"
+    <> short 'p'
+    <> metavar "NAMES"
+    <> help "File names of site profiles in Phylobayes format" )
 
 maybeMixtureWeights :: Parser (Maybe [Double])
 maybeMixtureWeights = optional $ option auto
diff --git a/src/Simulate/Simulate.hs b/src/Simulate/Simulate.hs
--- a/src/Simulate/Simulate.hs
+++ b/src/Simulate/Simulate.hs
@@ -19,40 +19,47 @@
   ( simulateCmd )
 where
 
+import           Control.Applicative                               ((<|>))
 import           Control.Concurrent
 import           Control.Concurrent.Async
-import           Control.Lens
+import           Control.Monad                                     (unless,
+                                                                    when)
 import           Control.Monad.IO.Class
 import           Control.Monad.Logger
 import           Control.Monad.Trans.Class
 import           Control.Monad.Trans.Reader
-import qualified Data.ByteString.Lazy                            as L
-import qualified Data.ByteString.Lazy.Char8                      as LC
-import qualified Data.Set                                        as Set
-import qualified Data.Text                                       as T
-import qualified Data.Text.Lazy                                  as LT
-import qualified Data.Text.Lazy.Encoding                         as LT
+import qualified Data.ByteString.Lazy                              as L
+import qualified Data.ByteString.Lazy.Char8                        as LC
+import           Data.Maybe
+import qualified Data.Set                                          as Set
+import qualified Data.Text                                         as T
+import qualified Data.Text.Lazy                                    as LT
+import qualified Data.Text.Lazy.Encoding                           as LT
 import           Data.Tree
-import qualified Data.Vector.Unboxed                             as V
-import           Numeric.LinearAlgebra                           hiding ((<>))
+import qualified Data.Vector.Unboxed                               as V
+import           Numeric.LinearAlgebra                             hiding ((<>))
 import           System.Random.MWC
 
 import           Simulate.Options
 import           Simulate.PhyloModel
 
-import           ELynx.Data.Alphabet.Alphabet                    as A
+import           ELynx.Data.Alphabet.Alphabet                      as A
 import           ELynx.Data.MarkovProcess.GammaRateHeterogeneity
-import qualified ELynx.Data.MarkovProcess.MixtureModel           as M
-import qualified ELynx.Data.MarkovProcess.PhyloModel             as P
-import qualified ELynx.Data.MarkovProcess.SubstitutionModel      as S
-import           ELynx.Data.Sequence.MultiSequenceAlignment
-import           ELynx.Data.Sequence.Sequence                    hiding (name)
+import qualified ELynx.Data.MarkovProcess.MixtureModel             as M
+import qualified ELynx.Data.MarkovProcess.PhyloModel               as P
+import qualified ELynx.Data.MarkovProcess.SubstitutionModel        as SM
+import qualified ELynx.Data.Sequence.Alignment                     as A
+import qualified ELynx.Data.Sequence.Sequence                      as Seq hiding
+                                                                           (name)
 import           ELynx.Data.Tree.MeasurableTree
 import           ELynx.Data.Tree.NamedTree
 import           ELynx.Data.Tree.Tree
 import           ELynx.Export.Sequence.Fasta
-import           ELynx.Import.MarkovProcess.EDMModelPhylobayes   hiding (Parser)
-import           ELynx.Import.Tree.Newick                        hiding (name)
+import           ELynx.Import.MarkovProcess.EDMModelPhylobayes     hiding
+                                                                    (Parser)
+import           ELynx.Import.MarkovProcess.SiteprofilesPhylobayes hiding
+                                                                    (Parser)
+import           ELynx.Import.Tree.Newick                          hiding (name)
 import           ELynx.Simulate.MarkovProcessAlongTree
 
 import           ELynx.Tools.ByteString
@@ -60,36 +67,40 @@
 import           ELynx.Tools.InputOutput
 import           ELynx.Tools.Misc
 
--- Simulate a 'MultiSequenceAlignment' for a given phylogenetic model,
+-- Simulate a 'Alignment' for a given phylogenetic model,
 -- phylogenetic tree, and alignment length.
-simulateMSA :: (Measurable a, Named a)
+simulateAlignment :: (Measurable a, Named a)
             => P.PhyloModel -> Tree a -> Int -> GenIO
-            -> IO MultiSequenceAlignment
-simulateMSA pm t n g = do
+            -> IO A.Alignment
+simulateAlignment pm t n g = do
   c  <- getNumCapabilities
   gs <- splitGen c g
   let chunks = getChunks c n
   leafStatesS <- case pm of
+    -- TODO: This parallelization is not very intelligent, because the matrices
+    -- exponentiation is done in all threads. So ten threads will exponentiate
+    -- the same matrix ten times.
     P.SubstitutionModel sm -> mapConcurrently
-      (\(num, gen) -> simulateAndFlattenNSitesAlongTree num d e t gen) (zip chunks gs)
-      where d = sm ^. S.stationaryDistribution
-            e = sm ^. S.exchangeabilityMatrix
-    P.MixtureModel mm      -> mapConcurrently
-      (\(num, gen) -> simulateAndFlattenNSitesAlongTreeMixtureModel num ws ds es t gen) (zip chunks gs)
+      (\(num, gen) -> simulateAndFlatten num d e t gen) (zip chunks gs)
+      where d = SM.stationaryDistribution sm
+            e = SM.exchangeabilityMatrix sm
+    -- P.MixtureModel mm      -> mapConcurrently
+    --   (\(num, gen) -> simulateAndFlattenNSitesAlongTreeMixtureModel num ws ds es t gen) (zip chunks gs)
+    P.MixtureModel mm      -> simulateAndFlattenMixtureModelPar n ws ds es t g
       where
         ws = vector $ M.getWeights mm
-        ds = map (view S.stationaryDistribution) $ M.getSubstitutionModels mm
-        es = map (view S.exchangeabilityMatrix) $ M.getSubstitutionModels mm
+        ds = map SM.stationaryDistribution $ M.getSubstitutionModels mm
+        es = map SM.exchangeabilityMatrix  $ M.getSubstitutionModels mm
   -- XXX: The horizontal concatenation might be slow. If so, 'concatenateSeqs'
-  -- or 'concatenateMSAs' can be used, which directly appends vectors.
+  -- or 'concatenateAlignments' can be used, which directly appends vectors.
   let leafStates = horizontalConcat leafStatesS
       leafNames  = map getName $ leaves t
       code       = P.getAlphabet pm
       -- XXX: Probably use type safe stuff here?
       alph       = A.all $ alphabetSpec code
-      sequences  = [ Sequence sName code (V.fromList $ map (`Set.elemAt` alph) ss) |
+      sequences  = [ Seq.Sequence sName code (V.fromList $ map (`Set.elemAt` alph) ss) |
                     (sName, ss) <- zip leafNames leafStates ]
-  return $ either error id $ fromSequenceList sequences
+  return $ either error id $ A.fromSequences sequences
 
 -- Summarize EDM components; line to be printed to screen or log.
 summarizeEDMComponents :: [EDMComponent] -> L.ByteString
@@ -101,32 +112,48 @@
 -- necessary. A human readable summary is reported anyways, and for Protein
 -- models the exchangeabilities are too many.
 reportModel :: Maybe FilePath -> P.PhyloModel -> Simulate ()
-reportModel outFn m = do
-  let modelFn = (<> ".model") <$> outFn
-  io "model definition (machine readable)" (bsShow m <> "\n") modelFn
+reportModel Nothing      _ = $(logInfo) "No output file provided; omit detailed report of phylogenetic model."
+reportModel (Just outFn) m = do
+  let modelFn = outFn <> ".model"
+  out "model definition (machine readable)" (bShow m <> "\n") (Just modelFn)
 
 -- | Simulate sequences.
 simulateCmd :: Maybe FilePath -> Simulate ()
 simulateCmd outFn = do
   a <- lift ask
-  $(logInfo) "Read tree."
   let treeFile = argsTreeFile a
+
+  $(logInfo) ""
+  $(logInfo) $ T.pack $ "Read tree from file '" ++ treeFile ++ "'."
   tree <- liftIO $ parseFileWith newick treeFile
   $(logInfo) $ LT.toStrict $ LT.decodeUtf8 $ summarize tree
 
   let edmFile = argsEDMFile a
+  let sProfileFiles = argsSiteprofilesFiles a
+  $(logInfo) ""
+  $(logDebug) "Read EDM file or siteprofile files."
+  when (isJust edmFile && isJust sProfileFiles) $ error "Got both: --edm-file and --siteprofile-files."
   edmCs <- case edmFile of
     Nothing   -> return Nothing
     Just edmF -> do
       $(logInfo) "Read EDM file."
       liftIO $ Just <$> parseFileWith phylobayes edmF
   maybe (return ()) ($(logInfo) . LT.toStrict . LT.decodeUtf8 . summarizeEDMComponents) edmCs
+  sProfiles <- case sProfileFiles of
+    Nothing   -> return Nothing
+    Just fns -> do
+      $(logInfo) $ T.pack $ "Read siteprofiles from " ++ show (length fns) ++ " file(s)."
+      $(logDebug) $ T.pack $ "The file names are:" ++ show fns
+      xs <- liftIO $ mapM (parseFileWith siteprofiles) fns
+      return $ Just $ concat xs
+  maybe (return ()) ($(logInfo) . LT.toStrict . LT.decodeUtf8 . summarizeEDMComponents) sProfiles
+  let edmCsOrSiteprofiles = edmCs <|> sProfiles
 
   $(logInfo) "Read model string."
   let ms = argsSubstitutionModelString a
       mm = argsMixtureModelString a
       mws = argsMixtureWeights a
-      eitherPhyloModel' = getPhyloModel ms mm mws edmCs
+      eitherPhyloModel' = getPhyloModel ms mm mws edmCsOrSiteprofiles
   phyloModel' <- case eitherPhyloModel' of
     Left err -> lift $ error err
     Right pm -> return pm
@@ -139,10 +166,16 @@
       return phyloModel'
     Just (n, alpha) -> do
       $(logInfo) $ LT.toStrict $ LT.decodeUtf8
-        $ LC.unlines $ P.summarize phyloModel' ++ summarizeGammaRateHeterogeneity n alpha
+        $ LC.intercalate "\n" $ P.summarize phyloModel' ++ summarizeGammaRateHeterogeneity n alpha
       return $ expand n alpha phyloModel'
-  reportModel outFn phyloModel
 
+  -- -- XXX: Do not report possibly huge empirical distribution mixture models
+  -- -- for now, because it takes too long and uses too much disk space :).
+  unless (isJust sProfiles) (
+    do reportModel outFn phyloModel
+       $(logInfo) ""
+    )
+
   $(logInfo) "Simulate alignment."
   let alignmentLength = argsLength a
   $(logInfo) $ T.pack $ "Length: " <> show alignmentLength <> "."
@@ -152,7 +185,8 @@
                >> liftIO createSystemRandom
     Just s  -> $(logInfo) (T.pack ("Seed: " <> show s <> "."))
                >> liftIO (initialize (V.fromList s))
-  msa <- liftIO $ simulateMSA phyloModel tree alignmentLength gen
-  let output = (sequencesToFasta . toSequenceList) msa
+  alignment <- liftIO $ simulateAlignment phyloModel tree alignmentLength gen
+  let output = (sequencesToFasta . A.toSequences) alignment
       outFile = (<> ".fasta") <$> outFn
-  io "simulated multi sequence alignment" output outFile
+  $(logInfo) ""
+  out "simulated multi sequence alignment" output outFile
diff --git a/src/SubSample/SubSample.hs b/src/SubSample/SubSample.hs
--- a/src/SubSample/SubSample.hs
+++ b/src/SubSample/SubSample.hs
@@ -25,17 +25,17 @@
 import           Control.Monad.Logger
 import           Control.Monad.Trans.Class
 import           Control.Monad.Trans.Reader
-import qualified Data.Text                                  as T
-import qualified Data.Text.Lazy                             as LT
-import qualified Data.Text.Lazy.Builder                     as LT
-import qualified Data.Text.Lazy.Builder.Int                 as LT
-import qualified Data.Vector                                as V
+import qualified Data.Text                     as T
+import qualified Data.Text.Lazy                as LT
+import qualified Data.Text.Lazy.Builder        as LT
+import qualified Data.Text.Lazy.Builder.Int    as LT
+import qualified Data.Vector                   as V
 import           System.Random.MWC
 
 import           SubSample.Options
 import           Tools
 
-import           ELynx.Data.Sequence.MultiSequenceAlignment
+import qualified ELynx.Data.Sequence.Alignment as M
 import           ELynx.Export.Sequence.Fasta
 import           ELynx.Tools.InputOutput
 
@@ -60,11 +60,11 @@
   $(logInfo) $ T.pack $ "  Sample " <> show nAlignments <> " multi sequence alignments."
   ss <- readSeqs al inFile
   gen <- liftIO $ maybe createSystemRandom (initialize . V.fromList) seed
-  let msa = either error id (fromSequenceList ss)
-  samples <- lift $ replicateM nAlignments $ randomSubSample nSites msa gen
-  let results = map (sequencesToFasta . toSequenceList) samples
+  let a = either error id (M.fromSequences ss)
+  samples <- lift $ replicateM nAlignments $ M.randomSubSample nSites a gen
+  let results = map (sequencesToFasta . M.toSequences) samples
   outFilePaths <- case outFileBaseName of
     Nothing -> return $ repeat Nothing
     Just fn -> return $ Just <$> getOutFilePaths fn nAlignments "fasta"
-  zipWithM_ (io "sub sampled multi sequence alignments") results outFilePaths
+  zipWithM_ (out "sub sampled multi sequence alignments") results outFilePaths
 
diff --git a/src/Tools.hs b/src/Tools.hs
--- a/src/Tools.hs
+++ b/src/Tools.hs
@@ -29,7 +29,7 @@
 
 import           ELynx.Data.Alphabet.Alphabet
 import           ELynx.Data.Sequence.Sequence
-import           ELynx.Import.Sequence.Fasta
+import           ELynx.Import.Sequence.Fasta  hiding (Parser)
 import           ELynx.Tools.InputOutput
 
 -- | Read sequences of given alphabet from file or standard input.
@@ -41,7 +41,7 @@
                <> show a <> "."
     Just fp -> $(logInfo) $ T.pack
                $ "Read sequences from file "
-               <> fp <> "; alphabet" <> show a <> "."
+               <> fp <> "; alphabet " <> show a <> "."
   liftIO $ parseFileOrIOWith (fasta a) mfp
 
 -- | Command line option to specify the alphabet. Used by various commands.
diff --git a/src/Translate/Translate.hs b/src/Translate/Translate.hs
--- a/src/Translate/Translate.hs
+++ b/src/Translate/Translate.hs
@@ -48,4 +48,4 @@
   ss <- readSeqs al inFile
   let result      = sequencesToFasta $ translateSeqs rf uc ss
   let outFilePath = (++ ".fasta") <$> outFileBaseName
-  io "translated sequences" result outFilePath
+  out "translated sequences" result outFilePath
