Repository: Ecogenomics/GTDBTk (language: python)

Issue:
Unset GTDBTK_DATA_PATH prevents even most basic operation
Hi there,

I just upgraded my installation to 2.2.5 via pip; unfortunately even most basic commands don't work anymore:

```
$ gtdbtk --version

================================================================================
                                     ERROR                                      
________________________________________________________________________________

          The 'GTDBTK_DATA_PATH' environment variable is not defined.           

            Please set this variable to your reference data package.            
               https://github.com/Ecogenomics/GTDBTk#installation               
================================================================================
```

```
$ gtdbtk --help

================================================================================
                                     ERROR                                      
________________________________________________________________________________

          The 'GTDBTK_DATA_PATH' environment variable is not defined.           

            Please set this variable to your reference data package.            
               https://github.com/Ecogenomics/GTDBTk#installation               
================================================================================
```

```
$ gtdbtk check_install

================================================================================
                                     ERROR                                      
________________________________________________________________________________

          The 'GTDBTK_DATA_PATH' environment variable is not defined.           

            Please set this variable to your reference data package.            
               https://github.com/Ecogenomics/GTDBTk#installation               
================================================================================
```

https://github.com/Ecogenomics/GTDBTk#installation doesn't exist (as an HTML anchor), and the 
documentation at https://ecogenomics.github.io/GTDBTk/ has nothing on setting up `GTDBTK_DATA_PATH`.

I guess basic things like `--version` and `--help` (at least) should work without this environment variable.
Missing Archaea summary when using ANI screen
Hello,

I've tested the new ANI screen method, using the mash DB, for `classify_wf`.

I've observed that I am missing a few genome at each run as well as the summary output `gtdbtl.ar53.summary.tsv`. The missing outputs correspond to Archaean genomes that were identified during the ANI screen as I can find them in `classify/ani_screen/gtdbtk.ar53.ani_summary.tsv`.

I guess implementation of the ANI screen missed the Archaea part of the pipeline ?

I am using version 2.2.6 in a conda environment created by installing GTDB-Tk from bioconda but I guess it is installation independent. Here is my command : `gtdbtk classify_wf --mash_db ./GTDB/gtdb-tk-r207v2.msh --genome_dir ./ALL/ -x fasta --out_dir gtdbtk2_classify --cpus 18 --pplacer_cpus 18 --tmpdir ./tmp --scratch_dir ./pplacer`

As it is a bit related, I was wondering if it was possible to consolidate the Archean et Bacterial summary into an unique output for the future release ?

Thank you.
Issue509



Discussion / hints:
Please try to set the `GTDBTK_DATA_PATH` as documented [here](https://ecogenomics.github.io/GTDBTk/installing/pip.html#step-3-download-and-alias-the-gtdb-tk-reference-data).


I will change the https://github.com/Ecogenomics/GTDBTk#installation URL to  https://ecogenomics.github.io/GTDBTk/installing/index.html instead.

I'll do that, but nonetheless, I'd expect basic things (`--version`, `--help`) to work anyways.



Fix patch:
diff --git a/.github/workflows/master-push.yml b/.github/workflows/master-push.yml
index 43f538a0..ccfc2a3d 100644
--- a/.github/workflows/master-push.yml
+++ b/.github/workflows/master-push.yml
@@ -33,13 +33,6 @@ jobs:
           python -m pip install --upgrade pip
           python -m pip install -r requirements.txt
 
-      - name: Extract config values
-        working-directory: ${{ github.workspace }}/master/gtdbtk/config
-        run: |
-          grep AF_THRESHOLD config.py > config2.py
-          grep PPLACER_MIN_RAM_BAC_FULL config.py >> config2.py
-          mv config2.py config.py
-
       - name: Build documentation
         working-directory: ${{ github.workspace }}/master/docs
         run: make html
diff --git a/README.md b/README.md
index b6346f72..4d49df3e 100644
--- a/README.md
+++ b/README.md
@@ -37,13 +37,9 @@ Documentation for GTDB-Tk can be found [here](https://ecogenomics.github.io/GTDB
 
 ## ✨ New Features
 
-GTDB-Tk v2.2.0+ includes the following new features:
-- GTDB-TK `classify` and `classify_wf` have changed in version 2.2.0+. There is now an ANI classification stage (`ANI screen`) that precedes classification by placement in a reference tree.
-  - **This is now the default behavior for `classify` and `classify_wf`.**
-  - In `classify`, user genomes are first compared against a Mash database comprised of all GTDB representative genomes and genome pairs of sufficient similarity processed by FastANI. User genomes classified to a GTDB representative based on FastANI results are not run through pplacer. 
-  - In the `classify_wf` workflow, genomes are classified using Mash and FastANI before executing the identify step. User genomes classified with FastANI are not run through the remainder of the pipeline (identify, align, classify).
-  - `classify_wf` and `classify` have now **an extra mutually exclusive required argument**: You can either pick `--skip_ani_screen` (to skip the ani_screening step to classify genomes using mash and FastANI) or `--mash_db` path to save/read (if exists) the Mash reference sketch database.
-  - To classify genomes without the additional `ani_screen` step, use the `--skip_ani_screen` flag.
+GTDB-Tk v2.3.0+ includes the following new features:
+- New functionality ``convert_to_species`` function to convert GTDB genome IDs to GTDB species names
+
 
 ## 📈 Performance
 Using ANI screen "can" reduce computation by >50%, although it depends on the set of input genomes. A set of input genomes consisting primarily of new species will not benefit from ANI screen as much as a set of genomes that are largely assigned to GTDB species clusters. In the latter case, the ANI screen will reduce the number of genomes that need to be classified by pplacer which reduces computation time substantially (between 25% and 60% in our testing).
diff --git a/docs/src/announcements.rst b/docs/src/announcements.rst
index 8de8008b..2a6bfdf8 100644
--- a/docs/src/announcements.rst
+++ b/docs/src/announcements.rst
@@ -1,6 +1,25 @@
 Announcements
 =============
 
+GTDB-Tk 2.3.0 available
+-----------------------
+
+*May 09, 2023*
+
+* GTDB-Tk version ``2.3.0`` is now available.
+* This version of GTDB-Tk **does not** require a new version of the GTDB-Tk reference package.
+
+
+GTDB R214 available
+-------------------
+
+*April 31, 2021*
+
+* GTDB Release 214 is now available and will be used from version ``2.3.0`` and up.
+* This version of GTDB-Tk is compatible with both release207 and release214 of the GTDB-Tk reference package.
+  `gtdbtk_r214_data.tar.gz <https://data.gtdb.ecogenomic.org/releases/release214/214.0/auxillary_files/>`_.
+
+
 GTDB-Tk 2.2.0 available
 -----------------------
 
diff --git a/docs/src/changelog.rst b/docs/src/changelog.rst
index 07c5db60..a059b5b3 100644
--- a/docs/src/changelog.rst
+++ b/docs/src/changelog.rst
@@ -2,6 +2,21 @@
 Change log
 ==========
 
+2.3.0
+-----
+
+Bug Fixes:
+
+* (`#508 <https://github.com/Ecogenomics/GTDBTk/issues/508>`_) (`#509 <https://github.com/Ecogenomics/GTDBTk/issues/509>`_) If **ALL** genomes for a specific domain are either filtered out or classified with ANI they are now reported in the summary file.
+
+Minor changes:
+
+* (`#491 <https://github.com/Ecogenomics/GTDBTk/issues/491>`_) (`#498 <https://github.com/Ecogenomics/GTDBTk/issues/498>`_) Allow GTDB-Tk to show ``--help`` and ``-v`` without ``GTDBTK_DATA_PATH`` being set.
+  * WARNING: This is a breaking change if you are importing GTDB-Tk as a library and importing values from ``gtdbtk.config.config``, instead you need to import as ``from gtdbtk.config.common import CONFIG`` then access values via ``CONFIG.<var>``
+* (`#508 <https://github.com/Ecogenomics/GTDBTk/issues/508>`_) Mash distance is changed from 0.1 to 0.15 . This is will increase the number of FastANI comparisons but will cover cases wheere genomes have a larger Mash distance but a small ANI.
+* (`#497 <https://github.com/Ecogenomics/GTDBTk/issues/497>`_) Add a ``convert_to_species`` function is GTDB-Tk to replace GCA/GCF ids with their GTDB species name
+* Add ``--db_version`` flag to ``check_install`` to check the version of previous GTDB-Tk packages.
+
 2.2.6
 -----
 
diff --git a/docs/src/installing/index.rst b/docs/src/installing/index.rst
index c9d15f14..78f0079b 100644
--- a/docs/src/installing/index.rst
+++ b/docs/src/installing/index.rst
@@ -33,12 +33,12 @@ Hardware requirements
      - Storage
      - Time
    * - Archaea
-     - ~34 GB
-     - ~65 GB
+     - ~45 GB
+     - ~85 GB
      - ~1 hour / 1,000 genomes @ 64 CPUs
    * - Bacteria
-     - ~55GB (320 GB when using --full_tree)
-     - ~65 GB
+     - ~65GB (410 GB when using --full_tree)
+     - ~85 GB
      - ~1 hour / 1,000 genomes @ 64 CPUs
 
 .. note::
@@ -117,13 +117,13 @@ Please cite these tools if you use GTDB-Tk in your work.
 GTDB-Tk reference data
 ----------------------
 
-GTDB-Tk requires ~66G of external data that needs to be downloaded and unarchived:
+GTDB-Tk requires ~84G of external data that needs to be downloaded and unarchived:
 
 .. code-block:: bash
 
-    wget https://data.gtdb.ecogenomic.org/releases/latest/auxillary_files/gtdbtk_v2_data.tar.gz
-    wget https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/auxillary_files/gtdbtk_v2_data.tar.gz  (or, mirror)
-    tar xvzf gtdbtk_v2_data.tar.gz
+    wget https://data.gtdb.ecogenomic.org/releases/latest/auxillary_files/gtdbtk_data.tar.gz
+    wget https://data.ace.uq.edu.au/public/gtdb/data/releases/latest/auxillary_files/gtdbtk_data.tar.gz  (or, mirror)
+    tar xvzf gtdbtk_data.tar.gz
 
 
 .. note:: Note that different versions of the GTDB release data may not run on all versions of GTDB-Tk, check the supported versions!
@@ -137,6 +137,10 @@ GTDB-Tk requires ~66G of external data that needs to be downloaded and unarchive
      - Minimum version
      - Maximum version
      - MD5
+   * - `R214 <https://data.gtdb.ecogenomic.org/releases/release214/214.0/auxillary_files/gtdbtk_r214_data.tar.gz>`_
+     - 2.1.0
+     - Current
+     - 630745840850c532546996b22da14c27
    * - `R207_v2 <https://data.gtdb.ecogenomic.org/releases/release207/207.0/auxillary_files/gtdbtk_r207_v2_data.tar.gz>`_
      - 2.1.0
      - Current
diff --git a/gtdbtk/__init__.py b/gtdbtk/__init__.py
index a8a6d5ec..027a3026 100644
--- a/gtdbtk/__init__.py
+++ b/gtdbtk/__init__.py
@@ -29,4 +29,4 @@
 __status__ = 'Production'
 __title__ = 'GTDB-Tk'
 __url__ = 'https://github.com/Ecogenomics/GTDBTk'
-__version__ = '2.2.6'
+__version__ = '2.3.0'
diff --git a/gtdbtk/__main__.py b/gtdbtk/__main__.py
index 8f531885..0afea986 100644
--- a/gtdbtk/__main__.py
+++ b/gtdbtk/__main__.py
@@ -49,12 +49,13 @@ def print_help():
     decorate -> Decorate tree with GTDB taxonomy
 
   Tools:
-    infer_ranks     -> Establish taxonomic ranks of internal nodes using RED
-    ani_rep         -> Calculates ANI to GTDB representative genomes
-    trim_msa        -> Trim an untrimmed MSA file based on a mask
-    export_msa      -> Export the untrimmed archaeal or bacterial MSA file
-    remove_labels   -> Remove labels (bootstrap values, node labels) from an Newick tree
-    convert_to_itol -> Convert a GTDB-Tk Newick tree to an iTOL tree
+    infer_ranks        -> Establish taxonomic ranks of internal nodes using RED
+    ani_rep            -> Calculates ANI to GTDB representative genomes
+    trim_msa           -> Trim an untrimmed MSA file based on a mask
+    export_msa         -> Export the untrimmed archaeal or bacterial MSA file
+    remove_labels      -> Remove labels (bootstrap values, node labels) from an Newick tree
+    convert_to_itol    -> Convert a GTDB-Tk Newick tree to an iTOL tree
+    convert_to_species -> Convert GTDB genome IDs to GTDB species names
  
 
   Testing:
diff --git a/gtdbtk/ani_rep.py b/gtdbtk/ani_rep.py
index d947ca0e..9d807075 100644
--- a/gtdbtk/ani_rep.py
+++ b/gtdbtk/ani_rep.py
@@ -6,8 +6,7 @@
 from gtdbtk.biolib_lite.common import canonical_gid
 from gtdbtk.biolib_lite.execute import check_dependencies
 from gtdbtk.biolib_lite.taxonomy import Taxonomy
-from gtdbtk.config.config import (TAXONOMY_FILE,
-                                  AF_THRESHOLD)
+from gtdbtk.config.common import CONFIG
 from gtdbtk.config.output import DIR_ANI_REP_INT_MASH
 from gtdbtk.exceptions import GTDBTkExit
 from gtdbtk.external.fastani import FastANI
@@ -76,7 +75,7 @@ def run(self, genomes, no_mash, mash_d, out_dir, prefix, mash_k, mash_v, mash_s,
                                                 prefix, mash_k, mash_v,
                                                 mash_s, max_mash_dist, mash_db=mash_db)
 
-        taxonomy = Taxonomy().read(TAXONOMY_FILE, canonical_ids=True)
+        taxonomy = Taxonomy().read(CONFIG.TAXONOMY_FILE, canonical_ids=True)
         ani_summary_file = ANISummaryFile(out_dir, prefix, fastani_results, taxonomy)
         ani_summary_file.write()
         ANIClosestFile(out_dir,
@@ -269,7 +268,7 @@ def _write(self):
                         fh.write(f'{gid}\t{ref_gid}')
                         fh.write(f'\t{closest_ani}\t{closest_af}')
                         fh.write(f'\t{taxonomy_str}')
-                        fh.write(f'\t{closest_ani >= gtdb_ani_radius and closest_af >= AF_THRESHOLD}\n')
+                        fh.write(f'\t{closest_ani >= gtdb_ani_radius and closest_af >= CONFIG.AF_THRESHOLD}\n')
                     else:
                         fh.write(f'{gid}\tno result\tno result\tno result\tno result\tno result\n')
                 else:
diff --git a/gtdbtk/ani_screen.py b/gtdbtk/ani_screen.py
index a2240b4f..4b461a5d 100644
--- a/gtdbtk/ani_screen.py
+++ b/gtdbtk/ani_screen.py
@@ -8,9 +8,8 @@
 from gtdbtk.classify import Classify
 from gtdbtk.config.output import DIR_ANISCREEN
 
-from gtdbtk.config.config import (TAXONOMY_FILE, MASH_SKETCH_FILE, AF_THRESHOLD)
 from gtdbtk.files.gtdb_radii import GTDBRadiiFile
-
+from gtdbtk.config.common import CONFIG
 
 class ANIScreener(object):
     """Computes a list of genomes to a list of representatives."""
@@ -39,7 +38,7 @@ def run_aniscreen(self,genomes, no_mash,out_dir,prefix, mash_k, mash_v, mash_s,
         if mash_db.endswith('/'):
             make_sure_path_exists(mash_db)
         if os.path.isdir(mash_db):
-            mash_db = os.path.join(mash_db, MASH_SKETCH_FILE)
+            mash_db = os.path.join(mash_db, CONFIG.MASH_SKETCH_FILE)
 
         #we set mash_d == mash_max_dist to avoid user to run mash with impossible values
         mash_d = mash_max_dist
@@ -49,7 +48,7 @@ def run_aniscreen(self,genomes, no_mash,out_dir,prefix, mash_k, mash_v, mash_s,
         fastani_results = ani_rep.run_mash_fastani(genomes, no_mash, mash_d, os.path.join(out_dir, DIR_ANISCREEN),
                                                     prefix, mash_k, mash_v, mash_s, mash_max_dist, mash_db)
 
-        taxonomy = Taxonomy().read(TAXONOMY_FILE, canonical_ids=True)
+        taxonomy = Taxonomy().read(CONFIG.TAXONOMY_FILE, canonical_ids=True)
 
         mash_classified_user_genomes = self.sort_fastani_ani_screen(
              fastani_results,taxonomy)
@@ -88,7 +87,7 @@ def sort_fastani_ani_screen(self,fastani_results,taxonomy,bac_ar_diff=None):
         # sort the dictionary by ani then af
         for gid in fastani_results.keys():
             thresh_results = [(ref_gid, hit) for (ref_gid, hit) in fastani_results[gid].items() if
-                              hit['af'] >= AF_THRESHOLD and hit['ani'] >= self.gtdb_radii.get_rep_ani(
+                              hit['af'] >= CONFIG.AF_THRESHOLD and hit['ani'] >= self.gtdb_radii.get_rep_ani(
                                   canonical_gid(ref_gid))]
             all_results = [(ref_gid, hit) for (ref_gid, hit) in fastani_results[gid].items()]
             closest = sorted(thresh_results, key=lambda x: (-x[1]['ani'], -x[1]['af']))
diff --git a/gtdbtk/biolib_lite/logger.py b/gtdbtk/biolib_lite/logger.py
index e15ef146..593c4650 100644
--- a/gtdbtk/biolib_lite/logger.py
+++ b/gtdbtk/biolib_lite/logger.py
@@ -23,7 +23,7 @@
 
 from tqdm import tqdm
 
-from gtdbtk.config.config import LOG_TASK
+from gtdbtk.config.common import CONFIG
 from .common import make_sure_path_exists
 
 
@@ -128,7 +128,7 @@ class SpecialFormatter(logging.Formatter):
                                      datefmt="%Y-%m-%d %H:%M:%S")
 
         def format(self, record):
-            if record.levelno == LOG_TASK:
+            if record.levelno == CONFIG.LOG_TASK:
                 return self.task_fmt.format(record)
             if record.levelno >= logging.ERROR:
                 return self.err_fmt.format(record)
@@ -162,7 +162,7 @@ class ColourlessFormatter(SpecialFormatter):
 
         def format(self, record):
             record.msg = self.ansi_escape.sub('', record.msg)
-            if record.levelno == LOG_TASK:
+            if record.levelno == CONFIG.LOG_TASK:
                 return self.task_fmt.format(record)
             if record.levelno >= logging.ERROR:
                 return self.err_fmt.format(record)
diff --git a/gtdbtk/classify.py b/gtdbtk/classify.py
index ad6a915e..4301912e 100644
--- a/gtdbtk/classify.py
+++ b/gtdbtk/classify.py
@@ -28,7 +28,7 @@
 
 from numpy import median as np_median
 
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 from gtdbtk.ani_rep import ANIRep, ANISummaryFile
 from gtdbtk.biolib_lite.common import make_sure_path_exists,canonical_gid
 from gtdbtk.biolib_lite.execute import check_dependencies
@@ -69,8 +69,8 @@ def __init__(self, cpus=1, pplacer_cpus=None, af_threshold=None,skip_pplacer=Fal
 
         self.skip_pplacer = skip_pplacer
 
-        self.taxonomy_file = Config.TAXONOMY_FILE
-        self.af_threshold = af_threshold if af_threshold else Config.AF_THRESHOLD
+        self.taxonomy_file = CONFIG.TAXONOMY_FILE
+        self.af_threshold = af_threshold if af_threshold else CONFIG.AF_THRESHOLD
         self.gtdb_taxonomy = Taxonomy().read(self.taxonomy_file)
 
         self.order_rank = ["d__", "p__", "c__", "o__", 'f__', 'g__', 's__']
@@ -110,7 +110,7 @@ def __init__(self, cpus=1, pplacer_cpus=None, af_threshold=None,skip_pplacer=Fal
     @staticmethod
     def parse_radius_file():
         results = {}
-        with open(Config.RADII_FILE) as f:
+        with open(CONFIG.RADII_FILE) as f:
             for line in f:
                 infos = line.strip().split('\t')
                 gid = infos[1]
@@ -159,16 +159,16 @@ def place_genomes(self,
         mem_gb = get_memory_gb()
         if mem_gb is not None:
             mem_total = mem_gb['MemTotal']
-            if marker_set_id == 'bac120' and levelopt is None and mem_total < Config.PPLACER_MIN_RAM_BAC_FULL:
-                self.logger.warning(mem_warning.format(req_gb=Config.PPLACER_MIN_RAM_BAC_FULL,
+            if marker_set_id == 'bac120' and levelopt is None and mem_total < CONFIG.PPLACER_MIN_RAM_BAC_FULL:
+                self.logger.warning(mem_warning.format(req_gb=CONFIG.PPLACER_MIN_RAM_BAC_FULL,
                                                        domain='bacterial',
                                                        cur_gb=mem_total))
-            if marker_set_id == 'bac120' and levelopt == 'high' and mem_total < Config.PPLACER_MIN_RAM_BAC_SPLIT:
-                self.logger.warning(mem_warning.format(req_gb=Config.PPLACER_MIN_RAM_BAC_SPLIT,
+            if marker_set_id == 'bac120' and levelopt == 'high' and mem_total < CONFIG.PPLACER_MIN_RAM_BAC_SPLIT:
+                self.logger.warning(mem_warning.format(req_gb=CONFIG.PPLACER_MIN_RAM_BAC_SPLIT,
                                                        domain='bacterial',
                                                        cur_gb=mem_total))
-            elif marker_set_id == 'ar53' and mem_total < Config.PPLACER_MIN_RAM_ARC:
-                self.logger.warning(mem_warning.format(req_gb=Config.PPLACER_MIN_RAM_ARC,
+            elif marker_set_id == 'ar53' and mem_total < CONFIG.PPLACER_MIN_RAM_ARC:
+                self.logger.warning(mem_warning.format(req_gb=CONFIG.PPLACER_MIN_RAM_ARC,
                                                        domain='archaeal',
                                                        cur_gb=mem_total))
 
@@ -200,35 +200,35 @@ def place_genomes(self,
         pplacer_ref_pkg = None
         if marker_set_id == 'bac120':
             if levelopt is None:
-                self.logger.log(Config.LOG_TASK,
+                self.logger.log(CONFIG.LOG_TASK,
                                 f'Placing {num_genomes:,} bacterial genomes '
                                 f'into reference tree with pplacer using '
                                 f'{self.pplacer_cpus} CPUs (be patient).')
-                pplacer_ref_pkg = os.path.join(Config.PPLACER_DIR,
-                                               Config.PPLACER_BAC120_REF_PKG)
+                pplacer_ref_pkg = os.path.join(CONFIG.PPLACER_DIR,
+                                               CONFIG.PPLACER_BAC120_REF_PKG)
 
             elif levelopt == 'high':
-                self.logger.log(Config.LOG_TASK,
+                self.logger.log(CONFIG.LOG_TASK,
                                 f'Placing {num_genomes:,} bacterial genomes '
                                 f'into backbone reference tree with pplacer using '
                                 f'{self.pplacer_cpus} CPUs (be patient).')
-                pplacer_ref_pkg = os.path.join(Config.BACKBONE_PPLACER_DIR,
-                                               Config.BACKBONE_PPLACER_REF_PKG)
+                pplacer_ref_pkg = os.path.join(CONFIG.BACKBONE_PPLACER_DIR,
+                                               CONFIG.BACKBONE_PPLACER_REF_PKG)
             elif levelopt == 'low':
-                self.logger.log(Config.LOG_TASK,
+                self.logger.log(CONFIG.LOG_TASK,
                                 f'Placing {num_genomes:,} bacterial genomes '
                                 f'into class-level reference tree {tree_iter} ({idx_tree}/{number_low_trees}) with '
                                 f'pplacer using {self.pplacer_cpus} CPUs '
                                 f'(be patient).')
-                pplacer_ref_pkg = os.path.join(Config.CLASS_LEVEL_PPLACER_DIR,
-                                               Config.CLASS_LEVEL_PPLACER_REF_PKG.format(iter=tree_iter))
+                pplacer_ref_pkg = os.path.join(CONFIG.CLASS_LEVEL_PPLACER_DIR,
+                                               CONFIG.CLASS_LEVEL_PPLACER_REF_PKG.format(iter=tree_iter))
         elif marker_set_id == 'ar53':
-            self.logger.log(Config.LOG_TASK,
+            self.logger.log(CONFIG.LOG_TASK,
                             f'Placing {num_genomes:,} archaeal genomes into '
                             f'reference tree with pplacer using '
                             f'{self.pplacer_cpus} CPUs (be patient).')
-            pplacer_ref_pkg = os.path.join(Config.PPLACER_DIR,
-                                           Config.PPLACER_AR53_REF_PKG)
+            pplacer_ref_pkg = os.path.join(CONFIG.PPLACER_DIR,
+                                           CONFIG.PPLACER_AR53_REF_PKG)
         else:
             raise GenomeMarkerSetUnknown(f'Unknown marker set: {marker_set_id}')
 
@@ -318,7 +318,7 @@ def parser_marker_summary_file(self, marker_summary_fh):
         for gid, marker_dict in marker_summary_fh.genomes.items():
             multi_hits_percent = (100 * len(marker_dict['mul'])) / \
                                  len(marker_summary_fh.marker_names)
-            if multi_hits_percent >= Config.DEFAULT_MULTIHIT_THRESHOLD:
+            if multi_hits_percent >= CONFIG.DEFAULT_MULTIHIT_THRESHOLD:
                 results[gid] = round(multi_hits_percent, 1)
         return results
 
@@ -333,10 +333,10 @@ def run(self,
             skip_ani_screen=False,
             genes=False,
             no_mash=False,
-            mash_k=Config.MASH_K_VALUE,
-            mash_v=Config.MASH_V_VALUE,
-            mash_s=Config.MASH_S_VALUE,
-            mash_max_dist=Config.MASH_MAX_DISTANCE,
+            mash_k=CONFIG.MASH_K_VALUE,
+            mash_v=CONFIG.MASH_V_VALUE,
+            mash_s=CONFIG.MASH_S_VALUE,
+            mash_max_dist=CONFIG.MASH_MAX_DISTANCE,
             mash_db=None,
             ani_summary_files=None,
             all_classified_ani=False):
@@ -360,7 +360,7 @@ def run(self,
                 if mash_db.endswith('/'):
                     make_sure_path_exists(mash_db)
                 if os.path.isdir(mash_db):
-                    mash_db = os.path.join(mash_db, Config.MASH_SKETCH_FILE)
+                    mash_db = os.path.join(mash_db, CONFIG.MASH_SKETCH_FILE)
 
             # we set mash_d == mash_max_dist to avoid user to run mash with impossible values
             mash_d = mash_max_dist
@@ -455,23 +455,45 @@ def run(self,
                 if (not os.path.exists(user_msa_file)) or (os.path.getsize(user_msa_file) < 30):
                     # file will not exist if there are no User genomes from a given domain
                     #
+                    if marker_set_id == 'ar53':
+                        # we still add the filtered genomes to the summary file
+                        # add filtered genomes to the summary file
+                        warning_counter = self.add_filtered_genomes_to_summary(align_dir, warning_counter, summary_file,
+                                                                               marker_set_id, prefix)
+
                     # But if there is Unclassified genomes without domain,
                     # they still have to be written in the bac120 summary file:
-                    if marker_set_id == 'bac120':
+                    elif marker_set_id == 'bac120':
                         # Add failed genomes from prodigal and genomes with no markers in the bac120 summary file
                         # This is an executive direction: failed prodigal and genomes with no markers are not bacterial or archaeal
                         # but they need to be included in one of the summary file
                         prodigal_failed_counter = self.add_failed_genomes_to_summary(align_dir, summary_file, prefix)
-                        if summary_file.has_row():
-                            summary_file.write()
-                            output_files.setdefault(marker_set_id, []).append(summary_file.path)
-                            # Symlink to the summary file from the root
+                        # we also add the filtered genomes to the summary file
+                        # add filtered genomes to the summary file
+                        warning_counter = self.add_filtered_genomes_to_summary(align_dir, warning_counter, summary_file,
+                                                                               marker_set_id, prefix)
+
+                    # we add all genomes classified with ANI
+                    if mash_classified_user_genomes and marker_set_id in mash_classified_user_genomes:
+                        list_summary_rows = mash_classified_user_genomes.get(marker_set_id)
+                        for row in list_summary_rows:
+                            summary_file.add_row(row)
+
+                    if summary_file.has_row():
+                        summary_file.write()
+                        output_files.setdefault(marker_set_id, []).append(summary_file.path)
+                        # Symlink to the summary file from the root
+                        if marker_set_id == 'ar53':
+                            symlink_f(PATH_AR53_SUMMARY_OUT.format(prefix=prefix),
+                                      os.path.join(out_dir, os.path.basename(PATH_AR53_SUMMARY_OUT.format(prefix=prefix))))
+                        elif marker_set_id == 'bac120':
                             symlink_f(PATH_BAC120_SUMMARY_OUT.format(prefix=prefix),
                                       os.path.join(out_dir, os.path.basename(PATH_BAC120_SUMMARY_OUT.format(prefix=prefix))))
-                            if prodigal_failed_counter > 0:
-                                self.logger.warning(f"{prodigal_failed_counter} of {len(genomes)} "
-                                                    f"genome{'' if prodigal_failed_counter == 1 else 's'} "
-                                                    f"ha{'s' if prodigal_failed_counter == 1 else 've'} been labeled as 'Unclassified'.")
+                        if prodigal_failed_counter > 0:
+                            self.logger.warning(f"{prodigal_failed_counter} of {len(genomes)} "
+                                                f"genome{'' if prodigal_failed_counter == 1 else 's'} "
+                                                f"ha{'s' if prodigal_failed_counter == 1 else 've'} been labeled as 'Unclassified'.")
+
 
                     continue
 
@@ -560,7 +582,7 @@ def run(self,
 
                     tree_mapping_dict = {}
                     tree_mapping_dict_reverse = {}
-                    with open(Config.CLASS_LEVEL_TREE_MAPPING_FILE) as ltmf:
+                    with open(CONFIG.CLASS_LEVEL_TREE_MAPPING_FILE) as ltmf:
                         for line in ltmf:
                             k, v = line.strip().split()
                             tree_mapping_dict[k] = v
@@ -1163,7 +1185,7 @@ def _parse_tree(self, tree, genomes, msa_dict, percent_multihit_dict,genes, tran
         # Persist descendant information for efficient traversal.
         tt = TreeTraversal()
 
-        self.logger.log(Config.LOG_TASK, 'Traversing tree to determine classification method.')
+        self.logger.log(CONFIG.LOG_TASK, 'Traversing tree to determine classification method.')
         if genes:
             fastani_verification = {}
         else:
@@ -1179,7 +1201,7 @@ def _parse_tree(self, tree, genomes, msa_dict, percent_multihit_dict,genes, tran
             fastani = FastANI(cpus=self.cpus, force_single=True)
             d_ani_compare, d_paths = self._get_fastani_genome_path(
                 fastani_verification, genomes)
-            self.logger.log(Config.LOG_TASK,
+            self.logger.log(CONFIG.LOG_TASK,
                             f'Calculating average nucleotide identity using '
                             f'FastANI (v{fastani.version}).')
             all_fastani_dict = fastani.run(d_ani_compare, d_paths)
@@ -1247,13 +1269,13 @@ def _assign_mrca_red(self, input_tree, marker_set_id, levelopt=None, tree_iter=N
         tt = TreeTraversal()
 
         if levelopt is None:
-            red_file = Config.MRCA_RED_BAC120
+            red_file = CONFIG.MRCA_RED_BAC120
         elif levelopt == 'high':
-            red_file = Config.BACKBONE_RED_FILE
+            red_file = CONFIG.BACKBONE_RED_FILE
         elif levelopt == 'low':
-            red_file = Config.CLASS_LEVEL_RED_FILE.format(iter=tree_iter)
+            red_file = CONFIG.CLASS_LEVEL_RED_FILE.format(iter=tree_iter)
         if marker_set_id == 'ar53':
-            red_file = Config.MRCA_RED_AR53
+            red_file = CONFIG.MRCA_RED_AR53
 
         # create map from leave labels to tree nodes
         leaf_node_map = {}
@@ -1367,16 +1389,17 @@ def add_filtered_genomes_to_summary(self, align_dir,warning_counter, summary_fil
         else:
             filtered_file = os.path.join(align_dir,PATH_AR53_FILTERED_GENOMES.format(prefix=prefix))
             domain = 'Archaea'
-
-        with open(filtered_file) as fin:
-            for line in fin:
-                infos = line.strip().split('\t')
-                summary_row = ClassifySummaryFileRow()
-                summary_row.gid = infos[0]
-                summary_row.classification = f'Unclassified {domain}'
-                summary_row.warnings = infos[1]
-                summary_file.add_row(summary_row)
-                warning_counter += 1
+        # if file exists:
+        if os.path.exists(filtered_file):
+            with open(filtered_file) as fin:
+                for line in fin:
+                    infos = line.strip().split('\t')
+                    summary_row = ClassifySummaryFileRow()
+                    summary_row.gid = infos[0]
+                    summary_row.classification = f'Unclassified {domain}'
+                    summary_row.warnings = infos[1]
+                    summary_file.add_row(summary_row)
+                    warning_counter += 1
         return warning_counter
 
     def add_failed_genomes_to_summary(self, align_dir, summary_file, prefix):
@@ -1442,7 +1465,7 @@ def _sort_fastani_results_pre_pplacer(self,fastani_results,bac_ar_diff):
         # sort the dictionary by ani then af
         for gid in fastani_results.keys():
             thresh_results = [(ref_gid, hit) for (ref_gid, hit) in fastani_results[gid].items() if
-                              hit['af'] >= Config.AF_THRESHOLD and hit['ani'] >= self.gtdb_radii.get_rep_ani(
+                              hit['af'] >= CONFIG.AF_THRESHOLD and hit['ani'] >= self.gtdb_radii.get_rep_ani(
                                   canonical_gid(ref_gid))]
             closest = sorted(thresh_results, key=lambda x: (-x[1]['ani'], -x[1]['af']))
             if len(closest) > 0:
@@ -1807,15 +1830,15 @@ def _calculate_red_distances(self, input_tree, out_dir):
                                            preserve_underscores=True)
 
         self.logger.info('Reading taxonomy from file.')
-        taxonomy = Taxonomy().read(Config.TAXONOMY_FILE)
+        taxonomy = Taxonomy().read(CONFIG.TAXONOMY_FILE)
 
         # determine taxa to be used for inferring distribution
         trusted_taxa = None
         taxa_for_dist_inference = self._filter_taxa_for_dist_inference(tree,
                                                                        taxonomy,
                                                                        trusted_taxa,
-                                                                       Config.RED_MIN_CHILDREN,
-                                                                       Config.RED_MIN_SUPPORT)
+                                                                       CONFIG.RED_MIN_CHILDREN,
+                                                                       CONFIG.RED_MIN_SUPPORT)
 
         phylum_rel_dists, rel_node_dists = self.median_rd_over_phyla(tree,
                                                                      taxa_for_dist_inference,
@@ -2153,14 +2176,14 @@ def _get_fastani_genome_path(self, fastani_verification, genomes):
                 # TODEL UBA genomes
                 if shortleaf.startswith("UBA"):
                     ref_path = os.path.join(
-                        Config.FASTANI_GENOMES,
+                        CONFIG.FASTANI_GENOMES,
                         'UBA',
-                        shortleaf + Config.FASTANI_GENOMES_EXT)
+                        shortleaf + CONFIG.FASTANI_GENOMES_EXT)
                 else:
                     ref_path = os.path.join(
-                        Config.FASTANI_GENOMES,
+                        CONFIG.FASTANI_GENOMES,
                         self.parse_leaf_to_dir_path(shortleaf),
-                        shortleaf + Config.FASTANI_GENOMES_EXT)
+                        shortleaf + CONFIG.FASTANI_GENOMES_EXT)
 
                 if not os.path.isfile(ref_path):
                     raise GTDBTkExit(f'Reference genome missing from FastANI database: {ref_path}')
diff --git a/gtdbtk/cli.py b/gtdbtk/cli.py
index 0b9e94f1..739e1160 100644
--- a/gtdbtk/cli.py
+++ b/gtdbtk/cli.py
@@ -4,8 +4,7 @@
 
 from gtdbtk.biolib_lite.custom_help_formatter import ChangeTempAction
 from gtdbtk.biolib_lite.custom_help_formatter import CustomHelpFormatter
-from gtdbtk.config.config import AF_THRESHOLD, PPLACER_MIN_RAM_BAC_FULL, MASH_K_VALUE, MASH_S_VALUE, MASH_D_VALUE, \
-    MASH_V_VALUE, MASH_MAX_DISTANCE
+from gtdbtk.config.common import CONFIG
 
 
 @contextmanager
@@ -63,7 +62,7 @@ def __bacteria(group):
 def __outgroup_taxon(group, required):
     group.add_argument('--outgroup_taxon', type=str, default=None, required=required,
                        help="taxon to use as outgroup (e.g., "
-                            "``p__Patescibacteria`` or ``p__Altarchaeota``)")
+                            "``p__Patescibacteria`` or ``p__Altiarchaeota``)")
 
 
 def __out_dir(group, required):
@@ -205,7 +204,7 @@ def __scratch_dir(group):
 def __full_tree(group):
     group.add_argument('-f', '--full_tree', default=False, action='store_true',
                        help='use the unsplit bacterial tree for the classify step; this is the original GTDB-Tk '
-                            f'approach (version < 2) and requires more than {PPLACER_MIN_RAM_BAC_FULL} GB of RAM to load the reference tree')
+                            f'approach (version < 2) and requires more than {CONFIG.PPLACER_MIN_RAM_BAC_FULL} GB of RAM to load the reference tree')
 
 
 def __identify_dir(group, required):
@@ -255,26 +254,26 @@ def __no_mash(group):
 
 
 def __mash_k(group):
-    group.add_argument('--mash_k', default=MASH_K_VALUE, type=int,
+    group.add_argument('--mash_k', default=CONFIG.MASH_K_VALUE, type=int,
                        help='k-mer size [1-32]')
 
 
 def __mash_s(group):
-    group.add_argument('--mash_s', default=MASH_S_VALUE, type=int,
+    group.add_argument('--mash_s', default=CONFIG.MASH_S_VALUE, type=int,
                        help='maximum number of non-redundant hashes')
 
 
 def __mash_d(group):
-    group.add_argument('--mash_d', default=MASH_D_VALUE, type=float,
+    group.add_argument('--mash_d', default=CONFIG.MASH_D_VALUE, type=float,
                        help='maximum distance to keep [0-1]')
 
 
 def __mash_v(group):
-    group.add_argument('--mash_v', default=MASH_V_VALUE, type=float,
+    group.add_argument('--mash_v', default=CONFIG.MASH_V_VALUE, type=float,
                        help='maximum p-value to keep [0-1]')
 
 def __mash_max_distance(group):
-    group.add_argument('--mash_max_distance', default=MASH_MAX_DISTANCE, type=float,
+    group.add_argument('--mash_max_distance', default=CONFIG.MASH_MAX_DISTANCE, type=float,
                        help='Maximum Mash distance to select a potential GTDB genome as representative '
                             'of a user genome.')
 
@@ -284,7 +283,7 @@ def __mash_db(group):
 
 
 def __min_af(group):
-    group.add_argument('--min_af', type=float, default=AF_THRESHOLD,
+    group.add_argument('--min_af', type=float, default=CONFIG.AF_THRESHOLD,
                        help='minimum alignment fraction to assign genome to a species cluster')
 
 
@@ -318,6 +317,14 @@ def __domain(group, required):
     group.add_argument('--domain', required=required, choices=['arc', 'bac'],
                        help="domain to export")
 
+def __all_ranks(group):
+    group.add_argument('--all_ranks', default=False, action='store_true',
+                       help='add all missing ranks to the leaf nodes if they are present in the reference tree.')
+
+def __db_version(group):
+    group.add_argument('--db_version', type = int, default = None,
+                       help="GTDB-Tk version package to test for compatibility.")
+
 
 def __write_single_copy_genes(group):
     group.add_argument('--write_single_copy_genes', default=False, action='store_true',
@@ -586,6 +593,17 @@ def get_main_parser():
             __debug(grp)
             __help(grp)
 
+    # Convert genome ids to species names.
+    with subparser(sub_parsers, 'convert_to_species', 'Replace GTDB genomes ids with GTDB Species name.') as parser:
+        with arg_group(parser, 'required named arguments') as grp:
+            __input_tree(grp, required=True)
+            __output_tree(grp, required=True)
+        with arg_group(parser, 'optional arguments') as grp:
+            __custom_taxonomy_file(grp)
+            __all_ranks(grp)
+            __debug(grp)
+            __help(grp)
+
     # Export MSA.
     with subparser(sub_parsers, 'export_msa', 'Export the untrimmed archaeal or bacterial MSA file.') as parser:
         with arg_group(parser, 'required named arguments') as grp:
@@ -599,6 +617,7 @@ def get_main_parser():
     with subparser(sub_parsers, 'check_install', 'Verify third party programs and '
                                                  'GTDB reference package.') as parser:
         with arg_group(parser, 'optional arguments') as grp:
+            __db_version(grp)
             __debug(grp)
             __help(grp)
 
diff --git a/gtdbtk/config/common.py b/gtdbtk/config/common.py
new file mode 100644
index 00000000..8a18e90f
--- /dev/null
+++ b/gtdbtk/config/common.py
@@ -0,0 +1,370 @@
+import json
+import os
+import sys
+from functools import lru_cache
+
+
+class __GTDBTkCommonConfig:
+    """
+    This class encapsulates all configuration options. It will protect against
+    importing code that depends on a specific value throwing an exception
+    that requires the setting of the GTDB-Tk reference data path.
+    """
+
+    MIN_REF_DATA_VERSION = 'r207'
+    COMPATIBLE_REF_DATA_VERSIONS = ['r207','r214']
+
+    BACKBONE_PPLACER_REF_PKG = 'gtdbtk_package_backbone.refpkg'
+    CLASS_LEVEL_PPLACER_REF_PKG = 'gtdbtk.package.{iter}.refpkg'
+
+    # Relative Evolution Distance
+    RED_INTERVAL = 0.1
+    RED_MIN_SUPPORT = 0.0
+    RED_MIN_CHILDREN = 2
+
+    # Marker information
+    BAC120_MARKERS = {"PFAM": ["PF00380.20.hmm", "PF00410.20.hmm", "PF00466.21.hmm",
+                               "PF01025.20.hmm", "PF02576.18.hmm", "PF03726.15.hmm"],
+                      "TIGRFAM": ["TIGR00006.HMM", "TIGR00019.HMM", "TIGR00020.HMM",
+                                  "TIGR00029.HMM", "TIGR00043.HMM", "TIGR00054.HMM",
+                                  "TIGR00059.HMM", "TIGR00061.HMM", "TIGR00064.HMM",
+                                  "TIGR00065.HMM", "TIGR00082.HMM", "TIGR00083.HMM",
+                                  "TIGR00084.HMM", "TIGR00086.HMM", "TIGR00088.HMM",
+                                  "TIGR00090.HMM", "TIGR00092.HMM", "TIGR00095.HMM",
+                                  "TIGR00115.HMM", "TIGR00116.HMM", "TIGR00138.HMM",
+                                  "TIGR00158.HMM", "TIGR00166.HMM", "TIGR00168.HMM",
+                                  "TIGR00186.HMM", "TIGR00194.HMM", "TIGR00250.HMM",
+                                  "TIGR00337.HMM", "TIGR00344.HMM", "TIGR00362.HMM",
+                                  "TIGR00382.HMM", "TIGR00392.HMM", "TIGR00396.HMM",
+                                  "TIGR00398.HMM", "TIGR00414.HMM", "TIGR00416.HMM",
+                                  "TIGR00420.HMM", "TIGR00431.HMM", "TIGR00435.HMM",
+                                  "TIGR00436.HMM", "TIGR00442.HMM", "TIGR00445.HMM",
+                                  "TIGR00456.HMM", "TIGR00459.HMM", "TIGR00460.HMM",
+                                  "TIGR00468.HMM", "TIGR00472.HMM", "TIGR00487.HMM",
+                                  "TIGR00496.HMM", "TIGR00539.HMM", "TIGR00580.HMM",
+                                  "TIGR00593.HMM", "TIGR00615.HMM", "TIGR00631.HMM",
+                                  "TIGR00634.HMM", "TIGR00635.HMM", "TIGR00643.HMM",
+                                  "TIGR00663.HMM", "TIGR00717.HMM", "TIGR00755.HMM",
+                                  "TIGR00810.HMM", "TIGR00922.HMM", "TIGR00928.HMM",
+                                  "TIGR00959.HMM", "TIGR00963.HMM", "TIGR00964.HMM",
+                                  "TIGR00967.HMM", "TIGR01009.HMM", "TIGR01011.HMM",
+                                  "TIGR01017.HMM", "TIGR01021.HMM", "TIGR01029.HMM",
+                                  "TIGR01032.HMM", "TIGR01039.HMM", "TIGR01044.HMM",
+                                  "TIGR01059.HMM", "TIGR01063.HMM", "TIGR01066.HMM",
+                                  "TIGR01071.HMM", "TIGR01079.HMM", "TIGR01082.HMM",
+                                  "TIGR01087.HMM", "TIGR01128.HMM", "TIGR01146.HMM",
+                                  "TIGR01164.HMM", "TIGR01169.HMM", "TIGR01171.HMM",
+                                  "TIGR01302.HMM", "TIGR01391.HMM", "TIGR01393.HMM",
+                                  "TIGR01394.HMM", "TIGR01510.HMM", "TIGR01632.HMM",
+                                  "TIGR01951.HMM", "TIGR01953.HMM", "TIGR02012.HMM",
+                                  "TIGR02013.HMM", "TIGR02027.HMM", "TIGR02075.HMM",
+                                  "TIGR02191.HMM", "TIGR02273.HMM", "TIGR02350.HMM",
+                                  "TIGR02386.HMM", "TIGR02397.HMM", "TIGR02432.HMM",
+                                  "TIGR02729.HMM", "TIGR03263.HMM", "TIGR03594.HMM",
+                                  "TIGR03625.HMM", "TIGR03632.HMM", "TIGR03654.HMM",
+                                  "TIGR03723.HMM", "TIGR03725.HMM", "TIGR03953.HMM"]}
+
+    # New Version of AR53_MARKERS
+    AR53_MARKERS = {"PFAM": ["PF04919.13.hmm", "PF07541.13.hmm", "PF01000.27.hmm",
+                             "PF00687.22.hmm", "PF00466.21.hmm", "PF00827.18.hmm", "PF01280.21.hmm", "PF01090.20.hmm",
+                             "PF01200.19.hmm", "PF01015.19.hmm", "PF00900.21.hmm", "PF00410.20.hmm"],
+                    "TIGRFAM": ["TIGR00037.HMM", "TIGR00064.HMM", "TIGR00111.HMM",
+                                "TIGR00134.HMM", "TIGR00279.HMM", "TIGR00291.HMM", "TIGR00323.HMM",
+                                "TIGR00335.HMM", "TIGR00373.HMM", "TIGR00405.HMM", "TIGR00448.HMM",
+                                "TIGR00483.HMM", "TIGR00491.HMM", "TIGR00522.HMM", "TIGR00967.HMM",
+                                "TIGR00982.HMM", "TIGR01008.HMM", "TIGR01012.HMM", "TIGR01018.HMM",
+                                "TIGR01020.HMM", "TIGR01028.HMM", "TIGR01046.HMM", "TIGR01052.HMM",
+                                "TIGR01171.HMM", "TIGR01213.HMM", "TIGR01952.HMM", "TIGR02236.HMM",
+                                "TIGR02338.HMM", "TIGR02389.HMM", "TIGR02390.HMM", "TIGR03626.HMM",
+                                "TIGR03627.HMM", "TIGR03628.HMM", "TIGR03629.HMM", "TIGR03670.HMM",
+                                "TIGR03671.HMM", "TIGR03672.HMM", "TIGR03673.HMM", "TIGR03674.HMM",
+                                "TIGR03676.HMM", "TIGR03680.HMM"]}
+
+    # Information for Multiple hits markers:
+    DEFAULT_MULTIHIT_THRESHOLD = 10.0
+
+    # Information for aligning genomes
+    DEFAULT_DOMAIN_THRESHOLD = 10.0
+    AR_MARKER_COUNT = 53
+    BAC_MARKER_COUNT = 120
+
+    # Information about alignment Fraction to resolve fastANI results
+    AF_THRESHOLD = 0.5
+
+    PPLACER_MIN_RAM_BAC_FULL = 320
+    PPLACER_MIN_RAM_BAC_SPLIT = 55
+    PPLACER_MIN_RAM_ARC = 40
+
+    FASTANI_SPECIES_THRESHOLD = 95.0
+    FASTANI_GENOMES_EXT = "_genomic.fna.gz"
+
+    # Mash configuration
+    MASH_SKETCH_FILE = 'gtdb_ref_sketch.msh'
+    MASH_K_VALUE = 16
+    MASH_S_VALUE = 5000
+    MASH_MAX_DISTANCE = 0.15
+    MASH_D_VALUE = MASH_MAX_DISTANCE
+    MASH_V_VALUE = 1.0
+
+    # Config values for checking GTDB-Tk on startup.
+    GTDBTK_VER_CHECK = True
+    GTDBTK_VER_TIMEOUT = 3  # seconds
+
+    # Internal settings used for logging.
+    LOG_TASK = 21
+
+    # To avoid multiple hits of parsing files
+    _generic_path = None
+    _red_dist_bac_dict = None
+    _red_dist_arc_dict = None
+    _version_data = None
+
+    @property
+    def GENERIC_PATH(self):
+        if self._generic_path is None:
+            try:
+                # expandvars is required to transform things like $HOME
+                out = os.path.expandvars(os.environ['GTDBTK_DATA_PATH'])
+                self._generic_path = out
+            except KeyError:
+                print('\n' + '=' * 80)
+                print(' ERROR '.center(80))
+                print('_' * 80 + '\n')
+                print("The 'GTDBTK_DATA_PATH' environment variable is not defined.".center(80) + '\n')
+                print('Please set this variable to your reference data package.'.center(80))
+                print('https://ecogenomics.github.io/GTDBTk/installing/index.html'.center(80))
+                print('=' * 80)
+                sys.exit(1)
+        return self._generic_path
+
+    @property
+    def MSA_FOLDER(self):
+        return os.path.join(self.GENERIC_PATH, 'msa/')
+
+    @property
+    def MASK_DIR(self):
+        return os.path.join(self.GENERIC_PATH, 'masks/')
+
+    @property
+    def PPLACER_DIR(self):
+        return os.path.join(self.GENERIC_PATH, 'pplacer/')
+
+    @property
+    def FASTANI_DIR(self):
+        return os.path.join(self.GENERIC_PATH, 'fastani/')
+
+    @property
+    def MASH_DIR(self):
+        return os.path.join(self.GENERIC_PATH, 'mash/')
+
+    @property
+    def TAX_FOLDER(self):
+        return os.path.join(self.GENERIC_PATH, 'taxonomy/')
+
+    @property
+    def RADII_DIR(self):
+        return os.path.join(self.GENERIC_PATH, 'radii/')
+
+    @property
+    def METADATA_DIR(self):
+        return os.path.join(self.GENERIC_PATH, 'metadata/')
+
+    @property
+    def RED_DIR(self):
+        return os.path.join(self.GENERIC_PATH, "mrca_red/")
+
+    @property
+    def MARKER_DIR(self):
+        return os.path.join(self.GENERIC_PATH, 'markers/')
+
+    @property
+    def TIGRFAM_HMMS(self):
+        return os.path.join(self.MARKER_DIR, 'tigrfam/tigrfam.hmm')
+
+    @property
+    def PFAM_HMM_DIR(self):
+        return os.path.join(self.MARKER_DIR, 'pfam/')
+
+    @property
+    def SPLIT_DIR(self):
+        return os.path.join(self.GENERIC_PATH, 'split')
+
+    @property
+    def BACKBONE_SPLIT_DIR(self):
+        return os.path.join(self.SPLIT_DIR, 'backbone')
+
+    @property
+    def CLASS_LEVEL_SPLIT_DIR(self):
+        return os.path.join(self.SPLIT_DIR, 'class_level')
+
+    @property
+    def BACKBONE_PPLACER_DIR(self):
+        return os.path.join(self.BACKBONE_SPLIT_DIR, 'pplacer')
+
+    @property
+    def CLASS_LEVEL_PPLACER_DIR(self):
+        return os.path.join(self.CLASS_LEVEL_SPLIT_DIR, 'pplacer')
+
+    @property
+    def BACKBONE_RED_DIR(self):
+        return os.path.join(self.BACKBONE_SPLIT_DIR, 'red')
+
+    @property
+    def CLASS_LEVEL_RED_DIR(self):
+        return os.path.join(self.CLASS_LEVEL_SPLIT_DIR, 'red')
+
+    @property
+    def CLASS_LEVEL_TREE_MAPPING_FILE(self):
+        return os.path.join(self.CLASS_LEVEL_SPLIT_DIR, 'tree_mapping.tsv')
+
+    @property
+    def BACKBONE_RED_FILE(self):
+        return os.path.join(self.BACKBONE_RED_DIR, 'backbone_red_value.tsv')
+
+    @property
+    def CLASS_LEVEL_RED_FILE(self):
+        return os.path.join(self.CLASS_LEVEL_RED_DIR, 'red_value_{iter}.tsv')
+
+    def _read_metadata_file(self):
+        if self._red_dist_bac_dict is None or self._red_dist_arc_dict is None or self._version_data is None:
+            try:
+                with open(os.path.join(self.METADATA_DIR, "metadata.txt")) as metadataData:
+                    for line in metadataData:
+                        try:
+                            line_infos = line.strip().split('=')
+                            if line_infos[0] == 'RED_DIST_BAC_DICT':
+                                self._red_dist_bac_dict = json.loads(line_infos[1])
+                            elif line_infos[0] == 'RED_DIST_ARC_DICT':
+                                self._red_dist_arc_dict = json.loads(line_infos[1])
+                            elif line_infos[0] == 'VERSION_DATA':
+                                self._version_data = line_infos[1]
+                        except ValueError:
+                            print(f"Skipping invalid line {repr(line)}")
+            except IOError:
+                print('\n' + '=' * 80)
+                print(' ERROR '.center(80))
+                print('_' * 80 + '\n')
+                print('The GTDB-Tk reference data does not exist or is corrupted.'.center(80))
+                print(('GTDBTK_DATA_PATH=%s' % self.GENERIC_PATH).center(80) + '\n')
+                print('Please compare the checksum to those provided in the download repository.'.center(80))
+                print('https://github.com/Ecogenomics/GTDBTk#gtdb-tk-reference-data'.center(80))
+                print('=' * 80)
+                sys.exit(1)
+        return self._red_dist_bac_dict, self._red_dist_arc_dict, self._version_data
+
+    @property
+    def RED_DIST_BAC_DICT(self):
+        return self._read_metadata_file()[0]
+
+    @property
+    def RED_DIST_ARC_DICT(self):
+        return self._read_metadata_file()[1]
+
+    @property
+    def VERSION_DATA(self):
+        return self._read_metadata_file()[2]
+
+    """
+    MSA file names
+    """
+
+    @property
+    def CONCAT_BAC120(self):
+        return os.path.join(self.MSA_FOLDER, f"gtdb_{self.VERSION_DATA}_bac120.faa")
+
+    @property
+    def CONCAT_AR53(self):
+        return os.path.join(self.MSA_FOLDER, f"gtdb_{self.VERSION_DATA}_ar53.faa")
+
+    @property
+    def TAXONOMY_FILE(self):
+        return os.path.join(self.TAX_FOLDER, "gtdb_taxonomy.tsv")
+
+    @property
+    def RADII_FILE(self):
+        return os.path.join(self.RADII_DIR, "gtdb_radii.tsv")
+
+    """
+    Mask file names
+    """
+
+    @property
+    def MASK_BAC120(self):
+        return f"gtdb_{self.VERSION_DATA}_bac120.mask"
+
+    @property
+    def MASK_AR53(self):
+        return f"gtdb_{self.VERSION_DATA}_ar53.mask"
+
+    @property
+    def MASK_RPS23(self):
+        return f"gtdb_{self.VERSION_DATA}_rps23.mask"
+
+    @property
+    def PPLACER_BAC120_REF_PKG(self):
+        return f"gtdb_{self.VERSION_DATA}_bac120.refpkg"
+
+    @property
+    def PPLACER_AR53_REF_PKG(self):
+        return f"gtdb_{self.VERSION_DATA}_ar53.refpkg"
+
+    @property
+    def PPLACER_RPS23_REF_PKG(self):
+        return f"gtdb_{self.VERSION_DATA}_rps23.refpkg"
+
+    @property
+    def FASTANI_GENOMES(self):
+        return os.path.join(self.FASTANI_DIR, "database/")
+
+    @property
+    def FASTANI_GENOME_LIST(self):
+        return os.path.join(self.FASTANI_DIR, "genome_paths.tsv")
+
+    @property
+    def MRCA_RED_BAC120(self):
+        return os.path.join(self.RED_DIR, f"gtdbtk_{self.VERSION_DATA}_bac120.tsv")
+
+    @property
+    def MRCA_RED_AR53(self):
+        return os.path.join(self.RED_DIR, f"gtdbtk_{self.VERSION_DATA}_ar53.tsv")
+
+    def get_REF_HASHES(self,version=None):
+        compatible_versions = [int(x.replace('r','')) for x in CONFIG.COMPATIBLE_REF_DATA_VERSIONS]
+        if version is not None and version not in compatible_versions:
+            raise ValueError(f"Version {version} is not compatible with this version of GTDB-Tk. Compatible versions are {compatible_versions}")
+
+        if version is None or version==214:
+            return {
+                self.PPLACER_DIR: '6786e9fc16b31db7d6eaaa9f8cfa87a8a4974434',
+                self.MASK_DIR: '8d5a2139feabbb70789c62155f3761d2aeed1601',
+                self.MARKER_DIR: '163f542c3f0a40f59df45d453aa235b39aa96e27',
+                self.RADII_DIR: '4753acc920001a1400788ee89cb4632900449055',
+                self.MSA_FOLDER: '75df495678a121497e14346b453caf42f4b03922',
+                self.METADATA_DIR: 'a089cc36bf79a40c7506019accc5f93e940d9fed',
+                self.TAX_FOLDER: '89b12cf8106f326887599dcb30ef94ebba142035',
+                self.FASTANI_DIR: 'e12824beccc15fe67a373e2aa8eee72feecf89c6',
+                self.RED_DIR: 'c24a2f48bb0c1df38f92a8f526aa846f596c94c6'
+            }
+        elif version==207:
+            return {
+                self.PPLACER_DIR: '20903925a856a58b102a7b0ce160c5cbd2cf675b',
+                self.MASK_DIR: '50e414a9de18170e8cb97f990f89ff60a0fe29d5',
+                self.MARKER_DIR: '163f542c3f0a40f59df45d453aa235b39aa96e27',
+                self.RADII_DIR: '8fd13b1c5d7a7b073ba96fb628581613b293a374',
+                self.MSA_FOLDER: '24f250d7cf0eb0bc65dccd2f3c9247e553ea322f',
+                self.METADATA_DIR: '9772fbeac1311b31e10293fa610eb33aa1ec8e15',
+                self.TAX_FOLDER: '6fb0233b05633242369b40c026fd1ee53e266afa',
+                self.FASTANI_DIR: '973c456c02f55bb82908a6811c7076e207e9b206',
+                self.RED_DIR: '7b8b67b3157204b470c9eb809d3c39c4effffabc'
+            }
+
+    REF_HASHES = property(get_REF_HASHES)
+
+
+# Export the class for import by other modules
+@lru_cache(maxsize=1)
+def __get_config():
+    return __GTDBTkCommonConfig()
+
+
+CONFIG = __get_config()
diff --git a/gtdbtk/config/config.py b/gtdbtk/config/config.py
deleted file mode 100644
index ccccac9e..00000000
--- a/gtdbtk/config/config.py
+++ /dev/null
@@ -1,266 +0,0 @@
-import json
-import os
-import sys
-
-"""
-Load the reference package. This will fail if the directory doesn't exist.
-"""
-try:
-    GENERIC_PATH = os.environ['GTDBTK_DATA_PATH']
-    #expand the variables in the path
-    GENERIC_PATH = os.path.expandvars(GENERIC_PATH)
-except KeyError:
-    print('\n' + '=' * 80)
-    print(' ERROR '.center(80))
-    print('_' * 80 + '\n')
-    print("The 'GTDBTK_DATA_PATH' environment variable is not defined.".center(80) + '\n')
-    print('Please set this variable to your reference data package.'.center(80))
-    print('https://ecogenomics.github.io/GTDBTk/installing/index.html'.center(80))
-    print('=' * 80)
-    sys.exit(1)
-
-"""
-If the reference package sub-folders still exist in GTDBTK_DATA_PATH, then there
-is no need to edit the variables below.
-"""
-MIN_REF_DATA_VERSION = 'r207'
-
-MSA_FOLDER = os.path.join(GENERIC_PATH, "msa/")
-MASK_DIR = os.path.join(GENERIC_PATH, "masks/")
-PPLACER_DIR = os.path.join(GENERIC_PATH, "pplacer/")
-FASTANI_DIR = os.path.join(GENERIC_PATH, "fastani/")
-MASH_DIR = os.path.join(GENERIC_PATH, "mash/")
-
-TAX_FOLDER = os.path.join(GENERIC_PATH, "taxonomy/")
-RADII_DIR = os.path.join(GENERIC_PATH, "radii/")
-METADATA_DIR = os.path.join(GENERIC_PATH, "metadata/")
-RED_DIR = os.path.join(GENERIC_PATH, "mrca_red/")
-MARKER_DIR = os.path.join(GENERIC_PATH, 'markers/')
-TIGRFAM_HMMS = os.path.join(MARKER_DIR, 'tigrfam/tigrfam.hmm')
-PFAM_HMM_DIR = os.path.join(MARKER_DIR, 'pfam/')
-
-SPLIT_DIR = os.path.join(GENERIC_PATH, 'split')
-BACKBONE_SPLIT_DIR = os.path.join(SPLIT_DIR, 'backbone')
-CLASS_LEVEL_SPLIT_DIR = os.path.join(SPLIT_DIR, 'class_level')
-BACKBONE_PPLACER_DIR = os.path.join(BACKBONE_SPLIT_DIR, 'pplacer')
-CLASS_LEVEL_PPLACER_DIR = os.path.join(CLASS_LEVEL_SPLIT_DIR, 'pplacer')
-BACKBONE_RED_DIR = os.path.join(BACKBONE_SPLIT_DIR, 'red')
-CLASS_LEVEL_RED_DIR = os.path.join(CLASS_LEVEL_SPLIT_DIR, 'red')
-
-CLASS_LEVEL_TREE_MAPPING_FILE = os.path.join(CLASS_LEVEL_SPLIT_DIR, 'tree_mapping.tsv')
-
-BACKBONE_PPLACER_REF_PKG = 'gtdbtk_package_backbone.refpkg'
-BACKBONE_RED_FILE = os.path.join(BACKBONE_RED_DIR, 'backbone_red_value.tsv')
-CLASS_LEVEL_PPLACER_REF_PKG = 'gtdbtk.package.{iter}.refpkg'
-CLASS_LEVEL_RED_FILE = os.path.join(CLASS_LEVEL_RED_DIR, 'red_value_{iter}.tsv')
-
-RED_DIST_BAC_DICT = ''
-RED_DIST_ARC_DICT = ''
-VERSION_DATA = ''
-try:
-    with open(os.path.join(METADATA_DIR, "metadata.txt")) as metadataData:
-        for line in metadataData:
-            try:
-                line_infos = line.strip().split('=')
-                if line_infos[0] == 'RED_DIST_BAC_DICT':
-                    RED_DIST_BAC_DICT = json.loads(line_infos[1])
-                elif line_infos[0] == 'RED_DIST_ARC_DICT':
-                    RED_DIST_ARC_DICT = json.loads(line_infos[1])
-                elif line_infos[0] == 'VERSION_DATA':
-                    VERSION_DATA = line_infos[1]
-            except ValueError:
-                print(f"Skipping invalid line {repr(line)}")
-except IOError:
-    print('\n' + '=' * 80)
-    print(' ERROR '.center(80))
-    print('_' * 80 + '\n')
-    print('The GTDB-Tk reference data does not exist or is corrupted.'.center(80))
-    print(('GTDBTK_DATA_PATH=%s' % GENERIC_PATH).center(80) + '\n')
-    print('Please compare the checksum to those provided in the download repository.'.center(80))
-    print('https://github.com/Ecogenomics/GTDBTk#gtdb-tk-reference-data'.center(80))
-    print('=' * 80)
-    sys.exit(1)
-
-# Relative Evolution Distance
-RED_INTERVAL = 0.1
-RED_MIN_SUPPORT = 0.0
-RED_MIN_CHILDREN = 2
-
-# Marker information
-BAC120_MARKERS = {"PFAM": ["PF00380.20.hmm", "PF00410.20.hmm", "PF00466.21.hmm",
-                           "PF01025.20.hmm", "PF02576.18.hmm", "PF03726.15.hmm"],
-                  "TIGRFAM": ["TIGR00006.HMM", "TIGR00019.HMM", "TIGR00020.HMM",
-                              "TIGR00029.HMM", "TIGR00043.HMM", "TIGR00054.HMM",
-                              "TIGR00059.HMM", "TIGR00061.HMM", "TIGR00064.HMM",
-                              "TIGR00065.HMM", "TIGR00082.HMM", "TIGR00083.HMM",
-                              "TIGR00084.HMM", "TIGR00086.HMM", "TIGR00088.HMM",
-                              "TIGR00090.HMM", "TIGR00092.HMM", "TIGR00095.HMM",
-                              "TIGR00115.HMM", "TIGR00116.HMM", "TIGR00138.HMM",
-                              "TIGR00158.HMM", "TIGR00166.HMM", "TIGR00168.HMM",
-                              "TIGR00186.HMM", "TIGR00194.HMM", "TIGR00250.HMM",
-                              "TIGR00337.HMM", "TIGR00344.HMM", "TIGR00362.HMM",
-                              "TIGR00382.HMM", "TIGR00392.HMM", "TIGR00396.HMM",
-                              "TIGR00398.HMM", "TIGR00414.HMM", "TIGR00416.HMM",
-                              "TIGR00420.HMM", "TIGR00431.HMM", "TIGR00435.HMM",
-                              "TIGR00436.HMM", "TIGR00442.HMM", "TIGR00445.HMM",
-                              "TIGR00456.HMM", "TIGR00459.HMM", "TIGR00460.HMM",
-                              "TIGR00468.HMM", "TIGR00472.HMM", "TIGR00487.HMM",
-                              "TIGR00496.HMM", "TIGR00539.HMM", "TIGR00580.HMM",
-                              "TIGR00593.HMM", "TIGR00615.HMM", "TIGR00631.HMM",
-                              "TIGR00634.HMM", "TIGR00635.HMM", "TIGR00643.HMM",
-                              "TIGR00663.HMM", "TIGR00717.HMM", "TIGR00755.HMM",
-                              "TIGR00810.HMM", "TIGR00922.HMM", "TIGR00928.HMM",
-                              "TIGR00959.HMM", "TIGR00963.HMM", "TIGR00964.HMM",
-                              "TIGR00967.HMM", "TIGR01009.HMM", "TIGR01011.HMM",
-                              "TIGR01017.HMM", "TIGR01021.HMM", "TIGR01029.HMM",
-                              "TIGR01032.HMM", "TIGR01039.HMM", "TIGR01044.HMM",
-                              "TIGR01059.HMM", "TIGR01063.HMM", "TIGR01066.HMM",
-                              "TIGR01071.HMM", "TIGR01079.HMM", "TIGR01082.HMM",
-                              "TIGR01087.HMM", "TIGR01128.HMM", "TIGR01146.HMM",
-                              "TIGR01164.HMM", "TIGR01169.HMM", "TIGR01171.HMM",
-                              "TIGR01302.HMM", "TIGR01391.HMM", "TIGR01393.HMM",
-                              "TIGR01394.HMM", "TIGR01510.HMM", "TIGR01632.HMM",
-                              "TIGR01951.HMM", "TIGR01953.HMM", "TIGR02012.HMM",
-                              "TIGR02013.HMM", "TIGR02027.HMM", "TIGR02075.HMM",
-                              "TIGR02191.HMM", "TIGR02273.HMM", "TIGR02350.HMM",
-                              "TIGR02386.HMM", "TIGR02397.HMM", "TIGR02432.HMM",
-                              "TIGR02729.HMM", "TIGR03263.HMM", "TIGR03594.HMM",
-                              "TIGR03625.HMM", "TIGR03632.HMM", "TIGR03654.HMM",
-                              "TIGR03723.HMM", "TIGR03725.HMM", "TIGR03953.HMM"]}
-
-
-
-#New Version of AR53_MARKERS
-AR53_MARKERS = {"PFAM": ["PF04919.13.hmm","PF07541.13.hmm","PF01000.27.hmm",
-                        "PF00687.22.hmm","PF00466.21.hmm","PF00827.18.hmm","PF01280.21.hmm","PF01090.20.hmm",
-                        "PF01200.19.hmm","PF01015.19.hmm","PF00900.21.hmm","PF00410.20.hmm"],
-                "TIGRFAM":["TIGR00037.HMM","TIGR00064.HMM","TIGR00111.HMM",
-                            "TIGR00134.HMM","TIGR00279.HMM","TIGR00291.HMM","TIGR00323.HMM",
-                            "TIGR00335.HMM","TIGR00373.HMM","TIGR00405.HMM","TIGR00448.HMM",
-                            "TIGR00483.HMM","TIGR00491.HMM","TIGR00522.HMM","TIGR00967.HMM",
-                            "TIGR00982.HMM","TIGR01008.HMM","TIGR01012.HMM","TIGR01018.HMM",
-                            "TIGR01020.HMM","TIGR01028.HMM","TIGR01046.HMM","TIGR01052.HMM",
-                            "TIGR01171.HMM","TIGR01213.HMM","TIGR01952.HMM","TIGR02236.HMM",
-                            "TIGR02338.HMM","TIGR02389.HMM","TIGR02390.HMM","TIGR03626.HMM",
-                            "TIGR03627.HMM","TIGR03628.HMM","TIGR03629.HMM","TIGR03670.HMM",
-                            "TIGR03671.HMM","TIGR03672.HMM","TIGR03673.HMM","TIGR03674.HMM",
-                            "TIGR03676.HMM","TIGR03680.HMM"]}
-
-
-# Information for Multiple hits markers:
-DEFAULT_MULTIHIT_THRESHOLD = 10.0
-
-# Information for aligning genomes
-DEFAULT_DOMAIN_THRESHOLD = 10.0
-AR_MARKER_COUNT = 53
-BAC_MARKER_COUNT = 120
-
-# Information about alignment Fraction to resolve fastANI results
-AF_THRESHOLD = 0.5
-
-# MSA file names
-CONCAT_BAC120 = os.path.join(MSA_FOLDER, f"gtdb_{VERSION_DATA}_bac120.faa")
-CONCAT_AR53 = os.path.join(MSA_FOLDER, f"gtdb_{VERSION_DATA}_ar53.faa")
-
-# Taxonomy file name
-TAXONOMY_FILE = os.path.join(TAX_FOLDER, "gtdb_taxonomy.tsv")
-
-# Type Strain radii file
-RADII_FILE = os.path.join(RADII_DIR, "gtdb_radii.tsv")
-
-# Mask file names
-MASK_BAC120 = f"gtdb_{VERSION_DATA}_bac120.mask"
-MASK_AR53 = f"gtdb_{VERSION_DATA}_ar53.mask"
-MASK_RPS23 = f"gtdb_{VERSION_DATA}_rps23.mask"
-
-# Pplacer configuration
-PPLACER_BAC120_REF_PKG = f"gtdb_{VERSION_DATA}_bac120.refpkg"
-PPLACER_AR53_REF_PKG = f"gtdb_{VERSION_DATA}_ar53.refpkg"
-PPLACER_RPS23_REF_PKG = f"gtdb_{VERSION_DATA}_rps23.refpkg"
-PPLACER_MIN_RAM_BAC_FULL = 320
-PPLACER_MIN_RAM_BAC_SPLIT = 55
-PPLACER_MIN_RAM_ARC = 40
-
-# Fastani configuration
-FASTANI_SPECIES_THRESHOLD = 95.0
-FASTANI_GENOMES = os.path.join(FASTANI_DIR, "database/")
-FASTANI_GENOME_LIST = os.path.join(FASTANI_DIR, "genome_paths.tsv")
-FASTANI_GENOMES_EXT = "_genomic.fna.gz"
-
-# Mash configuration
-MASH_SKETCH_FILE = 'gtdb_ref_sketch.msh'
-MASH_K_VALUE = 16
-MASH_S_VALUE = 5000
-MASH_MAX_DISTANCE = 0.1
-MASH_D_VALUE = MASH_MAX_DISTANCE
-MASH_V_VALUE = 1.0
-
-
-# MRCA RED VALUE
-MRCA_RED_BAC120 = os.path.join(RED_DIR, f"gtdbtk_{VERSION_DATA}_bac120.tsv")
-MRCA_RED_AR53 = os.path.join(RED_DIR, f"gtdbtk_{VERSION_DATA}_ar53.tsv")
-
-# Hashing information for validating the reference package.
-REF_HASHES = {PPLACER_DIR: '20903925a856a58b102a7b0ce160c5cbd2cf675b',
-              MASK_DIR: '50e414a9de18170e8cb97f990f89ff60a0fe29d5',
-              MARKER_DIR: '163f542c3f0a40f59df45d453aa235b39aa96e27',
-              RADII_DIR: '8fd13b1c5d7a7b073ba96fb628581613b293a374',
-              MSA_FOLDER: '24f250d7cf0eb0bc65dccd2f3c9247e553ea322f',
-              METADATA_DIR: '9772fbeac1311b31e10293fa610eb33aa1ec8e15',
-              TAX_FOLDER: '6fb0233b05633242369b40c026fd1ee53e266afa',
-              FASTANI_DIR: '973c456c02f55bb82908a6811c7076e207e9b206',
-              RED_DIR: '7b8b67b3157204b470c9eb809d3c39c4effffabc'}
-
-# Config values for checking GTDB-Tk on startup.
-GTDBTK_VER_CHECK = True
-GTDBTK_VER_TIMEOUT = 3  # seconds
-
-# Internal settings used for logging.
-LOG_TASK = 21
-
-
-
-
-#
-#New Version of AR53_MARKERS
-# AR53_MARKERS = {"PFAM": ["PF01868.17.hmm", "PF01282.20.hmm", "PF01655.19.hmm",
-#                           "PF01092.20.hmm", "PF01000.27.hmm", "PF00368.19.hmm",
-#                           "PF00827.18.hmm", "PF01269.18.hmm", "PF00466.21.hmm",
-#                           "PF01015.19.hmm", "PF13685.7.hmm", "PF02978.20.hmm",
-#                           "PF04919.13.hmm", "PF01984.21.hmm", "PF04104.15.hmm",
-#                           "PF00410.20.hmm", "PF01798.19.hmm", "PF01864.18.hmm",
-#                           "PF01990.18.hmm", "PF07541.13.hmm", "PF04019.13.hmm",
-#                           "PF00900.21.hmm", "PF01090.20.hmm", "PF02006.17.hmm",
-#                           "PF01157.19.hmm", "PF01191.20.hmm", "PF01866.18.hmm",
-#                           "PF01198.20.hmm", "PF01496.20.hmm", "PF00687.22.hmm",
-#                           "PF03874.17.hmm", "PF01194.18.hmm", "PF01200.19.hmm",
-#                           "PF13656.7.hmm", "PF01280.21.hmm"],
-#                  "TIGRFAM": ["TIGR00468.HMM", "TIGR01060.HMM", "TIGR03627.HMM",
-#                              "TIGR01020.HMM", "TIGR02258.HMM", "TIGR00293.HMM",
-#                              "TIGR00389.HMM", "TIGR01012.HMM", "TIGR00490.HMM",
-#                              "TIGR03677.HMM", "TIGR03636.HMM", "TIGR03722.HMM",
-#                              "TIGR00458.HMM", "TIGR00291.HMM", "TIGR00670.HMM",
-#                              "TIGR00064.HMM", "TIGR03629.HMM", "TIGR00021.HMM",
-#                              "TIGR03672.HMM", "TIGR00111.HMM", "TIGR03684.HMM",
-#                              "TIGR01077.HMM", "TIGR01213.HMM", "TIGR01080.HMM",
-#                              "TIGR00501.HMM", "TIGR00729.HMM", "TIGR01038.HMM",
-#                              "TIGR00270.HMM", "TIGR03628.HMM", "TIGR01028.HMM",
-#                              "TIGR00521.HMM", "TIGR03671.HMM", "TIGR00240.HMM",
-#                              "TIGR02390.HMM", "TIGR02338.HMM", "TIGR00037.HMM",
-#                              "TIGR02076.HMM", "TIGR00335.HMM", "TIGR01025.HMM",
-#                              "TIGR00471.HMM", "TIGR00336.HMM", "TIGR00522.HMM",
-#                              "TIGR02153.HMM", "TIGR02651.HMM", "TIGR03674.HMM",
-#                              "TIGR00323.HMM", "TIGR00134.HMM", "TIGR02236.HMM",
-#                              "TIGR03683.HMM", "TIGR00491.HMM", "TIGR00658.HMM",
-#                              "TIGR03680.HMM", "TIGR00392.HMM", "TIGR00422.HMM",
-#                              "TIGR00279.HMM", "TIGR01052.HMM", "TIGR00442.HMM",
-#                              "TIGR00308.HMM", "TIGR00398.HMM", "TIGR00456.HMM",
-#                              "TIGR00549.HMM", "TIGR00408.HMM", "TIGR00432.HMM",
-#                              "TIGR00264.HMM", "TIGR00982.HMM", "TIGR00324.HMM",
-#                              "TIGR01952.HMM", "TIGR03626.HMM", "TIGR03670.HMM",
-#                              "TIGR00337.HMM", "TIGR01046.HMM", "TIGR01018.HMM",
-#                              "TIGR00936.HMM", "TIGR00463.HMM", "TIGR01309.HMM",
-#                              "TIGR03653.HMM", "TIGR00042.HMM", "TIGR02389.HMM",
-#                              "TIGR00307.HMM", "TIGR03673.HMM", "TIGR00373.HMM",
-#                              "TIGR01008.HMM", "TIGR00283.HMM", "TIGR00425.HMM",
-#                              "TIGR00405.HMM", "TIGR03665.HMM", "TIGR00448.HMM"]}
diff --git a/gtdbtk/external/mash.py b/gtdbtk/external/mash.py
index fa18bd7d..7ee02144 100644
--- a/gtdbtk/external/mash.py
+++ b/gtdbtk/external/mash.py
@@ -8,7 +8,7 @@
 from gtdbtk.biolib_lite.common import make_sure_path_exists
 from gtdbtk.exceptions import GTDBTkExit
 from gtdbtk.tools import tqdm_log
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 
 
 class Mash(object):
@@ -271,7 +271,7 @@ def __init__(self, genomes, root, prefix, cpus, k, s):
 
 
 class RefSketchFile(SketchFile):
-    name = Config.MASH_SKETCH_FILE
+    name = CONFIG.MASH_SKETCH_FILE
 
     def __init__(self, genomes, root, prefix, cpus, k, s, mash_db=None):
         """Create a query file for a given set of genomes.
diff --git a/gtdbtk/files/gtdb_radii.py b/gtdbtk/files/gtdb_radii.py
index 55086a6a..b0f3ef73 100644
--- a/gtdbtk/files/gtdb_radii.py
+++ b/gtdbtk/files/gtdb_radii.py
@@ -1,16 +1,18 @@
 from gtdbtk.biolib_lite.common import canonical_gid
-from gtdbtk.config.config import RADII_FILE
-
+from gtdbtk.config.common import CONFIG
 
 class GTDBRadiiFile(object):
     """A wrapper for the gtdb_radii.tsv file included in the reference data."""
-    path = RADII_FILE
 
     def __init__(self):
         self._rep_idx = None
         self._species_idx = None
         self._read()
 
+    @property
+    def path(self):
+        return CONFIG.RADII_FILE
+
     def _read(self):
         """Read the file and create any data."""
         self._rep_idx, self._species_idx = dict(), dict()
diff --git a/gtdbtk/files/marker/copy_number.py b/gtdbtk/files/marker/copy_number.py
index b0323f83..8b6a3f0b 100644
--- a/gtdbtk/files/marker/copy_number.py
+++ b/gtdbtk/files/marker/copy_number.py
@@ -21,7 +21,7 @@
 
 from gtdbtk.biolib_lite.common import make_sure_path_exists
 from gtdbtk.biolib_lite.seq_io import read_fasta
-from gtdbtk.config.config import BAC120_MARKERS, AR53_MARKERS
+from gtdbtk.config.common import CONFIG
 from gtdbtk.config.output import PATH_BAC120_MARKER_SUMMARY, PATH_AR53_MARKER_SUMMARY
 from gtdbtk.exceptions import GTDBTkExit
 from gtdbtk.files.marker.tophit import TopHitPfamFile, TopHitTigrFile, Hit
@@ -159,7 +159,7 @@ class CopyNumberFileAR53(CopyNumberFile):
 
     def __init__(self, out_dir: str, prefix: str):
         path = os.path.join(out_dir, PATH_AR53_MARKER_SUMMARY.format(prefix=prefix))
-        super().__init__(path, 'ar53', AR53_MARKERS)
+        super().__init__(path, 'ar53', CONFIG.AR53_MARKERS)
 
 
 class CopyNumberFileBAC120(CopyNumberFile):
@@ -167,4 +167,4 @@ class CopyNumberFileBAC120(CopyNumberFile):
 
     def __init__(self, out_dir: str, prefix: str):
         path = os.path.join(out_dir, PATH_BAC120_MARKER_SUMMARY.format(prefix=prefix))
-        super().__init__(path, 'bac120', BAC120_MARKERS)
+        super().__init__(path, 'bac120', CONFIG.BAC120_MARKERS)
diff --git a/gtdbtk/files/marker_info.py b/gtdbtk/files/marker_info.py
index b5e07809..f07d0d23 100644
--- a/gtdbtk/files/marker_info.py
+++ b/gtdbtk/files/marker_info.py
@@ -18,20 +18,24 @@
 import os
 
 from gtdbtk.biolib_lite.common import make_sure_path_exists
-from gtdbtk.config.config import AR53_MARKERS, BAC120_MARKERS, TIGRFAM_HMMS, PFAM_HMM_DIR
+from gtdbtk.config.common import CONFIG
 from gtdbtk.config.output import PATH_AR53_MARKER_INFO, PATH_BAC120_MARKER_INFO
 
 
 class MarkerInfoFile(object):
     """Store the GTDB-Tk RED dictionary."""
 
-    marker_paths = {"PFAM": os.path.join(PFAM_HMM_DIR, 'individual_hmms'),
-                    "TIGRFAM": os.path.join(os.path.dirname(TIGRFAM_HMMS), 'individual_hmms')}
-
     def __init__(self, path: str, markers: dict):
         self.path = path
         self.markers = self._parse_markers(markers)
 
+    @property
+    def marker_paths(self):
+        return {
+            "PFAM": os.path.join(CONFIG.PFAM_HMM_DIR, 'individual_hmms'),
+            "TIGRFAM": os.path.join(os.path.dirname(CONFIG.TIGRFAM_HMMS), 'individual_hmms')
+        }
+
     def _parse_markers(self, markers):
         out = dict()
         for db_marker in sorted(markers):
@@ -71,7 +75,7 @@ class MarkerInfoFileAR53(MarkerInfoFile):
 
     def __init__(self, out_dir: str, prefix: str):
         path = os.path.join(out_dir, PATH_AR53_MARKER_INFO.format(prefix=prefix))
-        super().__init__(path, AR53_MARKERS)
+        super().__init__(path, CONFIG.AR53_MARKERS)
 
 
 class MarkerInfoFileBAC120(MarkerInfoFile):
@@ -79,4 +83,4 @@ class MarkerInfoFileBAC120(MarkerInfoFile):
 
     def __init__(self, out_dir: str, prefix: str):
         path = os.path.join(out_dir, PATH_BAC120_MARKER_INFO.format(prefix=prefix))
-        super().__init__(path, BAC120_MARKERS)
+        super().__init__(path, CONFIG.BAC120_MARKERS)
diff --git a/gtdbtk/files/red_dict.py b/gtdbtk/files/red_dict.py
index 989b64ec..7bd50180 100644
--- a/gtdbtk/files/red_dict.py
+++ b/gtdbtk/files/red_dict.py
@@ -19,7 +19,7 @@
 from typing import Dict
 
 from gtdbtk.biolib_lite.common import make_sure_path_exists
-from gtdbtk.config.config import RED_DIST_ARC_DICT, RED_DIST_BAC_DICT
+from gtdbtk.config.common import CONFIG
 from gtdbtk.config.output import PATH_AR53_RED_DICT, PATH_BAC120_RED_DICT
 
 
@@ -46,7 +46,7 @@ class REDDictFileAR53(REDDictFile):
 
     def __init__(self, out_dir: str, prefix: str):
         path = os.path.join(out_dir, PATH_AR53_RED_DICT.format(prefix=prefix))
-        super().__init__(path, RED_DIST_ARC_DICT)
+        super().__init__(path, CONFIG.RED_DIST_ARC_DICT)
 
 
 class REDDictFileBAC120(REDDictFile):
@@ -54,4 +54,4 @@ class REDDictFileBAC120(REDDictFile):
 
     def __init__(self, out_dir: str, prefix: str):
         path = os.path.join(out_dir, PATH_BAC120_RED_DICT.format(prefix=prefix))
-        super().__init__(path, RED_DIST_BAC_DICT)
+        super().__init__(path, CONFIG.RED_DIST_BAC_DICT)
diff --git a/gtdbtk/infer_ranks.py b/gtdbtk/infer_ranks.py
index 7464ee29..a7b46a74 100644
--- a/gtdbtk/infer_ranks.py
+++ b/gtdbtk/infer_ranks.py
@@ -21,12 +21,7 @@
 
 from gtdbtk.biolib_lite.newick import parse_label, create_label
 from gtdbtk.biolib_lite.taxonomy import Taxonomy
-from gtdbtk.config.config import (TAXONOMY_FILE,
-                                  RED_DIST_BAC_DICT,
-                                  RED_DIST_ARC_DICT,
-                                  MRCA_RED_BAC120,
-                                  MRCA_RED_AR53,
-                                  RED_INTERVAL)
+from gtdbtk.config.common import CONFIG
 from gtdbtk.exceptions import GTDBTkExit
 from gtdbtk.relative_distance import RelativeDistance
 
@@ -43,7 +38,7 @@ def _get_ingroup_domain(self, ingroup_taxon) -> str:
         """Get domain on ingroup taxon."""
 
         # read GTDB taxonomy in order to establish domain on ingroup taxon
-        gtdb_taxonomy = Taxonomy().read(TAXONOMY_FILE)
+        gtdb_taxonomy = Taxonomy().read(CONFIG.TAXONOMY_FILE)
         ingroup_domain = None
         for taxa in gtdb_taxonomy.values():
             if ingroup_taxon in taxa:
@@ -60,9 +55,9 @@ def _get_median_reds(self, ingroup_domain: str):
 
         # get median RED values for domain
         if ingroup_domain == 'd__Bacteria':
-            median_reds = RED_DIST_BAC_DICT
+            median_reds = CONFIG.RED_DIST_BAC_DICT
         elif ingroup_domain == 'd__Archaea':
-            median_reds = RED_DIST_ARC_DICT
+            median_reds = CONFIG.RED_DIST_ARC_DICT
         else:
             raise GTDBTkExit(f'Unrecognized GTDB domain: {ingroup_domain}.')
 
@@ -100,9 +95,9 @@ def _find_ingroup_taxon(self, ingroup_taxon, tree):
     def _find_ingroup_red(self, ingroup_node, ingroup_domain, tree):
         """Find RED of the ingroup taxon."""
 
-        red_file = MRCA_RED_BAC120
+        red_file = CONFIG.MRCA_RED_BAC120
         if ingroup_domain == 'd__Archaea':
-            red_file = MRCA_RED_AR53
+            red_file = CONFIG.MRCA_RED_AR53
 
         # create map from leave labels to tree nodes
         leaf_node_map = {}
@@ -132,7 +127,7 @@ def _determine_red_ranks(self, node_red, median_reds):
             rank_label = Taxonomy.rank_labels[rank_idx]
 
             abs_red_diff = abs(node_red - median_red)
-            if abs_red_diff <= RED_INTERVAL:
+            if abs_red_diff <= CONFIG.RED_INTERVAL:
                 red_ranks[rank_label] = abs_red_diff
 
         red_ranks_label = []
diff --git a/gtdbtk/main.py b/gtdbtk/main.py
index 9eb0db4e..bf881dd1 100644
--- a/gtdbtk/main.py
+++ b/gtdbtk/main.py
@@ -27,7 +27,7 @@
 
 from tqdm import tqdm
 
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 from gtdbtk.ani_rep import ANIRep
 from gtdbtk.ani_screen import ANIScreener
 from gtdbtk.biolib_lite.common import (check_dir_exists,
@@ -86,20 +86,20 @@ def __init__(self, version,output_dir=None):
             self.stage_logger = StageLogger()
             self.stage_logger.version=self.version
             self.stage_logger.command_line=f'{prog_name} {" ".join(sys.argv[1:])}'
-            self.stage_logger.database_version = Config.VERSION_DATA
-            self.stage_logger.database_path=Config.GENERIC_PATH
+            self.stage_logger.database_version = CONFIG.VERSION_DATA
+            self.stage_logger.database_path=CONFIG.GENERIC_PATH
             self.stage_logger.output_dir=output_dir
             self.stage_logger.path = os.path.join(output_dir, "gtdbtk.json")
 
     def _check_package_compatibility(self):
         """Check that GTDB-Tk is using the most up-to-date reference package."""
-        pkg_ver = float(Config.VERSION_DATA.replace('r', ''))
-        min_ver = float(Config.MIN_REF_DATA_VERSION.replace('r', ''))
+        pkg_ver = float(CONFIG.VERSION_DATA.replace('r', ''))
+        min_ver = float(CONFIG.MIN_REF_DATA_VERSION.replace('r', ''))
         self.logger.info(f'Using GTDB-Tk reference data version '
-                         f'{Config.VERSION_DATA}: {Config.GENERIC_PATH}')
+                         f'{CONFIG.VERSION_DATA}: {CONFIG.GENERIC_PATH}')
         if pkg_ver < min_ver:
             self.logger.warning(colour(f'You are not using the reference data '
-                                       f'intended for this release: {Config.MIN_REF_DATA_VERSION}',
+                                       f'intended for this release: {CONFIG.MIN_REF_DATA_VERSION}',
                                        ['bright'], fg='yellow'))
 
     def _verify_genome_id(self, genome_id: str) -> bool:
@@ -220,7 +220,7 @@ def _read_taxonomy_files(self, options) -> Dict[str, Tuple[str, str, str, str, s
         """Read and merge taxonomy files."""
 
         self.logger.info('Reading GTDB taxonomy for representative genomes.')
-        taxonomy = Taxonomy().read(Config.TAXONOMY_FILE)
+        taxonomy = Taxonomy().read(CONFIG.TAXONOMY_FILE)
 
         if options.gtdbtk_classification_file:
             # add and overwrite taxonomy for genomes specified in the
@@ -852,7 +852,7 @@ def decorate(self, options):
 
         self.logger.info('Done.')
 
-    def check_install(self):
+    def check_install(self,options):
         """ Verify all GTDB-Tk data files are present.
 
         Raises
@@ -862,7 +862,7 @@ def check_install(self):
         """
         self.logger.info("Running install verification")
         misc = Misc()
-        misc.check_install()
+        misc.check_install(options.db_version)
         self.logger.info('Done.')
 
     def infer_ranks(self, options):
@@ -911,6 +911,20 @@ def convert_to_itol(self, options):
         r.convert_to_itol(options.input_tree, options.output_tree)
         self.logger.info('Done.')
 
+    def convert_to_species(self, options):
+        """Change GTDB genomes ids to GTDb species name in the tree.
+
+        Parameters
+        ----------
+        options : argparse.Namespace
+            The CLI arguments input by the user.
+        """
+        check_file_exists(options.input_tree)
+
+        r = Misc()
+        r.convert_to_species(options.input_tree, options.output_tree,options.custom_taxonomy_file,options.all_ranks)
+        self.logger.info('Done.')
+
     def remove_labels(self, options):
         """Remove labels from tree.
 
@@ -1201,6 +1215,8 @@ def parse_options(self, options):
             self.remove_labels(options)
         elif options.subparser_name == 'convert_to_itol':
             self.convert_to_itol(options)
+        elif options.subparser_name == 'convert_to_species':
+            self.convert_to_species(options)
         elif options.subparser_name == 'trim_msa':
             self.trim_msa(options)
         elif options.subparser_name == 'export_msa':
@@ -1210,7 +1226,7 @@ def parse_options(self, options):
                                 'fastANI'])
             self.run_test(options)
         elif options.subparser_name == 'check_install':
-            self.check_install()
+            self.check_install(options)
         else:
             self.logger.error('Unknown GTDB-Tk command: "' +
                               options.subparser_name + '"\n')
diff --git a/gtdbtk/markers.py b/gtdbtk/markers.py
index fcb3bc1c..fd9ad6cd 100644
--- a/gtdbtk/markers.py
+++ b/gtdbtk/markers.py
@@ -25,7 +25,7 @@
 import gzip
 import numpy as np
 
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 from gtdbtk.biolib_lite.common import make_sure_path_exists
 from gtdbtk.biolib_lite.execute import check_dependencies
 from gtdbtk.biolib_lite.seq_io import read_fasta
@@ -65,13 +65,13 @@ def __init__(self, cpus=1, debug=False):
         self.gff_file_suffix = GFF_FILE_SUFFIX
         self.checksum_suffix = CHECKSUM_SUFFIX
 
-        self.taxonomy_file = Config.TAXONOMY_FILE
+        self.taxonomy_file = CONFIG.TAXONOMY_FILE
 
-        self.pfam_hmm_dir = Config.PFAM_HMM_DIR
+        self.pfam_hmm_dir = CONFIG.PFAM_HMM_DIR
         self.pfam_suffix = PFAM_SUFFIX
         self.pfam_top_hit_suffix = PFAM_TOP_HIT_SUFFIX
 
-        self.tigrfam_hmms = Config.TIGRFAM_HMMS
+        self.tigrfam_hmms = CONFIG.TIGRFAM_HMMS
         self.tigrfam_suffix = TIGRFAM_SUFFIX
         self.tigrfam_top_hit_suffix = TIGRFAM_TOP_HIT_SUFFIX
 
@@ -123,11 +123,11 @@ def _report_identified_marker_genes(self, gene_dict, outdir, prefix,
 
             # Iterate over each domain.
             marker_doms = list()
-            marker_doms.append((Config.AR53_MARKERS['PFAM'] +
-                                Config.AR53_MARKERS['TIGRFAM'],
+            marker_doms.append((CONFIG.AR53_MARKERS['PFAM'] +
+                                CONFIG.AR53_MARKERS['TIGRFAM'],
                                 ar53_copy_number_file, 'ar53'))
-            marker_doms.append((Config.BAC120_MARKERS['PFAM'] +
-                                Config.BAC120_MARKERS['TIGRFAM'],
+            marker_doms.append((CONFIG.BAC120_MARKERS['PFAM'] +
+                                CONFIG.BAC120_MARKERS['TIGRFAM'],
                                 bac120_copy_number_file, 'bac120'))
             for marker_names, marker_file, marker_d in marker_doms:
 
@@ -201,7 +201,7 @@ def identify(self, genomes, tln_tables, out_dir, prefix, force, genes, write_sin
                                 self.gff_file_suffix,
                                 force)
             self.logger.log(
-                Config.LOG_TASK, f'Running Prodigal {prodigal.version} to identify genes.')
+                CONFIG.LOG_TASK, f'Running Prodigal {prodigal.version} to identify genes.')
             genome_dictionary = prodigal.run(genomes, tln_tables)
 
         else:
@@ -222,7 +222,7 @@ def identify(self, genomes, tln_tables, out_dir, prefix, force, genes, write_sin
                 symlink_f(os.path.abspath(gpath), os.path.join(symlink_protein_dir,gid+self.protein_file_suffix))
 
         # annotated genes against TIGRFAM and Pfam databases
-        self.logger.log(Config.LOG_TASK,
+        self.logger.log(CONFIG.LOG_TASK,
                         'Identifying TIGRFAM protein families.')
         gene_files = [(db_genome_id, genome_dictionary[db_genome_id]['aa_gene_path'])
                       for db_genome_id in genome_dictionary.keys()]
@@ -235,7 +235,7 @@ def identify(self, genomes, tln_tables, out_dir, prefix, force, genes, write_sin
                                     self.marker_gene_dir)
         tigr_search.run(gene_files)
 
-        self.logger.log(Config.LOG_TASK, 'Identifying Pfam protein families.')
+        self.logger.log(CONFIG.LOG_TASK, 'Identifying Pfam protein families.')
         pfam_search = PfamSearch(self.cpus,
                                  self.pfam_hmm_dir,
                                  self.protein_file_suffix,
@@ -247,7 +247,7 @@ def identify(self, genomes, tln_tables, out_dir, prefix, force, genes, write_sin
         self.logger.info(
             f'Annotations done using HMMER {tigr_search.version}.')
 
-        self.logger.log(Config.LOG_TASK,
+        self.logger.log(CONFIG.LOG_TASK,
                         'Summarising identified marker genes.')
         reports = self._report_identified_marker_genes(genome_dictionary, out_dir, prefix,
                                              write_single_copy_genes,reports)
@@ -414,8 +414,8 @@ def genome_domain(self, identity_dir, prefix):
         ar_gids = set()
         bac_ar_diff = {}
         for gid in bac_count:
-            arc_aa_per = (ar_count[gid] * 100.0 / Config.AR_MARKER_COUNT)
-            bac_aa_per = (bac_count[gid] * 100.0 / Config.BAC_MARKER_COUNT)
+            arc_aa_per = (ar_count[gid] * 100.0 / CONFIG.AR_MARKER_COUNT)
+            bac_aa_per = (bac_count[gid] * 100.0 / CONFIG.BAC_MARKER_COUNT)
             if bac_aa_per >= arc_aa_per:
                 bac_gids.add(gid)
             else:
@@ -534,8 +534,8 @@ def align(self,
 
         self.logger.info(
             f'Aligning markers in {len(genomic_files):,} genomes with {self.cpus} CPUs.')
-        dom_iter = ((bac_gids, Config.CONCAT_BAC120, Config.MASK_BAC120, "bac120", 'bacterial', CopyNumberFileBAC120),
-                    (ar_gids, Config.CONCAT_AR53, Config.MASK_AR53, "ar53", 'archaeal', CopyNumberFileAR53))
+        dom_iter = ((bac_gids, CONFIG.CONCAT_BAC120, CONFIG.MASK_BAC120, "bac120", 'bacterial', CopyNumberFileBAC120),
+                    (ar_gids, CONFIG.CONCAT_AR53, CONFIG.MASK_AR53, "ar53", 'archaeal', CopyNumberFileAR53))
 
         # For some genomes, it is possible to have no markers.
         no_marker_gids = bac_gids.union(ar_gids)
@@ -576,7 +576,7 @@ def align(self,
                                                     gtdb_taxonomy,
                                                     taxa_filter,
                                                     outgroup_taxon)
-            gtdb_msa_mask = os.path.join(Config.MASK_DIR, mask_file)
+            gtdb_msa_mask = os.path.join(CONFIG.MASK_DIR, mask_file)
 
             # Generate the user MSA.
             user_msa = align.align_marker_set(
@@ -641,7 +641,7 @@ def align(self,
                     self.logger.info(
                         f'Filtered genomes include {len(filtered_user_genomes)} user submitted genomes.')
             else:
-                self.logger.log(Config.LOG_TASK,
+                self.logger.log(CONFIG.LOG_TASK,
                                 f'Masking columns of {domain_str} multiple sequence alignment using canonical mask.')
                 trimmed_seqs, pruned_seqs = self._apply_mask(gtdb_msa,
                                                             user_msa,
diff --git a/gtdbtk/misc.py b/gtdbtk/misc.py
index 32457539..925ea0e4 100644
--- a/gtdbtk/misc.py
+++ b/gtdbtk/misc.py
@@ -22,7 +22,8 @@
 
 import dendropy
 
-import gtdbtk.config.config as Config
+from gtdbtk.biolib_lite.taxonomy import Taxonomy
+from gtdbtk.config.common import CONFIG
 from gtdbtk.biolib_lite.execute import check_dependencies
 from gtdbtk.biolib_lite.logger import colour
 from gtdbtk.biolib_lite.newick import parse_label
@@ -53,9 +54,9 @@ def trim_msa(self, untrimmed_msa, mask_type, maskid, output_file):
             The path to the output trimmed MSA.
         """
         if maskid == 'bac' and mask_type == 'reference':
-            mask = os.path.join(Config.MASK_DIR, Config.MASK_BAC120)
+            mask = os.path.join(CONFIG.MASK_DIR, CONFIG.MASK_BAC120)
         elif maskid == 'arc' and mask_type == 'reference':
-            mask = os.path.join(Config.MASK_DIR, Config.MASK_AR53)
+            mask = os.path.join(CONFIG.MASK_DIR, CONFIG.MASK_AR53)
         elif mask_type == 'file':
             mask = maskid
         else:
@@ -158,6 +159,52 @@ def convert_to_itol(self, input_file, output_file):
 
         intree.write_to_path(output_file, schema='newick', suppress_rooting=True,unquoted_underscores=True)
 
+    def convert_to_species(self, input_file, output_file,custom_taxonomy_file=None,all_ranks=False):
+        """Change GTDB genomes ids to GTDb species name in the tree.
+
+        Parameters
+        ----------
+        input_file : str
+            The path to the input Newick tree.
+        output_file : str
+            The path to the output Newick tree.
+        """
+
+        self.logger.info("Convert GTDB-Tk tree...")
+        intree= dendropy.Tree.get_from_path(input_file,
+                                           schema='newick',
+                                           rooting='force-rooted',
+                                           preserve_underscores=True)
+
+        # get all leaves from the tree
+        leaves = intree.leaf_nodes()
+        #load the taxonomy file
+        taxonomy = Taxonomy().read(CONFIG.TAXONOMY_FILE)
+        #load the custom taxonomy file
+        if custom_taxonomy_file:
+            self.logger.info("Loading custom taxonomy file...")
+            custom_taxonomy = Taxonomy().read(custom_taxonomy_file)
+            #check intersection between custom taxonomy and taxonomy
+            intersection = set(custom_taxonomy.keys()).intersection(set(taxonomy.keys()))
+            if len(intersection) > 0:
+                self.logger.warning("{} genomes are present in both custom taxonomy and taxonomy file. The custom taxonomy will be used.".format(len(intersection)))
+            #update taxonomy with custom taxonomy
+            taxonomy.update(custom_taxonomy)
+
+
+        #get the species name for each genome
+        for leaf in leaves:
+            if leaf.taxon.label in taxonomy:
+                # get the label from parent node
+                if all_ranks:
+                    leaf.taxon.label = ';'.join(taxonomy[leaf.taxon.label])
+                else:
+                    leaf.taxon.label = taxonomy[leaf.taxon.label][-1]
+
+        #write the tree
+        intree.write_to_path(output_file, schema='newick', suppress_rooting=True,unquoted_underscores=True)
+
+
 
     def remove_intermediate_files(self,output_dir,wf_name):
         """Remove intermediate files.
@@ -190,7 +237,7 @@ def remove_intermediate_files(self,output_dir,wf_name):
                 shutil.rmtree(intermediate_infer)
         self.logger.info('Intermediate files removed.')
 
-    def check_install(self):
+    def check_install(self,db_version):
         """Check that all reference files exist.
 
         Returns
@@ -220,8 +267,10 @@ def check_install(self):
         ok = True
 
         # Compute the hash for each directory
-        self.logger.info(f'Checking integrity of reference package: {Config.GENERIC_PATH}')
-        for obj_path, expected_hash in Config.REF_HASHES.items():
+        self.logger.info(f'Checking integrity of reference package: {CONFIG.GENERIC_PATH}')
+        ref_hashes = CONFIG.get_REF_HASHES(db_version)
+
+        for obj_path, expected_hash in ref_hashes.items():
             base_name = obj_path[:-1] if obj_path.endswith('/') else obj_path
             base_name = base_name.split('/')[-1]
             user_hash = sha1_dir(obj_path, progress=True)
diff --git a/gtdbtk/pipeline/align.py b/gtdbtk/pipeline/align.py
index e64d214a..e0457228 100644
--- a/gtdbtk/pipeline/align.py
+++ b/gtdbtk/pipeline/align.py
@@ -5,7 +5,7 @@
 import tempfile
 from collections import defaultdict
 
-from gtdbtk.config.config import LOG_TASK
+from gtdbtk.config.common import CONFIG
 from gtdbtk.exceptions import GTDBTkExit
 from gtdbtk.external.hmm_aligner import HmmAligner
 from gtdbtk.files.marker.copy_number import CopyNumberFile
@@ -215,7 +215,7 @@ def align_marker_set(gid_dict, marker_info_file: MarkerInfoFile, copy_number_fil
     """
     logger = logging.getLogger('timestamp')
 
-    logger.log(LOG_TASK, f'Generating concatenated alignment for each marker.')
+    logger.log(CONFIG.LOG_TASK, f'Generating concatenated alignment for each marker.')
     single_copy_hits = get_single_copy_hits(gid_dict, copy_number_file, cpus)
 
     with tempfile.TemporaryDirectory(prefix='gtdbtk_tmp_') as dir_tmp:
@@ -230,7 +230,7 @@ def align_marker_set(gid_dict, marker_info_file: MarkerInfoFile, copy_number_fil
 
         # Run hmmalign on all of the markers (in order of largest)
         hmmer_v = HmmAligner.get_version()
-        logger.log(LOG_TASK, f'Aligning {len(marker_paths)} identified markers using hmmalign {hmmer_v}.')
+        logger.log(CONFIG.LOG_TASK, f'Aligning {len(marker_paths)} identified markers using hmmalign {hmmer_v}.')
         queue = list()
         for marker_id, marker_path in sorted(marker_paths.items(),
                                              key=lambda z: -marker_info_file.markers[z[0]]['size']):
diff --git a/gtdbtk/pipeline/export_msa.py b/gtdbtk/pipeline/export_msa.py
index 31340998..4f215c41 100644
--- a/gtdbtk/pipeline/export_msa.py
+++ b/gtdbtk/pipeline/export_msa.py
@@ -2,7 +2,7 @@
 from shutil import copyfile
 
 from gtdbtk.biolib_lite.common import make_sure_path_exists
-from gtdbtk.config.config import CONCAT_AR53, CONCAT_BAC120
+from gtdbtk.config.common import CONFIG
 from gtdbtk.exceptions import GTDBTkExit
 from gtdbtk.model.enum import Domain
 
@@ -14,9 +14,9 @@ def export_msa(domain: Domain, output_file: str):
     :param output_file: The path to write the MSA.
     """
     if domain is Domain.ARCHAEA:
-        file_to_export = CONCAT_AR53
+        file_to_export = CONFIG.CONCAT_AR53
     elif domain is Domain.BACTERIA:
-        file_to_export = CONCAT_BAC120
+        file_to_export = CONFIG.CONCAT_BAC120
     else:
         raise GTDBTkExit(f'Unknown domain: "{domain}"')
 
diff --git a/gtdbtk/split.py b/gtdbtk/split.py
index ee0c90db..b92547d5 100644
--- a/gtdbtk/split.py
+++ b/gtdbtk/split.py
@@ -18,7 +18,7 @@
 
 import logging
 
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 from gtdbtk.biolib_lite.common import make_sure_path_exists
 from gtdbtk.biolib_lite.newick import parse_label
 from gtdbtk.biolib_lite.seq_io import read_fasta
@@ -69,7 +69,7 @@ def get_high_pplacer_taxonomy(self, out_dir, marker_set_id, prefix, user_msa_fil
             self.logger.error('There was an error determining the marker set.')
             raise GenomeMarkerSetUnknown
 
-        red_bac_dict = Config.RED_DIST_BAC_DICT
+        red_bac_dict = CONFIG.RED_DIST_BAC_DICT
 
         # We get the pplacer taxonomy for comparison
         user_genome_ids = set(read_fasta(user_msa_file).keys())
diff --git a/gtdbtk/tools.py b/gtdbtk/tools.py
index 9022eb5a..77f33959 100644
--- a/gtdbtk/tools.py
+++ b/gtdbtk/tools.py
@@ -14,7 +14,7 @@
 import dendropy
 from tqdm import tqdm
 
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 from gtdbtk.config.output import CHECKSUM_SUFFIX
 from gtdbtk.exceptions import GTDBTkExit
 
@@ -34,7 +34,7 @@ def get_reference_ids():
         An immutable set with short and long accessions (e.g. GB_GCA_ and GCA_).
     """
     results = set()
-    with open(Config.TAXONOMY_FILE) as tf:
+    with open(CONFIG.TAXONOMY_FILE) as tf:
         for line in tf:
             raw_id = line.split('\t')[0]
             results.add(raw_id)
@@ -53,12 +53,12 @@ def get_ref_genomes():
         Dict[genome_id] = fasta_path
     """
     ref_genomes = dict()
-    with open(Config.FASTANI_GENOME_LIST) as g_path_file:
+    with open(CONFIG.FASTANI_GENOME_LIST) as g_path_file:
         for line in g_path_file:
             (full_name, path) = line.strip().split()
-            if full_name.endswith(Config.FASTANI_GENOMES_EXT):
-                accession = full_name.split(Config.FASTANI_GENOMES_EXT)[0]
-            ref_genomes[accession] = os.path.join(Config.FASTANI_DIR, path, full_name)
+            if full_name.endswith(CONFIG.FASTANI_GENOMES_EXT):
+                accession = full_name.split(CONFIG.FASTANI_GENOMES_EXT)[0]
+            ref_genomes[accession] = os.path.join(CONFIG.FASTANI_DIR, path, full_name)
     return ref_genomes
 
 def aa_percent_msa(aa_string):
@@ -290,11 +290,11 @@ def get_proc_memory_gb(pid):
 
 
 def get_gtdbtk_latest_version():
-    if not Config.GTDBTK_VER_CHECK:
+    if not CONFIG.GTDBTK_VER_CHECK:
         return None
     try:
         resp = json.loads(urllib.request.urlopen('https://pypi.org/pypi/gtdbtk/json',
-                                                 timeout=Config.GTDBTK_VER_TIMEOUT).read().decode('utf-8'))
+                                                 timeout=CONFIG.GTDBTK_VER_TIMEOUT).read().decode('utf-8'))
         return resp['info']['version']
     except Exception:
         return None


Test patch:
diff --git a/tests/test_classify.py b/tests/test_classify.py
index 2bfaec0f..3d65f522 100644
--- a/tests/test_classify.py
+++ b/tests/test_classify.py
@@ -22,7 +22,7 @@
 
 import dendropy
 
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 from gtdbtk.biolib_lite.taxonomy import Taxonomy
 from gtdbtk.classify import Classify
 from gtdbtk.config.output import *
@@ -38,7 +38,7 @@ def setUp(self):
         self.pplacer_dir_reference = 'tests/data/pplacer_dir_reference'
         self.aln_dir_ref = 'tests/data/align_dir_reference/align'
         self.user_msa_file = os.path.join(self.aln_dir_ref, 'gtdbtk.ar53.user_msa.fasta')
-        self.taxonomy_file = Config.TAXONOMY_FILE
+        self.taxonomy_file = CONFIG.TAXONOMY_FILE
         self.gtdb_taxonomy = Taxonomy().read(self.taxonomy_file)
 
     def tearDown(self):
diff --git a/tests/test_gtdbtk/test__main__.py b/tests/test_gtdbtk/test__main__.py
index 1f9dfd73..f2a5b040 100644
--- a/tests/test_gtdbtk/test__main__.py
+++ b/tests/test_gtdbtk/test__main__.py
@@ -20,7 +20,7 @@
 import tempfile
 import unittest
 
-from gtdbtk.config.config import CONCAT_AR53, CONCAT_BAC120, MASK_AR53, MASK_DIR, MASK_BAC120
+from gtdbtk.config.common import CONFIG
 from gtdbtk.files.classify_summary import ClassifySummaryFileAR53
 from gtdbtk.tools import sha256
 
@@ -176,14 +176,14 @@ def test_ani_rep(self):
 
     def test_trim_msa(self):
         path_out = os.path.join(self.dir_tmp, 'msa.faa')
-        args = ['python', '-m', 'gtdbtk', 'trim_msa', '--untrimmed_msa', CONCAT_AR53,
+        args = ['python', '-m', 'gtdbtk', 'trim_msa', '--untrimmed_msa', CONFIG.CONCAT_AR53,
                 '--output', path_out, '--reference_mask', 'arc']
         proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8')
         stdout, stderr = proc.communicate()
         self.assertEqual(proc.returncode, 0)
 
     def test_trim_msa_reference_mask_arc(self):
-        with open(os.path.join(MASK_DIR, MASK_AR53), 'r') as f:
+        with open(os.path.join(CONFIG.MASK_DIR, CONFIG.MASK_AR53), 'r') as f:
             mask = [x == '1' for x in f.read().strip()]
 
         path_untrimmed_msa = os.path.join(self.dir_tmp, 'untrimmed_msa.fasta')
@@ -217,7 +217,7 @@ def test_trim_msa_reference_mask_arc(self):
         self.assertDictEqual(results, expected)
 
     def test_trim_msa_reference_mask_bac(self):
-        with open(os.path.join(MASK_DIR, MASK_BAC120), 'r') as f:
+        with open(os.path.join(CONFIG.MASK_DIR, CONFIG.MASK_BAC120), 'r') as f:
             mask = [x == '1' for x in f.read().strip()]
 
         path_untrimmed_msa = os.path.join(self.dir_tmp, 'untrimmed_msa.fasta')
@@ -290,7 +290,7 @@ def test_export_msa_arc(self):
         self.assertEqual(p.returncode, 0)
 
         test_hash = sha256(path_output)
-        true_hash = sha256(CONCAT_AR53)
+        true_hash = sha256(CONFIG.CONCAT_AR53)
         self.assertEqual(test_hash, true_hash)
 
     def test_export_msa_bac(self):
@@ -302,7 +302,7 @@ def test_export_msa_bac(self):
         self.assertEqual(p.returncode, 0)
 
         test_hash = sha256(path_output)
-        true_hash = sha256(CONCAT_BAC120)
+        true_hash = sha256(CONFIG.CONCAT_BAC120)
         self.assertEqual(test_hash, true_hash)
 
     def test_test(self):
diff --git a/tests/test_gtdbtk/test_external/test_fastani.py b/tests/test_gtdbtk/test_external/test_fastani.py
index 47c6e14d..50ba6339 100644
--- a/tests/test_gtdbtk/test_external/test_fastani.py
+++ b/tests/test_gtdbtk/test_external/test_fastani.py
@@ -20,14 +20,14 @@
 import unittest
 import json
 from gtdbtk.external.fastani import FastANI
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 
 class TestFastANI(unittest.TestCase):
 
     def setUp(self):
         self.dir_tmp = tempfile.mkdtemp(prefix='gtdbtk_tmp_')
         self.cpus = 1
-        self.genome_root = Config.FASTANI_GENOMES
+        self.genome_root = CONFIG.FASTANI_GENOMES
 
     def tearDown(self):
         shutil.rmtree(self.dir_tmp)
diff --git a/tests/test_gtdbtk/test_external/test_fasttree.py b/tests/test_gtdbtk/test_external/test_fasttree.py
index cf6f723d..d4536c09 100644
--- a/tests/test_gtdbtk/test_external/test_fasttree.py
+++ b/tests/test_gtdbtk/test_external/test_fasttree.py
@@ -19,7 +19,7 @@
 import tempfile
 import unittest
 
-import gtdbtk.config.config as Config
+from gtdbtk.config.common import CONFIG
 from gtdbtk.external.fasttree import FastTree
 
 
@@ -28,7 +28,7 @@ class TestFastTree(unittest.TestCase):
     def setUp(self):
         self.dir_tmp = tempfile.mkdtemp(prefix='gtdbtk_tmp_')
         self.cpus = 1
-        self.genome_root = Config.FASTANI_GENOMES
+        self.genome_root = CONFIG.FASTANI_GENOMES
         self.test_msa = 'tests/data/example.faa'
         self.test_msa_gz = 'tests/data/example.faa.gz'