From a31df44eac2f07c4467b3541a16c6492b608d283 Mon Sep 17 00:00:00 2001
From: Markus Scheidgen <markus.scheidgen@gmail.com>
Date: Thu, 19 Mar 2020 12:24:30 +0100
Subject: [PATCH] Added python based metainfo definitions to all parsers.

---
 dependencies-git.sh                           |   21 +
 dependencies/nomad-meta-info                  |    2 +-
 dependencies/parsers/abinit                   |    2 +-
 dependencies/parsers/aptfim                   |    2 +-
 dependencies/parsers/atk                      |    2 +-
 dependencies/parsers/band                     |    2 +-
 dependencies/parsers/bigdft                   |    2 +-
 dependencies/parsers/castep                   |    2 +-
 dependencies/parsers/cp2k                     |    2 +-
 dependencies/parsers/cpmd                     |    2 +-
 dependencies/parsers/crystal                  |    2 +-
 dependencies/parsers/dl-poly                  |    2 +-
 dependencies/parsers/dmol3                    |    2 +-
 dependencies/parsers/eels                     |    2 +-
 dependencies/parsers/elastic                  |    2 +-
 dependencies/parsers/elk                      |    2 +-
 dependencies/parsers/exciting                 |    2 +-
 dependencies/parsers/fhi-aims                 |    2 +-
 dependencies/parsers/fleur                    |    2 +-
 dependencies/parsers/gamess                   |    2 +-
 dependencies/parsers/gaussian                 |    2 +-
 dependencies/parsers/gpaw                     |    2 +-
 dependencies/parsers/gulp                     |    2 +-
 dependencies/parsers/lib-atoms                |    2 +-
 dependencies/parsers/molcas                   |    2 +-
 dependencies/parsers/mpes                     |    2 +-
 dependencies/parsers/nwchem                   |    2 +-
 dependencies/parsers/octopus                  |    2 +-
 dependencies/parsers/onetep                   |    2 +-
 dependencies/parsers/orca                     |    2 +-
 dependencies/parsers/phonopy                  |    2 +-
 dependencies/parsers/photoemission            |    2 +-
 dependencies/parsers/qbox                     |    2 +-
 dependencies/parsers/quantum-espresso         |    2 +-
 dependencies/parsers/siesta                   |    2 +-
 dependencies/parsers/skeleton                 |    2 +-
 dependencies/parsers/turbomole                |    2 +-
 dependencies/parsers/vasp                     |    2 +-
 dependencies/parsers/wien2k                   |    2 +-
 dependencies/python_common                    |    2 +-
 nomad/cli/client/local.py                     |   20 +-
 nomad/cli/dev.py                              |   51 +-
 nomad/cli/parse.py                            |   44 +-
 nomad/datamodel/__init__.py                   |    2 +-
 nomad/datamodel/dft.py                        |   42 +-
 nomad/datamodel/ems.py                        |   10 +-
 nomad/datamodel/metainfo/common.py            |  448 +++--
 nomad/datamodel/metainfo/general.py           |   58 +-
 .../metainfo/general_experimental.py          |  112 ++
 .../metainfo/general_experimental_data.py     |   30 +
 .../metainfo/general_experimental_method.py   |   67 +
 .../metainfo/general_experimental_sample.py   |  127 ++
 nomad/datamodel/metainfo/public.py            | 1765 +++++++++++------
 nomad/metainfo/__init__.py                    |    1 +
 nomad/metainfo/legacy.py                      |  175 +-
 nomad/metainfo/metainfo.py                    |   93 +-
 nomad/metainfo/templates/environment.j2       |    4 +-
 nomad/metainfo/templates/package.j2           |   30 +-
 nomad/normalizing/dos.py                      |    2 +-
 nomad/normalizing/fhiaims.py                  |    9 +-
 nomad/normalizing/normalizer.py               |   29 +-
 nomad/normalizing/optimade.py                 |    2 +
 nomad/normalizing/system.py                   |    4 +-
 nomad/parsing/__init__.py                     |   30 +-
 nomad/parsing/artificial.py                   |   28 +-
 nomad/parsing/backend.py                      |  608 ------
 nomad/parsing/legacy.py                       |  592 ++++++
 nomad/parsing/metainfo.py                     |  321 ---
 nomad/parsing/parser.py                       |   89 +-
 nomad/processing/data.py                      |   12 +-
 requirements.txt                              |    1 -
 tests/app/test_api.py                         |    9 +-
 tests/app/test_optimade.py                    |   21 +-
 tests/conftest.py                             |   29 +-
 tests/data/parsers/template_no_system.json    |    1 -
 .../proc/examples_with_warning_template.zip   |  Bin 1965 -> 1966 bytes
 tests/metainfo/test_legacy.py                 |   46 +-
 tests/metainfo/test_metainfo.py               |   32 +-
 tests/parser_measurement.py                   |    4 +-
 tests/processing/test_data.py                 |    5 +-
 tests/test_cli.py                             |    3 +-
 tests/test_datamodel.py                       |    6 +-
 tests/test_files.py                           |    4 +-
 tests/test_normalizing.py                     |   57 +-
 tests/test_parsing.py                         |  138 +-
 tests/test_search.py                          |   10 +-
 tests/test_utils.py                           |    5 +-
 tests/utils.py                                |   17 -
 88 files changed, 3022 insertions(+), 2270 deletions(-)
 create mode 100755 dependencies-git.sh
 create mode 100644 nomad/datamodel/metainfo/general_experimental.py
 create mode 100644 nomad/datamodel/metainfo/general_experimental_data.py
 create mode 100644 nomad/datamodel/metainfo/general_experimental_method.py
 create mode 100644 nomad/datamodel/metainfo/general_experimental_sample.py
 delete mode 100644 nomad/parsing/backend.py
 create mode 100644 nomad/parsing/legacy.py
 delete mode 100644 nomad/parsing/metainfo.py

diff --git a/dependencies-git.sh b/dependencies-git.sh
new file mode 100755
index 0000000000..9d8677f0f7
--- /dev/null
+++ b/dependencies-git.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+set -e
+working_dir=`pwd`
+echo $working_dir
+
+git config -f .gitmodules --get-regexp '^submodule\..*\.path$' |
+    while read path_key path
+    do
+        cd $working_dir
+        cd $path
+        if [ -z "$(git status --porcelain)" ]; then
+            echo "$path is clean"
+        else
+            echo "$path is not clean"
+            git checkout -b nomad-fair-metainfo
+            git add -A
+            git commit -a -m "Added metainfo python code."
+            git push origin nomad-fair-metainfo
+        fi
+    done
diff --git a/dependencies/nomad-meta-info b/dependencies/nomad-meta-info
index ad28fc1d47..ce3d4e85ed 160000
--- a/dependencies/nomad-meta-info
+++ b/dependencies/nomad-meta-info
@@ -1 +1 @@
-Subproject commit ad28fc1d4787f31999b2be6ebec7ffd98bf0a3bb
+Subproject commit ce3d4e85edbd978e1a2f0ff9f9ab2137d7ee1211
diff --git a/dependencies/parsers/abinit b/dependencies/parsers/abinit
index 142ba39f70..dc168fb235 160000
--- a/dependencies/parsers/abinit
+++ b/dependencies/parsers/abinit
@@ -1 +1 @@
-Subproject commit 142ba39f70ec298818775028631db4037494dbb0
+Subproject commit dc168fb235d76a8bbf28c826894eb5b82bc8e6f3
diff --git a/dependencies/parsers/aptfim b/dependencies/parsers/aptfim
index 95b3874b72..d576cd09e8 160000
--- a/dependencies/parsers/aptfim
+++ b/dependencies/parsers/aptfim
@@ -1 +1 @@
-Subproject commit 95b3874b72035d0529f7dd0cde419192dba68100
+Subproject commit d576cd09e81d02769d8f65f43a0ad3f51e22cd4c
diff --git a/dependencies/parsers/atk b/dependencies/parsers/atk
index 8e6def6b73..cb91cdd843 160000
--- a/dependencies/parsers/atk
+++ b/dependencies/parsers/atk
@@ -1 +1 @@
-Subproject commit 8e6def6b737a195231754f170f6df227096b00c6
+Subproject commit cb91cdd8433d4071b1eca035e28d13f40f50148b
diff --git a/dependencies/parsers/band b/dependencies/parsers/band
index d30ef0bd92..f98b920976 160000
--- a/dependencies/parsers/band
+++ b/dependencies/parsers/band
@@ -1 +1 @@
-Subproject commit d30ef0bd9275206380866c89946a0c129e7d8df9
+Subproject commit f98b920976d5507c9584676e8f77071bcf041cf9
diff --git a/dependencies/parsers/bigdft b/dependencies/parsers/bigdft
index 42b2b0ea89..e1a03db77a 160000
--- a/dependencies/parsers/bigdft
+++ b/dependencies/parsers/bigdft
@@ -1 +1 @@
-Subproject commit 42b2b0ea894aa83cda9588d3d9bf2cdee1f40a92
+Subproject commit e1a03db77aa4acb3f7f55691e11f1277a2ca6726
diff --git a/dependencies/parsers/castep b/dependencies/parsers/castep
index f9979f05e6..1d1bc7902f 160000
--- a/dependencies/parsers/castep
+++ b/dependencies/parsers/castep
@@ -1 +1 @@
-Subproject commit f9979f05e6a26e0512c26d5a316f4b0749528640
+Subproject commit 1d1bc7902fe397b80cae97b15949ad1ab10798cf
diff --git a/dependencies/parsers/cp2k b/dependencies/parsers/cp2k
index b87cd29be9..5742af2804 160000
--- a/dependencies/parsers/cp2k
+++ b/dependencies/parsers/cp2k
@@ -1 +1 @@
-Subproject commit b87cd29be9fe1637c20a23087ce98855ff1fea44
+Subproject commit 5742af2804e002b49bed42a0d5f38f8a79630697
diff --git a/dependencies/parsers/cpmd b/dependencies/parsers/cpmd
index a8b323f8f8..e3a0ab05c4 160000
--- a/dependencies/parsers/cpmd
+++ b/dependencies/parsers/cpmd
@@ -1 +1 @@
-Subproject commit a8b323f8f8b24a5cead4c7e0cca15a78193b12b5
+Subproject commit e3a0ab05c403a97155ffc8bdc1a9c8321b1c4278
diff --git a/dependencies/parsers/crystal b/dependencies/parsers/crystal
index 7863212e4b..24a12012ef 160000
--- a/dependencies/parsers/crystal
+++ b/dependencies/parsers/crystal
@@ -1 +1 @@
-Subproject commit 7863212e4bde3443fae8fbb57caf3b0d95fb28f3
+Subproject commit 24a12012effc70d296ec45dcc0bd5fbeb0a0b2ff
diff --git a/dependencies/parsers/dl-poly b/dependencies/parsers/dl-poly
index de6d49f897..21a5354148 160000
--- a/dependencies/parsers/dl-poly
+++ b/dependencies/parsers/dl-poly
@@ -1 +1 @@
-Subproject commit de6d49f89748010236baa9b683464b70bc8507a6
+Subproject commit 21a5354148aa5c08c7128bdf92e4a6d5347aa58e
diff --git a/dependencies/parsers/dmol3 b/dependencies/parsers/dmol3
index 247efac742..de8f0f37aa 160000
--- a/dependencies/parsers/dmol3
+++ b/dependencies/parsers/dmol3
@@ -1 +1 @@
-Subproject commit 247efac74234a9c53f3a792e1027ba995b887bb6
+Subproject commit de8f0f37aa37ea6c4f7b0e76ce38165b2a54e6ae
diff --git a/dependencies/parsers/eels b/dependencies/parsers/eels
index ed3d77fdb5..38ed55429b 160000
--- a/dependencies/parsers/eels
+++ b/dependencies/parsers/eels
@@ -1 +1 @@
-Subproject commit ed3d77fdb5c16ebc11c9a8b509fe5cdbc57674fd
+Subproject commit 38ed55429bd8c2289471c5dbc162bcdd80b7bb94
diff --git a/dependencies/parsers/elastic b/dependencies/parsers/elastic
index 523a9c202a..dddddaa0f9 160000
--- a/dependencies/parsers/elastic
+++ b/dependencies/parsers/elastic
@@ -1 +1 @@
-Subproject commit 523a9c202aa97612ed616f6545e4f84882a4687f
+Subproject commit dddddaa0f933d5a38b479ffdd90a95654e9df133
diff --git a/dependencies/parsers/elk b/dependencies/parsers/elk
index d08b1f7f62..a6dbd8ceb4 160000
--- a/dependencies/parsers/elk
+++ b/dependencies/parsers/elk
@@ -1 +1 @@
-Subproject commit d08b1f7f6273c9e8b857a43cb76956cba2040df9
+Subproject commit a6dbd8ceb4f26f76477487b1b3e91b071a74d5d9
diff --git a/dependencies/parsers/exciting b/dependencies/parsers/exciting
index 528f355e6a..3be1e3eeb7 160000
--- a/dependencies/parsers/exciting
+++ b/dependencies/parsers/exciting
@@ -1 +1 @@
-Subproject commit 528f355e6a7835f630db41fbfa8a9dae4be4991a
+Subproject commit 3be1e3eeb79c2587fec37b9c29a0a0ea8d45c6f7
diff --git a/dependencies/parsers/fhi-aims b/dependencies/parsers/fhi-aims
index d41ed9c3e6..c9e833f1e1 160000
--- a/dependencies/parsers/fhi-aims
+++ b/dependencies/parsers/fhi-aims
@@ -1 +1 @@
-Subproject commit d41ed9c3e636b1638e904b6459262a610c62dad2
+Subproject commit c9e833f1e1483ae162563619e4b6e093522ffaaa
diff --git a/dependencies/parsers/fleur b/dependencies/parsers/fleur
index 7617a48711..6d446f7791 160000
--- a/dependencies/parsers/fleur
+++ b/dependencies/parsers/fleur
@@ -1 +1 @@
-Subproject commit 7617a487113450d394d2091dda29766f1632cb3c
+Subproject commit 6d446f779116b5fd5b9d2a377093442ecaf3d951
diff --git a/dependencies/parsers/gamess b/dependencies/parsers/gamess
index 75a5cd92db..46704661bf 160000
--- a/dependencies/parsers/gamess
+++ b/dependencies/parsers/gamess
@@ -1 +1 @@
-Subproject commit 75a5cd92dbd6299067e0fca0b9949f8b4410ec91
+Subproject commit 46704661bf408e1feb705a4b7327bb14f4b42f9b
diff --git a/dependencies/parsers/gaussian b/dependencies/parsers/gaussian
index 022a2af6ba..795f1076a6 160000
--- a/dependencies/parsers/gaussian
+++ b/dependencies/parsers/gaussian
@@ -1 +1 @@
-Subproject commit 022a2af6bad45364dbdfac6b6c913f04186ac7d4
+Subproject commit 795f1076a66d6f5cc92d16d5c6c8c4acb81170c3
diff --git a/dependencies/parsers/gpaw b/dependencies/parsers/gpaw
index f5be159e49..496153077e 160000
--- a/dependencies/parsers/gpaw
+++ b/dependencies/parsers/gpaw
@@ -1 +1 @@
-Subproject commit f5be159e49f643d220497726da9801138ed615c3
+Subproject commit 496153077ee8ab82c2d88739357e1a9c65563a37
diff --git a/dependencies/parsers/gulp b/dependencies/parsers/gulp
index e113cbf21f..34af403cf6 160000
--- a/dependencies/parsers/gulp
+++ b/dependencies/parsers/gulp
@@ -1 +1 @@
-Subproject commit e113cbf21f23054394ad6099ad4836cbd9e21790
+Subproject commit 34af403cf64aa18a495847d98a6a2628ae6b8229
diff --git a/dependencies/parsers/lib-atoms b/dependencies/parsers/lib-atoms
index 22bc82b9d4..c0de955c66 160000
--- a/dependencies/parsers/lib-atoms
+++ b/dependencies/parsers/lib-atoms
@@ -1 +1 @@
-Subproject commit 22bc82b9d41354cfb571b2659e317ec376c9eb08
+Subproject commit c0de955c6625357aedbade5926cf4ca38f586ff6
diff --git a/dependencies/parsers/molcas b/dependencies/parsers/molcas
index da34ee2d16..14a38b8beb 160000
--- a/dependencies/parsers/molcas
+++ b/dependencies/parsers/molcas
@@ -1 +1 @@
-Subproject commit da34ee2d16407db1a25e96de518f8b67618b86c8
+Subproject commit 14a38b8beb77ef587450e1490a79b01527c8946e
diff --git a/dependencies/parsers/mpes b/dependencies/parsers/mpes
index e772c6d954..124b42b985 160000
--- a/dependencies/parsers/mpes
+++ b/dependencies/parsers/mpes
@@ -1 +1 @@
-Subproject commit e772c6d954009d7b3419200ffd370f55fd62c1a4
+Subproject commit 124b42b9851329682e11c2f1f3e00056d215bd3b
diff --git a/dependencies/parsers/nwchem b/dependencies/parsers/nwchem
index 179c4ce3e0..1d6b84386a 160000
--- a/dependencies/parsers/nwchem
+++ b/dependencies/parsers/nwchem
@@ -1 +1 @@
-Subproject commit 179c4ce3e0990b431869a7d644590689e91f8fe2
+Subproject commit 1d6b84386a07d30b214d16922db43ad1c3b08fe5
diff --git a/dependencies/parsers/octopus b/dependencies/parsers/octopus
index f564234759..00ebfda7b9 160000
--- a/dependencies/parsers/octopus
+++ b/dependencies/parsers/octopus
@@ -1 +1 @@
-Subproject commit f5642347597ec378d897d35b03209ad2e2cc1f8f
+Subproject commit 00ebfda7b98dd37498ff855316f0009c12e052a4
diff --git a/dependencies/parsers/onetep b/dependencies/parsers/onetep
index 40c58ba15f..7abec2b259 160000
--- a/dependencies/parsers/onetep
+++ b/dependencies/parsers/onetep
@@ -1 +1 @@
-Subproject commit 40c58ba15fe6434aa8522770dec3650385ad22f9
+Subproject commit 7abec2b2598d8d479c34ebe45068ae53757fc5dd
diff --git a/dependencies/parsers/orca b/dependencies/parsers/orca
index 9b5f343563..783bb929a8 160000
--- a/dependencies/parsers/orca
+++ b/dependencies/parsers/orca
@@ -1 +1 @@
-Subproject commit 9b5f343563313ca1ad8fc84f8fc127eeba64e42b
+Subproject commit 783bb929a82f748a813eba40b16f7df973aa22d3
diff --git a/dependencies/parsers/phonopy b/dependencies/parsers/phonopy
index ae1f7175be..c6fe788d94 160000
--- a/dependencies/parsers/phonopy
+++ b/dependencies/parsers/phonopy
@@ -1 +1 @@
-Subproject commit ae1f7175bea210eff43d52a30a454f4f9acce30b
+Subproject commit c6fe788d944699e2d15a55d4cb846649971eb2a9
diff --git a/dependencies/parsers/photoemission b/dependencies/parsers/photoemission
index 51ad1335ac..fc29369476 160000
--- a/dependencies/parsers/photoemission
+++ b/dependencies/parsers/photoemission
@@ -1 +1 @@
-Subproject commit 51ad1335acc2ab3cffac57117a7cfaa63e092103
+Subproject commit fc29369476e84f8d95de4ef1bdf6d1ce2f55cdc9
diff --git a/dependencies/parsers/qbox b/dependencies/parsers/qbox
index f914e0c0ba..f5f7ae8ceb 160000
--- a/dependencies/parsers/qbox
+++ b/dependencies/parsers/qbox
@@ -1 +1 @@
-Subproject commit f914e0c0bafc0922ab77a4347462a15b62d2efa7
+Subproject commit f5f7ae8cebbf3f81baf1e5116d6300af9c1af509
diff --git a/dependencies/parsers/quantum-espresso b/dependencies/parsers/quantum-espresso
index d60013e159..ca6d9a765c 160000
--- a/dependencies/parsers/quantum-espresso
+++ b/dependencies/parsers/quantum-espresso
@@ -1 +1 @@
-Subproject commit d60013e1597493972237210a36549bfcf0a2706f
+Subproject commit ca6d9a765cda0f67f3b78e820c5590bf6ed250cf
diff --git a/dependencies/parsers/siesta b/dependencies/parsers/siesta
index 0feea3bb5a..9185e1b7a0 160000
--- a/dependencies/parsers/siesta
+++ b/dependencies/parsers/siesta
@@ -1 +1 @@
-Subproject commit 0feea3bb5aeb2847cde41c4d642c6b5af8e38cd5
+Subproject commit 9185e1b7a00e7d4844e5ad5cbce27b0b6b9d542d
diff --git a/dependencies/parsers/skeleton b/dependencies/parsers/skeleton
index c0e9362469..3054fcd440 160000
--- a/dependencies/parsers/skeleton
+++ b/dependencies/parsers/skeleton
@@ -1 +1 @@
-Subproject commit c0e936246972c0fb98b9b9c96a67167f1725156f
+Subproject commit 3054fcd44013c78b55a784328b99c16ffd32710c
diff --git a/dependencies/parsers/turbomole b/dependencies/parsers/turbomole
index f2b7f39ca6..41c2473940 160000
--- a/dependencies/parsers/turbomole
+++ b/dependencies/parsers/turbomole
@@ -1 +1 @@
-Subproject commit f2b7f39ca62438d25a21cdbaf267269fbc4f62ac
+Subproject commit 41c2473940d66aaa64788c5d97abf1eb12bd941e
diff --git a/dependencies/parsers/vasp b/dependencies/parsers/vasp
index 6e4654fa3b..3de50ada36 160000
--- a/dependencies/parsers/vasp
+++ b/dependencies/parsers/vasp
@@ -1 +1 @@
-Subproject commit 6e4654fa3b016fa099104d3f33078c510c980434
+Subproject commit 3de50ada3666413015907c27d64970edd2736f10
diff --git a/dependencies/parsers/wien2k b/dependencies/parsers/wien2k
index 628e4b3330..02386cdfc1 160000
--- a/dependencies/parsers/wien2k
+++ b/dependencies/parsers/wien2k
@@ -1 +1 @@
-Subproject commit 628e4b333004ffa7636b70a99b13efea606119e1
+Subproject commit 02386cdfc1e7e98f1c829c3951c798274d829fc2
diff --git a/dependencies/python_common b/dependencies/python_common
index fc60b6cfb9..5d33cd54d8 160000
--- a/dependencies/python_common
+++ b/dependencies/python_common
@@ -1 +1 @@
-Subproject commit fc60b6cfb902e1bf493a57d398e5b364f2153a9d
+Subproject commit 5d33cd54d81a8f0b9370fc57dd551b95891050fe
diff --git a/nomad/cli/client/local.py b/nomad/cli/client/local.py
index 427210522e..450c7f40b1 100644
--- a/nomad/cli/client/local.py
+++ b/nomad/cli/client/local.py
@@ -19,13 +19,13 @@ import requests
 import click
 from typing import Union, Callable
 import sys
-import ujson
 import bravado.exception
+import json
 
 from nomad import config, utils
 from nomad.files import ArchiveBasedStagingUploadFiles
 from nomad.datamodel import EntryMetadata
-from nomad.parsing import LocalBackend
+from nomad.parsing import Backend
 from nomad.cli.parse import parse, normalize, normalize_all
 
 from .client import client
@@ -124,14 +124,16 @@ class CalcProcReproduction:
     def __exit__(self, *args):
         self.upload_files.delete()
 
-    def parse(self, parser_name: str = None, **kwargs) -> LocalBackend:
+    def parse(self, parser_name: str = None, **kwargs) -> Backend:
         '''
         Run the given parser on the downloaded calculation. If no parser is given,
         do parser matching and use the respective parser.
         '''
-        return parse(self.mainfile, self.upload_files, parser_name=parser_name, logger=self.logger, **kwargs)
+        return parse(
+            self.upload_files.raw_file_object(self.mainfile).os_path,
+            parser_name=parser_name, logger=self.logger, **kwargs)
 
-    def normalize(self, normalizer: Union[str, Callable], parser_backend: LocalBackend = None):
+    def normalize(self, normalizer: Union[str, Callable], parser_backend: Backend = None):
         '''
         Parse the downloaded calculation and run the given normalizer.
         '''
@@ -140,7 +142,7 @@ class CalcProcReproduction:
 
         return normalize(parser_backend=parser_backend, normalizer=normalizer, logger=self.logger)
 
-    def normalize_all(self, parser_backend: LocalBackend = None):
+    def normalize_all(self, parser_backend: Backend = None):
         '''
         Parse the downloaded calculation and run the whole normalizer chain.
         '''
@@ -170,9 +172,9 @@ def local(calc_id, show_backend, show_metadata, skip_normalizers, not_strict, **
             local.normalize_all(parser_backend=backend)
 
         if show_backend:
-            backend.write_json(sys.stdout, pretty=True)
+            json.dump(backend.resource.m_to_dict(), sys.stdout, indent=2)
 
         if show_metadata:
-            metadata = EntryMetadata(domain=local.parser.domain)
+            metadata = EntryMetadata(domain='dft')  # TODO take domain from matched parser
             metadata.apply_domain_metadata(backend)
-            ujson.dump(metadata.m_to_dict(), sys.stdout, indent=4)
+            json.dump(metadata.m_to_dict(), sys.stdout, indent=4)
diff --git a/nomad/cli/dev.py b/nomad/cli/dev.py
index 82a73709e7..adfe436745 100644
--- a/nomad/cli/dev.py
+++ b/nomad/cli/dev.py
@@ -45,9 +45,52 @@ def qa(skip_tests: bool, exitfirst: bool):
 
 
 @dev.command(help='Generates source-code for the new metainfo from .json files of the old.')
-@click.argument('package', nargs=1)
-def legacy_metainfo(package):
+@click.argument('path', nargs=-1)
+def legacy_metainfo(path):
     from nomad.metainfo.legacy import convert, generate_metainfo_code
 
-    env = convert(package)
-    generate_metainfo_code(env)
+    if len(path) == 0:
+        path = [
+            'abinit.nomadmetainfo.json',
+            'aptfim.nomadmetainfo.json',
+            'atk.nomadmetainfo.json',
+            'band.nomadmetainfo.json',
+            'bigdft.nomadmetainfo.json',
+            'castep.nomadmetainfo.json',
+            'cp2k.nomadmetainfo.json',
+            'cpmd.nomadmetainfo.json',
+            'crystal.nomadmetainfo.json',
+            'dl_poly.nomadmetainfo.json',
+            'dmol3.nomadmetainfo.json',
+            'eels.nomadmetainfo.json',
+            'elastic.nomadmetainfo.json',
+            'elk.nomadmetainfo.json',
+            'exciting.nomadmetainfo.json',
+            'fhi_aims.nomadmetainfo.json',
+            'fleur.nomadmetainfo.json',
+            'gamess.nomadmetainfo.json',
+            'gaussian.nomadmetainfo.json',
+            'gpaw.nomadmetainfo.json',
+            'gulp.nomadmetainfo.json',
+            'lib_atoms.nomadmetainfo.json',
+            'molcas.nomadmetainfo.json',
+            'mpes.nomadmetainfo.json',
+            'nwchem.nomadmetainfo.json',
+            'octopus.nomadmetainfo.json',
+            'onetep.nomadmetainfo.json',
+            'orca.nomadmetainfo.json',
+            'phonopy.nomadmetainfo.json',
+            'photoemission.nomadmetainfo.json',
+            'qbox.nomadmetainfo.json',
+            'quantum_espresso.nomadmetainfo.json',
+            'siesta.nomadmetainfo.json',
+            'skeleton.nomadmetainfo.json',
+            'turbomole.nomadmetainfo.json',
+            'vasp.nomadmetainfo.json',
+            'wien2k.nomadmetainfo.json',
+            'dft.nomadmetainfo.json',
+            'ems.nomadmetainfo.json']
+
+    for element in path:
+        env = convert(element)
+        generate_metainfo_code(env)
diff --git a/nomad/cli/parse.py b/nomad/cli/parse.py
index a1433f1195..55e39848ef 100644
--- a/nomad/cli/parse.py
+++ b/nomad/cli/parse.py
@@ -4,9 +4,8 @@ import json
 import click
 import sys
 
-from nomad import config, utils, files
-from nomad.parsing import LocalBackend, parser_dict, match_parser, MatchingParser, MetainfoBackend
-from nomad.metainfo.legacy import convert
+from nomad import config, utils
+from nomad.parsing import Backend, parser_dict, match_parser, MatchingParser
 from nomad.normalizing import normalizers
 from nomad.datamodel import EntryMetadata
 
@@ -16,21 +15,23 @@ from .cli import cli
 
 
 def parse(
-        mainfile: str, upload_files: Union[str, files.StagingUploadFiles],
+        mainfile_path: str,
         parser_name: str = None,
         backend_factory: Callable = None,
-        strict: bool = True, logger=None) -> LocalBackend:
+        strict: bool = True, logger=None) -> Backend:
     '''
     Run the given parser on the downloaded calculation. If no parser is given,
     do parser matching and use the respective parser.
     '''
+    mainfile = os.path.basename(mainfile_path)
+
     if logger is None:
         logger = utils.get_logger(__name__)
     if parser_name is not None:
         parser = parser_dict.get(parser_name)
         assert parser is not None, 'the given parser must exist'
     else:
-        parser = match_parser(mainfile, upload_files, strict=strict)
+        parser = match_parser(mainfile_path, strict=strict)
         if isinstance(parser, MatchingParser):
             parser_name = parser.name
         else:
@@ -42,11 +43,6 @@ def parse(
     if hasattr(parser, 'backend_factory'):
         setattr(parser, 'backend_factory', backend_factory)
 
-    if isinstance(upload_files, str):
-        mainfile_path = os.path.join(upload_files, mainfile)
-    else:
-        mainfile_path = upload_files.raw_file_object(mainfile).os_path
-
     parser_backend = parser.run(mainfile_path, logger=logger)
 
     if not parser_backend.status[0] == 'ParseSuccess':
@@ -65,8 +61,8 @@ def parse(
 
 
 def normalize(
-        normalizer: Union[str, Callable], parser_backend: LocalBackend = None,
-        logger=None) -> LocalBackend:
+        normalizer: Union[str, Callable], parser_backend: Backend = None,
+        logger=None) -> Backend:
 
     if logger is None:
         logger = utils.get_logger(__name__)
@@ -86,7 +82,7 @@ def normalize(
     return parser_backend
 
 
-def normalize_all(parser_backend: LocalBackend = None, logger=None) -> LocalBackend:
+def normalize_all(parser_backend: Backend = None, logger=None) -> Backend:
     '''
     Parse the downloaded calculation and run the whole normalizer chain.
     '''
@@ -105,36 +101,24 @@ def normalize_all(parser_backend: LocalBackend = None, logger=None) -> LocalBack
 @click.option('--skip-normalizers', is_flag=True, default=False, help='Do not run the normalizer.')
 @click.option('--not-strict', is_flag=True, help='Do also match artificial parsers.')
 @click.option('--parser', help='Skip matching and use the provided parser')
-@click.option('--metainfo', is_flag=True, help='Use the new metainfo instead of the legacy metainfo.')
 @click.option('--annotate', is_flag=True, help='Sub-matcher based parsers will create a .annotate file.')
 def _parse(
         mainfile, show_backend, show_metadata, skip_normalizers, not_strict, parser,
-        metainfo, annotate):
+        annotate):
 
     simple_parser.annotate = annotate
 
     utils.configure_logging()
     kwargs = dict(strict=not not_strict, parser_name=parser)
 
-    if metainfo:
-
-        def backend_factory(env, logger):
-            # from vaspparser.metainfo import m_env
-            # from nomad.metainfo import Section
-            # m_env.resolve_definition('section_basis_set_atom_centered', Section)
-            # return MetainfoBackend(m_env, logger=logger)
-
-            return MetainfoBackend(convert(env), logger=logger)
-
-        kwargs.update(backend_factory=backend_factory)
-
-    backend = parse(mainfile, '.', **kwargs)
+    backend = parse(mainfile, **kwargs)
 
     if not skip_normalizers:
         normalize_all(backend)
 
     if show_backend:
-        backend.write_json(sys.stdout, pretty=True)
+        json.dump(backend.resource.m_to_dict(), sys.stdout, indent=2)
+
     if show_metadata:
         metadata = EntryMetadata(domain='dft')  # TODO take domain from matched parser
         metadata.apply_domain_metadata(backend)
diff --git a/nomad/datamodel/__init__.py b/nomad/datamodel/__init__.py
index cd336e3c6a..c3fea7df96 100644
--- a/nomad/datamodel/__init__.py
+++ b/nomad/datamodel/__init__.py
@@ -72,4 +72,4 @@ domains = {
     }
 }
 
-root_sections = [domain['root_section'] for domain in domains.values()] + ['section_entry_info']
+root_sections = [domain['root_section'] for domain in domains.values()] + ['section_entry_info', 'OptimadeEntry']
diff --git a/nomad/datamodel/dft.py b/nomad/datamodel/dft.py
index e4d6d89200..909ee11f7f 100644
--- a/nomad/datamodel/dft.py
+++ b/nomad/datamodel/dft.py
@@ -18,14 +18,13 @@ DFT specific metadata
 
 import re
 
-from nomadcore.local_backend import ParserEvent
-
 from nomad import utils, config
 from nomad.metainfo import MSection, Section, Quantity, MEnum, SubSection
 from nomad.metainfo.search_extension import Search
 
 from .common import get_optional_backend_value
 from .optimade import OptimadeEntry
+from .metainfo.public import section_run
 
 
 xc_treatments = {
@@ -175,18 +174,6 @@ class DFTMetadata(MSection):
         description='Metadata used for the optimade API.',
         a_search='optimade')
 
-    def m_update(self, **kwargs):
-        # TODO necessary?
-        if 'labels' in kwargs:
-            print('########################## A')
-            self.labels = [Label.m_from_dict(label) for label in kwargs.pop('labels')]
-
-        if 'optimade' in kwargs:
-            print('########################## B')
-            self.optimade = OptimadeEntry.m_from_dict(kwargs.pop('optimade'))
-
-        super().m_update(**kwargs)
-
     def apply_domain_metadata(self, backend):
         from nomad.normalizing.system import normalized_atom_labels
         entry = self.m_parent
@@ -248,23 +235,28 @@ class DFTMetadata(MSection):
         n_total_energies = 0
         n_geometries = 0
 
-        for meta_info, event, value in backend.traverse():
-            quantities.add(meta_info)
+        for root_section in backend.resource.contents:
+            if not root_section.m_follows(section_run.m_def):
+                continue
+
+            quantities.add(root_section.m_def.name)
+            n_quantities += 1
 
-            if event == ParserEvent.add_value or event == ParserEvent.add_array_value:
+            for section, property_def, _ in root_section.m_traverse():
+                property_name = property_def.name
+                quantities.add(property_name)
                 n_quantities += 1
 
-                if meta_info == 'energy_total':
+                if property_name == 'energy_total':
                     n_total_energies += 1
 
-                if meta_info == 'configuration_raw_gid':
-                    geometries.add(value)
+                if property_name == 'configuration_raw_gid':
+                    geometries.add(section.m_get(property_def))
 
-            elif event == ParserEvent.open_section:
-                if meta_info == 'section_single_configuration_calculation':
+                if property_name == 'section_single_configuration_calculation':
                     n_calculations += 1
 
-                if meta_info == 'section_system':
+                if property_name == 'section_system':
                     n_geometries += 1
 
         self.quantities = list(quantities)
@@ -294,4 +286,6 @@ class DFTMetadata(MSection):
             self.labels.append(Label(label=aflow_id, type='prototype_id', source='aflow_prototype_library'))
 
         # optimade
-        self.optimade = backend.get_mi2_section(OptimadeEntry.m_def)
+        optimade = backend.get_mi2_section(OptimadeEntry.m_def)
+        if optimade is not None:
+            self.optimade = optimade.m_copy()
diff --git a/nomad/datamodel/ems.py b/nomad/datamodel/ems.py
index bb8b3ebd02..3a85b46b65 100644
--- a/nomad/datamodel/ems.py
+++ b/nomad/datamodel/ems.py
@@ -21,6 +21,7 @@ from nomad.metainfo import Quantity, MSection, Section, Datetime
 from nomad.metainfo.search_extension import Search
 
 from .common import get_optional_backend_value
+from .metainfo.general_experimental import section_experiment
 
 
 class EMSMetadata(MSection):
@@ -106,7 +107,12 @@ class EMSMetadata(MSection):
 
         quantities = set()
 
-        for meta_info, _, _ in backend.traverse(root_section='section_experiment'):
-            quantities.add(meta_info)
+        for root_section in backend.resource.contents:
+            if not root_section.m_follows(section_experiment.m_def):
+                continue
+
+            quantities.add(root_section.m_def.name)
+            for _, property_def, _ in root_section.m_traverse():
+                quantities.add(property_def.name)
 
         self.quantities = list(quantities)
diff --git a/nomad/datamodel/metainfo/common.py b/nomad/datamodel/metainfo/common.py
index c01bbe1758..a69593a5f6 100644
--- a/nomad/datamodel/metainfo/common.py
+++ b/nomad/datamodel/metainfo/common.py
@@ -4,10 +4,14 @@ from nomad.metainfo import (  # pylint: disable=unused-import
     MSection, MCategory, Category, Package, Quantity, Section, SubSection, SectionProxy,
     Reference
 )
+from nomad.metainfo.legacy import LegacyDefinition
 
 from nomad.datamodel.metainfo import public
 
-m_package = Package(name='common', description='None')
+m_package = Package(
+    name='common_nomadmetainfo_json',
+    description='None',
+    a_legacy=LegacyDefinition(name='common.nomadmetainfo.json'))
 
 
 class settings_atom_in_molecule(MCategory):
@@ -15,24 +19,36 @@ class settings_atom_in_molecule(MCategory):
     Parameters of an atom within a molecule.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_atom_in_molecule'))
+
 
 class settings_constraint(MCategory):
     '''
     Some parameters that describe a constraint
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_constraint'))
+
 
 class settings_interaction(MCategory):
     '''
     Some parameters that describe a bonded interaction.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_interaction'))
+
 
 class soap_parameter(MCategory):
     '''
     A soap parameter
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='soap_parameter'))
+
 
 class response_context(MSection):
     '''
@@ -40,18 +56,20 @@ class response_context(MSection):
     are tipically in the meta part
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='response_context'))
 
     shortened_meta_info = Quantity(
         type=str,
         shape=[],
         description='''
         A meta info whose corresponding data has been shortened
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='shortened_meta_info'))
 
     section_response_message = SubSection(
         sub_section=SectionProxy('section_response_message'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_response_message'))
 
 
 class section_atom_type(MSection):
@@ -59,7 +77,7 @@ class section_atom_type(MSection):
     Section describing a type of atom in the system.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_atom_type'))
 
     atom_type_charge = Quantity(
         type=np.dtype(np.float64),
@@ -67,7 +85,8 @@ class section_atom_type(MSection):
         unit='coulomb',
         description='''
         Charge of the atom type.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_type_charge'))
 
     atom_type_mass = Quantity(
         type=np.dtype(np.float64),
@@ -75,14 +94,16 @@ class section_atom_type(MSection):
         unit='kilogram',
         description='''
         Mass of the atom type.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_type_mass'))
 
     atom_type_name = Quantity(
         type=str,
         shape=[],
         description='''
         Name (label) of the atom type.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_type_name'))
 
 
 class section_constraint(MSection):
@@ -90,7 +111,7 @@ class section_constraint(MSection):
     Section describing a constraint between arbitrary atoms.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_constraint'))
 
     constraint_atoms = Quantity(
         type=np.dtype(np.int32),
@@ -98,7 +119,8 @@ class section_constraint(MSection):
         description='''
         List of the indexes involved in this constraint. The fist atom has index 1, the
         last number_of_topology_atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='constraint_atoms'))
 
     constraint_kind = Quantity(
         type=str,
@@ -107,7 +129,8 @@ class section_constraint(MSection):
         Short and unique name for this constraint type. Valid names are described in the
         [constraint\\_kind wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/constraint-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='constraint_kind'))
 
     constraint_parameters = Quantity(
         type=typing.Any,
@@ -115,21 +138,24 @@ class section_constraint(MSection):
         description='''
         Explicit constraint parameters for this kind of constraint (depending on the
         constraint type, some might be given implicitly through other means).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='constraint_parameters'))
 
     number_of_atoms_per_constraint = Quantity(
         type=int,
         shape=[],
         description='''
         Number of atoms involved in this constraint.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atoms_per_constraint'))
 
     number_of_constraints = Quantity(
         type=int,
         shape=[],
         description='''
         Number of constraints of this type.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_constraints'))
 
 
 class section_dft_plus_u_orbital(MSection):
@@ -137,14 +163,15 @@ class section_dft_plus_u_orbital(MSection):
     Section for DFT+U-settings of a single orbital
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_dft_plus_u_orbital'))
 
     dft_plus_u_orbital_atom = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         DFT+U-orbital setting: atom index (references index of atom_labels/atom_positions)
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dft_plus_u_orbital_atom'))
 
     dft_plus_u_orbital_J = Quantity(
         type=np.dtype(np.float64),
@@ -152,14 +179,16 @@ class section_dft_plus_u_orbital(MSection):
         description='''
         DFT+U-orbital setting: value J (exchange interaction)
         ''',
-        categories=[public.energy_value])
+        categories=[public.energy_value],
+        a_legacy=LegacyDefinition(name='dft_plus_u_orbital_J'))
 
     dft_plus_u_orbital_label = Quantity(
         type=str,
         shape=[],
         description='''
         DFT+U-orbital setting: orbital label (normally (n,l)), notation: '3d', '4f', ...
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dft_plus_u_orbital_label'))
 
     dft_plus_u_orbital_U_effective = Quantity(
         type=np.dtype(np.float64),
@@ -167,7 +196,8 @@ class section_dft_plus_u_orbital(MSection):
         description='''
         DFT+U-orbital setting: value U_{effective} (U-J), if implementation uses it
         ''',
-        categories=[public.energy_value])
+        categories=[public.energy_value],
+        a_legacy=LegacyDefinition(name='dft_plus_u_orbital_U_effective'))
 
     dft_plus_u_orbital_U = Quantity(
         type=np.dtype(np.float64),
@@ -175,7 +205,8 @@ class section_dft_plus_u_orbital(MSection):
         description='''
         DFT+U-orbital setting: value U (on-site Coulomb interaction)
         ''',
-        categories=[public.energy_value])
+        categories=[public.energy_value],
+        a_legacy=LegacyDefinition(name='dft_plus_u_orbital_U'))
 
 
 class section_excited_states(MSection):
@@ -183,7 +214,7 @@ class section_excited_states(MSection):
     Excited states properties.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_excited_states'))
 
     excitation_energies = Quantity(
         type=np.dtype(np.float64),
@@ -191,28 +222,32 @@ class section_excited_states(MSection):
         description='''
         Excitation energies.
         ''',
-        categories=[public.energy_value])
+        categories=[public.energy_value],
+        a_legacy=LegacyDefinition(name='excitation_energies'))
 
     number_of_excited_states = Quantity(
         type=int,
         shape=[],
         description='''
         Number of excited states.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_excited_states'))
 
     oscillator_strengths = Quantity(
         type=np.dtype(np.float64),
         shape=['number_of_excited_states'],
         description='''
         Excited states oscillator strengths.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='oscillator_strengths'))
 
     transition_dipole_moments = Quantity(
         type=np.dtype(np.float64),
         shape=['number_of_excited_states', 3],
         description='''
         Transition dipole moments.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='transition_dipole_moments'))
 
 
 class section_interaction(MSection):
@@ -220,7 +255,7 @@ class section_interaction(MSection):
     Section containing the description of a bonded interaction between arbitrary atoms.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_interaction'))
 
     interaction_atoms = Quantity(
         type=np.dtype(np.int32),
@@ -228,7 +263,8 @@ class section_interaction(MSection):
         description='''
         List of the indexes involved in this interaction. The fist atom has index 1, the
         last atom index number_of_topology_atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='interaction_atoms'))
 
     interaction_kind = Quantity(
         type=str,
@@ -237,7 +273,8 @@ class section_interaction(MSection):
         Short and unique name for this interaction type. Valid names are described in the
         [interaction\\_kind wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/interaction-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='interaction_kind'))
 
     interaction_parameters = Quantity(
         type=typing.Any,
@@ -245,21 +282,24 @@ class section_interaction(MSection):
         description='''
         Explicit interaction parameters for this kind of interaction (depending on the
         interaction_kind some might be given implicitly through other means).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='interaction_parameters'))
 
     number_of_atoms_per_interaction = Quantity(
         type=int,
         shape=[],
         description='''
         Number of atoms involved in this interaction.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atoms_per_interaction'))
 
     number_of_interactions = Quantity(
         type=int,
         shape=[],
         description='''
         Number of interactions of this type.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_interactions'))
 
 
 class section_method_basis_set(MSection):
@@ -268,7 +308,7 @@ class section_method_basis_set(MSection):
     of the atomic configuration.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_method_basis_set'))
 
     mapping_section_method_basis_set_atom_centered = Quantity(
         type=np.dtype(np.int64),
@@ -276,14 +316,16 @@ class section_method_basis_set(MSection):
         description='''
         Reference to an atom-centered basis set defined in section_basis_set_atom_centered
         and to the atom kind as defined in section_method_atom_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='mapping_section_method_basis_set_atom_centered'))
 
     mapping_section_method_basis_set_cell_associated = Quantity(
         type=public.section_basis_set_cell_dependent,
         shape=[],
         description='''
         Reference to a cell-associated basis set.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='mapping_section_method_basis_set_cell_associated'))
 
     method_basis_set_kind = Quantity(
         type=str,
@@ -293,7 +335,8 @@ class section_method_basis_set(MSection):
         wavefunction or an electron density. Allowed values are listed in the
         [basis\\_set\\_kind wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/basis-set-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_basis_set_kind'))
 
     number_of_basis_sets_atom_centered = Quantity(
         type=int,
@@ -303,7 +346,8 @@ class section_method_basis_set(MSection):
         wavefunction or an electron density. Allowed values are listed in the
         [basis\\_set\\_kind wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/basis-set-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_basis_sets_atom_centered'))
 
 
 class section_molecule_constraint(MSection):
@@ -311,7 +355,7 @@ class section_molecule_constraint(MSection):
     Section describing a constraint between atoms within a molecule.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_molecule_constraint'))
 
     molecule_constraint_atoms = Quantity(
         type=np.dtype(np.int32),
@@ -319,7 +363,8 @@ class section_molecule_constraint(MSection):
         description='''
         List of the indexes involved in this constraint. The fist atom has index 1, the
         last index is number_of_atoms_in_molecule.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='molecule_constraint_atoms'))
 
     molecule_constraint_kind = Quantity(
         type=str,
@@ -328,7 +373,8 @@ class section_molecule_constraint(MSection):
         Short and unique name for this constraint type. Valid names are described in the
         [constraint\\_kind wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/constraint-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='molecule_constraint_kind'))
 
     molecule_constraint_parameters = Quantity(
         type=typing.Any,
@@ -336,21 +382,24 @@ class section_molecule_constraint(MSection):
         description='''
         Explicit constraint parameters for this kind of constraint (depending on the
         constraint type some might be given implicitly through other means).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='molecule_constraint_parameters'))
 
     number_of_atoms_per_molecule_constraint = Quantity(
         type=int,
         shape=[],
         description='''
         Number of atoms, in this molecule, involved in this constraint.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atoms_per_molecule_constraint'))
 
     number_of_molecule_constraints = Quantity(
         type=int,
         shape=[],
         description='''
         Number of constraints of this type.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_molecule_constraints'))
 
 
 class section_molecule_interaction(MSection):
@@ -358,7 +407,7 @@ class section_molecule_interaction(MSection):
     Section describing a bonded interaction between atoms within a molecule.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_molecule_interaction'))
 
     molecule_interaction_atoms = Quantity(
         type=np.dtype(np.int32),
@@ -366,7 +415,8 @@ class section_molecule_interaction(MSection):
         description='''
         List of the indexes involved in this bonded interaction within a molecule. The
         first atom has index 1, the last index is number_of_atoms_in_.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='molecule_interaction_atoms'))
 
     molecule_interaction_kind = Quantity(
         type=str,
@@ -376,7 +426,8 @@ class section_molecule_interaction(MSection):
         atoms in a molecule. Valid names are described in the [interaction\\_kind wiki
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/interaction-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='molecule_interaction_kind'))
 
     molecule_interaction_parameters = Quantity(
         type=typing.Any,
@@ -385,21 +436,24 @@ class section_molecule_interaction(MSection):
         Explicit interaction parameters for this kind of interaction (depending on the
         interaction type some might be given implicitly through other means), used for
         bonded interactions for atoms in a molecule.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='molecule_interaction_parameters'))
 
     number_of_atoms_per_molecule_interaction = Quantity(
         type=int,
         shape=[],
         description='''
         Number of atoms, in this molecule, involved in this interaction.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atoms_per_molecule_interaction'))
 
     number_of_molecule_interactions = Quantity(
         type=int,
         shape=[],
         description='''
         Number of bonded interactions of this type.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_molecule_interactions'))
 
 
 class section_molecule_type(MSection):
@@ -407,7 +461,7 @@ class section_molecule_type(MSection):
     Section describing a type of molecule in the system.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_molecule_type'))
 
     atom_in_molecule_charge = Quantity(
         type=np.dtype(np.float64),
@@ -416,7 +470,8 @@ class section_molecule_type(MSection):
         description='''
         Charge of each atom in the molecule.
         ''',
-        categories=[settings_atom_in_molecule])
+        categories=[settings_atom_in_molecule],
+        a_legacy=LegacyDefinition(name='atom_in_molecule_charge'))
 
     atom_in_molecule_name = Quantity(
         type=str,
@@ -424,7 +479,8 @@ class section_molecule_type(MSection):
         description='''
         Name (label) of each atom in the molecule.
         ''',
-        categories=[settings_atom_in_molecule])
+        categories=[settings_atom_in_molecule],
+        a_legacy=LegacyDefinition(name='atom_in_molecule_name'))
 
     atom_in_molecule_to_atom_type_ref = Quantity(
         type=Reference(SectionProxy('section_atom_type')),
@@ -432,29 +488,34 @@ class section_molecule_type(MSection):
         description='''
         Reference to the atom type of each atom in the molecule.
         ''',
-        categories=[settings_atom_in_molecule])
+        categories=[settings_atom_in_molecule],
+        a_legacy=LegacyDefinition(name='atom_in_molecule_to_atom_type_ref'))
 
     molecule_type_name = Quantity(
         type=str,
         shape=[],
         description='''
         Name of the molecule.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='molecule_type_name'))
 
     number_of_atoms_in_molecule = Quantity(
         type=int,
         shape=[],
         description='''
         Number of atoms in this molecule.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atoms_in_molecule'))
 
     section_molecule_constraint = SubSection(
         sub_section=SectionProxy('section_molecule_constraint'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_molecule_constraint'))
 
     section_molecule_interaction = SubSection(
         sub_section=SectionProxy('section_molecule_interaction'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_molecule_interaction'))
 
 
 class section_response_message(MSection):
@@ -462,28 +523,31 @@ class section_response_message(MSection):
     Messages outputted by the program formatting the data in the current response
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_response_message'))
 
     response_message_count = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         How many times this message was repeated
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='response_message_count'))
 
     response_message_level = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         level of the message: 0 fatal, 1 error, 2 warning, 3 debug
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='response_message_level'))
 
     response_message = Quantity(
         type=str,
         shape=[],
         description='''
         Message outputted by the program formatting the data in the current format
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='response_message'))
 
 
 class section_soap_coefficients(MSection):
@@ -492,21 +556,23 @@ class section_soap_coefficients(MSection):
     soap_coefficients_atom_pair.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_soap_coefficients'))
 
     number_of_soap_coefficients = Quantity(
         type=int,
         shape=[],
         description='''
         number of soap coefficients
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_soap_coefficients'))
 
     soap_coefficients_atom_pair = Quantity(
         type=str,
         shape=[],
         description='''
         Pair of atoms described in the current section
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='soap_coefficients_atom_pair'))
 
     soap_coefficients = Quantity(
         type=np.dtype(np.float64),
@@ -514,7 +580,8 @@ class section_soap_coefficients(MSection):
         description='''
         Compressed coefficient of the soap descriptor for the atom pair
         soap_coefficients_atom_pair
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='soap_coefficients'))
 
 
 class section_soap(MSection):
@@ -522,7 +589,7 @@ class section_soap(MSection):
     Stores a soap descriptor for this configuration.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_soap'))
 
     soap_angular_basis_L = Quantity(
         type=np.dtype(np.int32),
@@ -530,7 +597,8 @@ class section_soap(MSection):
         description='''
         angular basis L
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_angular_basis_L'))
 
     soap_angular_basis_type = Quantity(
         type=str,
@@ -538,7 +606,8 @@ class section_soap(MSection):
         description='''
         angular basis type
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_angular_basis_type'))
 
     soap_kernel_adaptor = Quantity(
         type=str,
@@ -546,7 +615,8 @@ class section_soap(MSection):
         description='''
         kernel adaptor
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_kernel_adaptor'))
 
     soap_parameters_gid = Quantity(
         type=str,
@@ -554,7 +624,8 @@ class section_soap(MSection):
         description='''
         Unique checksum of all the soap parameters (all those with abstract type
         soap_parameter) with prefix psoap
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='soap_parameters_gid'))
 
     soap_radial_basis_integration_steps = Quantity(
         type=np.dtype(np.int32),
@@ -562,7 +633,8 @@ class section_soap(MSection):
         description='''
         radial basis integration steps
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_basis_integration_steps'))
 
     soap_radial_basis_mode = Quantity(
         type=str,
@@ -570,7 +642,8 @@ class section_soap(MSection):
         description='''
         radial basis mode
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_basis_mode'))
 
     soap_radial_basis_n = Quantity(
         type=np.dtype(np.int32),
@@ -578,7 +651,8 @@ class section_soap(MSection):
         description='''
         radial basis N
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_basis_n'))
 
     soap_radial_basis_sigma = Quantity(
         type=np.dtype(np.float64),
@@ -586,7 +660,8 @@ class section_soap(MSection):
         description='''
         radial basis sigma
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_basis_sigma'))
 
     soap_radial_basis_type = Quantity(
         type=str,
@@ -594,7 +669,8 @@ class section_soap(MSection):
         description='''
         radial basis type
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_basis_type'))
 
     soap_radial_cutoff_center_weight = Quantity(
         type=np.dtype(np.float64),
@@ -602,7 +678,8 @@ class section_soap(MSection):
         description='''
         radial cutoff center weight
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_cutoff_center_weight'))
 
     soap_radial_cutoff_rc_width = Quantity(
         type=np.dtype(np.int32),
@@ -610,7 +687,8 @@ class section_soap(MSection):
         description='''
         radial cutoff width
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_cutoff_rc_width'))
 
     soap_radial_cutoff_rc = Quantity(
         type=np.dtype(np.float64),
@@ -618,7 +696,8 @@ class section_soap(MSection):
         description='''
         radial cutoff
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_cutoff_rc'))
 
     soap_radial_cutoff_type = Quantity(
         type=str,
@@ -626,7 +705,8 @@ class section_soap(MSection):
         description='''
         radial cutoff type
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_radial_cutoff_type'))
 
     soap_spectrum_2l1_norm = Quantity(
         type=bool,
@@ -634,7 +714,8 @@ class section_soap(MSection):
         description='''
         2l1 norm spectrum
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_spectrum_2l1_norm'))
 
     soap_spectrum_global = Quantity(
         type=bool,
@@ -642,7 +723,8 @@ class section_soap(MSection):
         description='''
         global spectrum
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_spectrum_global'))
 
     soap_spectrum_gradients = Quantity(
         type=bool,
@@ -650,7 +732,8 @@ class section_soap(MSection):
         description='''
         gradients in specturm
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_spectrum_gradients'))
 
     soap_type_list = Quantity(
         type=str,
@@ -658,11 +741,13 @@ class section_soap(MSection):
         description='''
         Type list
         ''',
-        categories=[soap_parameter])
+        categories=[soap_parameter],
+        a_legacy=LegacyDefinition(name='soap_type_list'))
 
     section_soap_coefficients = SubSection(
         sub_section=SectionProxy('section_soap_coefficients'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_soap_coefficients'))
 
 
 class section_topology(MSection):
@@ -671,7 +756,7 @@ class section_topology(MSection):
     fileds), force field, and constraints of a system.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_topology'))
 
     atom_to_molecule = Quantity(
         type=np.dtype(np.int32),
@@ -680,28 +765,32 @@ class section_topology(MSection):
         Table mapping atom to molecules: the first column is the index of the molecule and
         the second column the index of the atom, signifying that the atom in the second
         column belongs to the molecule in the first column in the same row.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_to_molecule'))
 
     molecule_to_molecule_type_map = Quantity(
         type=Reference(SectionProxy('section_molecule_type')),
         shape=['number_of_topology_molecules'],
         description='''
         Mapping from molecules to molecule types.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='molecule_to_molecule_type_map'))
 
     number_of_topology_atoms = Quantity(
         type=int,
         shape=[],
         description='''
         Number of atoms in the system described by this topology.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_topology_atoms'))
 
     number_of_topology_molecules = Quantity(
         type=int,
         shape=[],
         description='''
         Number of molecules in the system, as described by this topology.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_topology_molecules'))
 
     topology_force_field_name = Quantity(
         type=str,
@@ -711,28 +800,33 @@ class section_topology(MSection):
         define it are discussed in the
         [topology\\_force\\_field\\_name](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/topology-force-field-name).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='topology_force_field_name'))
 
     section_atom_type = SubSection(
         sub_section=SectionProxy('section_atom_type'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_atom_type'))
 
     section_constraint = SubSection(
         sub_section=SectionProxy('section_constraint'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_constraint'))
 
     section_interaction = SubSection(
         sub_section=SectionProxy('section_interaction'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_interaction'))
 
     section_molecule_type = SubSection(
         sub_section=SectionProxy('section_molecule_type'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_molecule_type'))
 
 
 class section_method(public.section_method):
 
-    m_def = Section(validate=False, extends_base_section=True)
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_method'))
 
     dft_plus_u_functional = Quantity(
         type=str,
@@ -742,7 +836,8 @@ class section_method(public.section_method):
         names are described in the [dft\\_plus\\_u\\_functional wiki
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/dft-
         plus-u-functional).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dft_plus_u_functional'))
 
     dft_plus_u_projection_type = Quantity(
         type=str,
@@ -752,7 +847,8 @@ class section_method(public.section_method):
         numbers. Valid names are described in the [dft\\_plus\\_u\\_projection\\_type wiki
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/dft-
         plus-u-projection-type).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dft_plus_u_projection_type'))
 
     gw_bare_coulomb_cutofftype = Quantity(
         type=str,
@@ -760,7 +856,8 @@ class section_method(public.section_method):
         description='''
         Cutoff type for the calculation of the bare Coulomb potential: none, 0d, 1d, 2d.
         See Rozzi et al., PRB 73, 205119 (2006)
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_bare_coulomb_cutofftype'))
 
     gw_bare_coulomb_gmax = Quantity(
         type=np.dtype(np.float64),
@@ -768,7 +865,8 @@ class section_method(public.section_method):
         unit='1 / meter',
         description='''
         Maximum G for the pw basis for the Coulomb potential.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_bare_coulomb_gmax'))
 
     gw_basis_set = Quantity(
         type=str,
@@ -776,7 +874,8 @@ class section_method(public.section_method):
         description='''
         Auxillary basis set used for non-local operators: mixed - mixed basis set, Kotani
         and Schilfgaarde, Solid State Comm. 121, 461 (2002).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_basis_set'))
 
     gw_core_treatment = Quantity(
         type=str,
@@ -786,7 +885,8 @@ class section_method(public.section_method):
         electron calculation; val - Valence electron only calculation; vab - Core
         electrons are excluded from the mixed product basis; xal - All electron treatment
         of the exchange self-energy only
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_core_treatment'))
 
     gw_frequency_grid_type = Quantity(
         type=str,
@@ -797,14 +897,16 @@ class section_method(public.section_method):
         from 0 to infinity; 'gauleg' - Gauss-Legendre quadrature from 0 to freqmax;
         'gaule2' (default) - double Gauss-Legendre quadrature from 0 to freqmax and from
         freqmax to infinity.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_frequency_grid_type'))
 
     gw_max_frequency = Quantity(
         type=np.dtype(np.float64),
         shape=[],
         description='''
         Maximum frequency for the calculation of the self energy.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_max_frequency'))
 
     gw_mixed_basis_gmax = Quantity(
         type=np.dtype(np.float64),
@@ -813,14 +915,16 @@ class section_method(public.section_method):
         description='''
         Cut-off parameter for the truncation of the expansion of the plane waves in the
         interstitial region.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_mixed_basis_gmax'))
 
     gw_mixed_basis_lmax = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         Maximum l value used for the radial functions within the muffin-tin.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_mixed_basis_lmax'))
 
     gw_mixed_basis_tolerance = Quantity(
         type=np.dtype(np.float64),
@@ -828,21 +932,24 @@ class section_method(public.section_method):
         description='''
         Eigenvalue threshold below which the egenvectors are discarded in the construction
         of the radial basis set.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_mixed_basis_tolerance'))
 
     gw_ngridq = Quantity(
         type=np.dtype(np.int32),
         shape=[3],
         description='''
         k/q-point grid size used in the GW calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_ngridq'))
 
     gw_frequency_number = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         Number referring to the frequency used in the calculation of the self energy.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_frequency_number'))
 
     gw_frequency_values = Quantity(
         type=np.dtype(np.float64),
@@ -850,35 +957,40 @@ class section_method(public.section_method):
         unit='joule',
         description='''
         Values of the frequency used in the calculation of the self energy.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_frequency_values'))
 
     gw_frequency_weights = Quantity(
         type=np.dtype(np.float64),
         shape=[],
         description='''
         Weights of the frequency used in the calculation of the self energy.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_frequency_weights'))
 
     gw_number_of_frequencies = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         Number of frequency points used in the calculation of the self energy.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_number_of_frequencies'))
 
     gw_polarizability_number_of_empty_states = Quantity(
         type=int,
         shape=[],
         description='''
         Number of empty states used to compute the polarizability P
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_polarizability_number_of_empty_states'))
 
     gw_qp_equation_treatment = Quantity(
         type=str,
         shape=[],
         description='''
         Methods to solve the quasi-particle equation: 'linearization', 'self-consistent'
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_qp_equation_treatment'))
 
     gw_screened_coulomb_volume_average = Quantity(
         type=str,
@@ -888,7 +1000,8 @@ class section_method(public.section_method):
         - Simple averaging along a specified direction using only diagonal components of
         the dielectric tensor; anisotropic - Anisotropic screening by C. Freysoldt et al.,
         CPC 176, 1-13 (2007)
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_screened_coulomb_volume_average'))
 
     gw_screened_Coulomb = Quantity(
         type=str,
@@ -900,7 +1013,8 @@ class section_method(public.section_method):
         Rev. B 34, 5390 (1986); 'ppm_lh' - von der Linden and P. Horsh, Phys. Rev. B 37,
         8351 (1988); 'ppm_fe' - Farid and Engel, Phys. Rev. B 47,15931 (1993); 'cdm' -
         Contour deformation method, Phys. Rev. B 67, 155208 (2003).)
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_screened_Coulomb'))
 
     gw_self_energy_c_analytical_continuation = Quantity(
         type=str,
@@ -910,21 +1024,24 @@ class section_method(public.section_method):
         approximant (by H. J. Vidberg and J. W. Serence, J. Low Temp. Phys. 29, 179
         (1977)); 'mpf' -  Multi-Pole Fitting (by H. N Rojas, R. W. Godby and R. J. Needs,
         Phys. Rev. Lett. 74, 1827 (1995)); 'cd' - contour deformation; 'ra' - real axis
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_self_energy_c_analytical_continuation'))
 
     gw_self_energy_c_number_of_empty_states = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         Number of empty states to be used to calculate the correlation self energy.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_self_energy_c_number_of_empty_states'))
 
     gw_self_energy_c_number_of_poles = Quantity(
         type=int,
         shape=[],
         description='''
         Number of poles used in the analytical continuation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_self_energy_c_number_of_poles'))
 
     gw_self_energy_singularity_treatment = Quantity(
         type=str,
@@ -934,7 +1051,8 @@ class section_method(public.section_method):
         Values: 'mpb' - Auxiliary function method by S. Massidda, M. Posternak, and A.
         Baldereschi, PRB 48, 5058 (1993); 'crg' - Auxiliary function method by P. Carrier,
         S. Rohra, and A. Goerling, PRB 75, 205126 (2007).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_self_energy_singularity_treatment'))
 
     gw_starting_point = Quantity(
         type=str,
@@ -943,14 +1061,16 @@ class section_method(public.section_method):
         Exchange-correlation functional of the ground-state calculation. See XC_functional
         list at https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/XC-
         functional
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_starting_point'))
 
     gw_type_test = Quantity(
         type=str,
         shape=[],
         description='''
         GW methodology: exciting test variable
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_type_test'))
 
     gw_type = Quantity(
         type=str,
@@ -961,27 +1081,31 @@ class section_method(public.section_method):
         226402 (2006)  scGW0: (self-consistent G with fixed W0) – Phys.Rev.B 54, 8411
         (1996); scG0W: (self-consistent W with fixed G0); scGW: (self-consistent GW) –
         Phys. Rev. B 88, 075105 (2013)
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_type'))
 
     method_to_topology_ref = Quantity(
         type=Reference(SectionProxy('section_topology')),
         shape=[],
         description='''
         Reference to the topology and force fields to be used.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_to_topology_ref'))
 
     section_dft_plus_u_orbital = SubSection(
         sub_section=SectionProxy('section_dft_plus_u_orbital'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_dft_plus_u_orbital'))
 
     section_method_basis_set = SubSection(
         sub_section=SectionProxy('section_method_basis_set'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_method_basis_set'))
 
 
 class section_single_configuration_calculation(public.section_single_configuration_calculation):
 
-    m_def = Section(validate=False, extends_base_section=True)
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_single_configuration_calculation'))
 
     energy_C_mGGA = Quantity(
         type=np.dtype(np.float64),
@@ -992,7 +1116,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         self-consistent density of the target XC functional (full unscaled value, i.e.,
         not scaled due to exact-exchange mixing).
         ''',
-        categories=[public.energy_value, public.energy_type_C, public.energy_component])
+        categories=[public.energy_component, public.energy_value, public.energy_type_C],
+        a_legacy=LegacyDefinition(name='energy_C_mGGA'))
 
     energy_reference_fermi = Quantity(
         type=np.dtype(np.float64),
@@ -1001,7 +1126,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         description='''
         Fermi energy (separates occupied from unoccupied single-particle states in metals)
         ''',
-        categories=[public.energy_type_reference, public.energy_value])
+        categories=[public.energy_type_reference, public.energy_value],
+        a_legacy=LegacyDefinition(name='energy_reference_fermi'))
 
     energy_reference_highest_occupied = Quantity(
         type=np.dtype(np.float64),
@@ -1011,7 +1137,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         Highest occupied single-particle state energy (in insulators or HOMO energy in
         finite systems)
         ''',
-        categories=[public.energy_type_reference, public.energy_value])
+        categories=[public.energy_type_reference, public.energy_value],
+        a_legacy=LegacyDefinition(name='energy_reference_highest_occupied'))
 
     energy_reference_lowest_unoccupied = Quantity(
         type=np.dtype(np.float64),
@@ -1021,7 +1148,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         Lowest unoccupied single-particle state energy (in insulators or LUMO energy in
         finite systems)
         ''',
-        categories=[public.energy_type_reference, public.energy_value])
+        categories=[public.energy_type_reference, public.energy_value],
+        a_legacy=LegacyDefinition(name='energy_reference_lowest_unoccupied'))
 
     energy_X_mGGA_scaled = Quantity(
         type=np.dtype(np.float64),
@@ -1032,7 +1160,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         consistent density of the target functional, scaled accordingly to the mixing
         parameter.
         ''',
-        categories=[public.energy_value, public.energy_component])
+        categories=[public.energy_component, public.energy_value],
+        a_legacy=LegacyDefinition(name='energy_X_mGGA_scaled'))
 
     energy_X_mGGA = Quantity(
         type=np.dtype(np.float64),
@@ -1043,7 +1172,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         consistent density of the target functional (full unscaled value, i.e., not scaled
         due to exact-exchange mixing).
         ''',
-        categories=[public.energy_type_X, public.energy_value, public.energy_component])
+        categories=[public.energy_type_X, public.energy_component, public.energy_value],
+        a_legacy=LegacyDefinition(name='energy_X_mGGA'))
 
     gw_fermi_energy = Quantity(
         type=np.dtype(np.float64),
@@ -1051,7 +1181,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         unit='joule',
         description='''
         GW Fermi energy
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_fermi_energy'))
 
     gw_fundamental_gap = Quantity(
         type=np.dtype(np.float64),
@@ -1059,7 +1190,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         unit='joule',
         description='''
         GW fundamental band gap
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_fundamental_gap'))
 
     gw_optical_gap = Quantity(
         type=np.dtype(np.float64),
@@ -1067,7 +1199,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         unit='joule',
         description='''
         GW optical band gap
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_optical_gap'))
 
     gw_self_energy_c = Quantity(
         type=np.dtype(np.float64),
@@ -1075,7 +1208,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         unit='joule',
         description='''
         Diagonal matrix elements of the correlation self-energy
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_self_energy_c'))
 
     gw_self_energy_x = Quantity(
         type=np.dtype(np.float64),
@@ -1083,7 +1217,8 @@ class section_single_configuration_calculation(public.section_single_configurati
         unit='joule',
         description='''
         Diagonal matrix elements of the exchange self-energy
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_self_energy_x'))
 
     gw_xc_potential = Quantity(
         type=np.dtype(np.float64),
@@ -1091,16 +1226,18 @@ class section_single_configuration_calculation(public.section_single_configurati
         unit='joule',
         description='''
         Diagonal matrix elements of the exchange-correlation potential
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_xc_potential'))
 
     section_excited_states = SubSection(
         sub_section=SectionProxy('section_excited_states'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_excited_states'))
 
 
 class section_scf_iteration(public.section_scf_iteration):
 
-    m_def = Section(validate=False, extends_base_section=True)
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_scf_iteration'))
 
     energy_reference_fermi_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -1110,7 +1247,8 @@ class section_scf_iteration(public.section_scf_iteration):
         Fermi energy (separates occupied from unoccupied single-particle states in metals)
         during the self-consistent field (SCF) iterations.
         ''',
-        categories=[public.energy_type_reference, public.energy_value])
+        categories=[public.energy_type_reference, public.energy_value],
+        a_legacy=LegacyDefinition(name='energy_reference_fermi_iteration'))
 
     energy_reference_highest_occupied_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -1120,7 +1258,8 @@ class section_scf_iteration(public.section_scf_iteration):
         Highest occupied single-particle state energy (in insulators or HOMO energy in
         finite systems) during the self-consistent field (SCF) iterations.
         ''',
-        categories=[public.energy_type_reference, public.energy_value])
+        categories=[public.energy_type_reference, public.energy_value],
+        a_legacy=LegacyDefinition(name='energy_reference_highest_occupied_iteration'))
 
     energy_reference_lowest_unoccupied_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -1130,24 +1269,26 @@ class section_scf_iteration(public.section_scf_iteration):
         Lowest unoccupied single-particle state energy (in insulators or LUMO energy in
         finite systems) during the self-consistent field (SCF) iterations.
         ''',
-        categories=[public.energy_type_reference, public.energy_value])
+        categories=[public.energy_type_reference, public.energy_value],
+        a_legacy=LegacyDefinition(name='energy_reference_lowest_unoccupied_iteration'))
 
 
 class section_eigenvalues(public.section_eigenvalues):
 
-    m_def = Section(validate=False, extends_base_section=True)
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_eigenvalues'))
 
     gw_qp_linearization_prefactor = Quantity(
         type=np.dtype(np.float64),
         shape=['number_of_spin_channels', 'number_of_eigenvalues_kpoints', 'number_of_eigenvalues'],
         description='''
         Linearization prefactor
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gw_qp_linearization_prefactor'))
 
 
 class section_system(public.section_system):
 
-    m_def = Section(validate=False, extends_base_section=True)
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_system'))
 
     number_of_electrons = Quantity(
         type=np.dtype(np.float64),
@@ -1155,7 +1296,8 @@ class section_system(public.section_system):
         description='''
         Number of electrons in system
         ''',
-        categories=[public.configuration_core])
+        categories=[public.configuration_core],
+        a_legacy=LegacyDefinition(name='number_of_electrons'))
 
     topology_ref = Quantity(
         type=Reference(SectionProxy('section_topology')),
@@ -1163,7 +1305,8 @@ class section_system(public.section_system):
         description='''
         Reference to the topology used for this system; if not given, the trivial topology
         should be assumed.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='topology_ref'))
 
     is_representative = Quantity(
         type=bool,
@@ -1171,20 +1314,23 @@ class section_system(public.section_system):
         description='''
         Most systems in a run are only minor variations of each other. Systems marked
         representative where chosen to be representative for all systems in the run.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='is_representative'))
 
     section_soap = SubSection(
         sub_section=SectionProxy('section_soap'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_soap'))
 
 
 class section_run(public.section_run):
 
-    m_def = Section(validate=False, extends_base_section=True)
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_run'))
 
     section_topology = SubSection(
         sub_section=SectionProxy('section_topology'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_topology'))
 
 
 m_package.__init_metainfo__()
diff --git a/nomad/datamodel/metainfo/general.py b/nomad/datamodel/metainfo/general.py
index bbb8dda361..190322f5a5 100644
--- a/nomad/datamodel/metainfo/general.py
+++ b/nomad/datamodel/metainfo/general.py
@@ -4,9 +4,13 @@ from nomad.metainfo import (  # pylint: disable=unused-import
     MSection, MCategory, Category, Package, Quantity, Section, SubSection, SectionProxy,
     Reference
 )
+from nomad.metainfo.legacy import LegacyDefinition
 
 
-m_package = Package(name='general', description='None')
+m_package = Package(
+    name='general_nomadmetainfo_json',
+    description='None',
+    a_legacy=LegacyDefinition(name='general.nomadmetainfo.json'))
 
 
 class section_entry_info(MSection):
@@ -15,7 +19,7 @@ class section_entry_info(MSection):
     used parser
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_entry_info'))
 
     entry_upload_time = Quantity(
         type=np.dtype(np.int64),
@@ -23,56 +27,64 @@ class section_entry_info(MSection):
         description='''
         Upload datetime, given as total number of seconds is the elapsed since the unix
         epoch (1 January 1970)
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='entry_upload_time'))
 
     entry_uploader_name = Quantity(
         type=str,
         shape=[],
         description='''
         Name of the uploader, given as lastname, firstname.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='entry_uploader_name'))
 
     entry_uploader_id = Quantity(
         type=str,
         shape=[],
         description='''
         The id of the uploader.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='entry_uploader_id'))
 
     upload_id = Quantity(
         type=str,
         shape=[],
         description='''
         Nomad upload id
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='upload_id'))
 
     calc_id = Quantity(
         type=str,
         shape=[],
         description='''
         Nomad calc id.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calc_id'))
 
     calc_hash = Quantity(
         type=str,
         shape=[],
         description='''
         Calculation hash based on raw file contents.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calc_hash'))
 
     mainfile = Quantity(
         type=str,
         shape=[],
         description='''
         Path to the main file within the upload.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='mainfile'))
 
     parser_name = Quantity(
         type=str,
         shape=[],
         description='''
         Name of the parser used to extract this information.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='parser_name'))
 
     filepaths = Quantity(
         type=str,
@@ -80,18 +92,21 @@ class section_entry_info(MSection):
         description='''
         Filepaths of files that belong to this entry, i.e. files in the same directory.
         Filepaths are relative to the upload.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='filepaths'))
 
     number_of_files = Quantity(
         type=int,
         shape=[],
         description='''
         Number of files that belong to this entry.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_files'))
 
     section_archive_processing_info = SubSection(
         sub_section=SectionProxy('section_archive_processing_info'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_archive_processing_info'))
 
 
 class section_archive_processing_info(MSection):
@@ -99,14 +114,15 @@ class section_archive_processing_info(MSection):
     Information about the used archive processing steps and their execution.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_archive_processing_info'))
 
     archive_processor_name = Quantity(
         type=str,
         shape=[],
         description='''
         Name of the applied archive processing program.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='archive_processor_name'))
 
     archive_processor_error = Quantity(
         type=str,
@@ -114,28 +130,32 @@ class section_archive_processing_info(MSection):
         description='''
         The main error during execution of the archive processing program that failed the
         program.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='archive_processor_error'))
 
     number_of_archive_processor_warnings = Quantity(
         type=int,
         shape=[],
         description='''
         Number of warnings during execution of the archive processing program.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_archive_processor_warnings'))
 
     archive_processor_warnings = Quantity(
         type=str,
         shape=['number_of_archive_processor_warnings'],
         description='''
         Warnings during execution of the archive processing program.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='archive_processor_warnings'))
 
     archive_processor_status = Quantity(
         type=str,
         shape=[],
         description='''
         Status returned by archive processing program.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='archive_processor_status'))
 
 
 m_package.__init_metainfo__()
diff --git a/nomad/datamodel/metainfo/general_experimental.py b/nomad/datamodel/metainfo/general_experimental.py
new file mode 100644
index 0000000000..f57457f5d9
--- /dev/null
+++ b/nomad/datamodel/metainfo/general_experimental.py
@@ -0,0 +1,112 @@
+import numpy as np            # pylint: disable=unused-import
+import typing                 # pylint: disable=unused-import
+from nomad.metainfo import (  # pylint: disable=unused-import
+    MSection, MCategory, Category, Package, Quantity, Section, SubSection, SectionProxy,
+    Reference
+)
+from nomad.metainfo.legacy import LegacyDefinition
+
+
+m_package = Package(
+    name='general_experimental_nomadmetainfo_json',
+    description='None',
+    a_legacy=LegacyDefinition(name='general.experimental.nomadmetainfo.json'))
+
+
+class section_experiment(MSection):
+    '''
+    The root section for all (meta)data that belongs to a single experiment.
+    '''
+
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_experiment'))
+
+    experiment_summary = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        A descriptive summary of the content of the experiment.
+        ''',
+        a_legacy=LegacyDefinition(name='experiment_summary'))
+
+    experiment_location = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        Name of the city and country the experiment took place, format 'Country, City'
+        ''',
+        a_legacy=LegacyDefinition(name='experiment_location'))
+
+    experiment_facility_institution = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        Name of the institution hosting the experimental facility (e.g. in full or an
+        acronym).
+        ''',
+        a_legacy=LegacyDefinition(name='experiment_facility_institution'))
+
+    experiment_facility_name = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        Name of the experimental facility (e.g. in full or an acronym).
+        ''',
+        a_legacy=LegacyDefinition(name='experiment_facility_name'))
+
+    experiment_time = Quantity(
+        type=np.dtype(np.int64),
+        shape=[],
+        unit='second',
+        description='''
+        The datetime of the beginning of the experiment in seconds since epoch.
+        ''',
+        a_legacy=LegacyDefinition(name='experiment_time'))
+
+    experiment_end_time = Quantity(
+        type=np.dtype(np.int64),
+        shape=[],
+        unit='second',
+        description='''
+        The datetime of the experiment end in seconds since epoch.
+        ''',
+        a_legacy=LegacyDefinition(name='experiment_end_time'))
+
+    section_data = SubSection(
+        sub_section=SectionProxy('section_data'),
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_data'))
+
+
+class section_data(MSection):
+    '''
+    This section contains information about the stored data.
+    '''
+
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_data'))
+
+    data_repository_name = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        The name of the repository, where the data is stored.
+        ''',
+        a_legacy=LegacyDefinition(name='data_repository_name'))
+
+    data_repository_url = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        An URL to the repository, where the data is stored.
+        ''',
+        a_legacy=LegacyDefinition(name='data_repository_url'))
+
+    data_preview_url = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        An URL to an image file that contains a preview.
+        ''',
+        a_legacy=LegacyDefinition(name='data_preview_url'))
+
+
+m_package.__init_metainfo__()
diff --git a/nomad/datamodel/metainfo/general_experimental_data.py b/nomad/datamodel/metainfo/general_experimental_data.py
new file mode 100644
index 0000000000..2d9425aa29
--- /dev/null
+++ b/nomad/datamodel/metainfo/general_experimental_data.py
@@ -0,0 +1,30 @@
+import numpy as np            # pylint: disable=unused-import
+import typing                 # pylint: disable=unused-import
+from nomad.metainfo import (  # pylint: disable=unused-import
+    MSection, MCategory, Category, Package, Quantity, Section, SubSection, SectionProxy,
+    Reference
+)
+from nomad.metainfo.legacy import LegacyDefinition
+
+from nomad.datamodel.metainfo import general_experimental
+
+m_package = Package(
+    name='general_experimental_data_nomadmetainfo_json',
+    description='None',
+    a_legacy=LegacyDefinition(name='general.experimental.data.nomadmetainfo.json'))
+
+
+class section_data(general_experimental.section_data):
+
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_data'))
+
+    entry_repository_url = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        An URL to the entry on the repository, where the data is stored.
+        ''',
+        a_legacy=LegacyDefinition(name='entry_repository_url'))
+
+
+m_package.__init_metainfo__()
diff --git a/nomad/datamodel/metainfo/general_experimental_method.py b/nomad/datamodel/metainfo/general_experimental_method.py
new file mode 100644
index 0000000000..1a8f0bcce8
--- /dev/null
+++ b/nomad/datamodel/metainfo/general_experimental_method.py
@@ -0,0 +1,67 @@
+import numpy as np            # pylint: disable=unused-import
+import typing                 # pylint: disable=unused-import
+from nomad.metainfo import (  # pylint: disable=unused-import
+    MSection, MCategory, Category, Package, Quantity, Section, SubSection, SectionProxy,
+    Reference
+)
+from nomad.metainfo.legacy import LegacyDefinition
+
+from nomad.datamodel.metainfo import general_experimental
+
+m_package = Package(
+    name='general_experimental_method_nomadmetainfo_json',
+    description='None',
+    a_legacy=LegacyDefinition(name='general.experimental.method.nomadmetainfo.json'))
+
+
+class section_method(MSection):
+    '''
+    This section contains information about the applied experimental method.
+    '''
+
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_method'))
+
+    experiment_method_name = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        Full name of the experimental method in use
+        ''',
+        a_legacy=LegacyDefinition(name='experiment_method_name'))
+
+    experiment_method_abbreviation = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        Abbreviated name (i.e. acronym) of the experimental method
+        ''',
+        a_legacy=LegacyDefinition(name='experiment_method_abbreviation'))
+
+    equipment_description = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        Name or model of the equipment (e.g. in full or an acronym).
+        ''',
+        a_legacy=LegacyDefinition(name='equipment_description'))
+
+    probing_method = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        The probing method used
+        ''',
+        a_legacy=LegacyDefinition(name='probing_method'))
+
+
+class section_experiment(general_experimental.section_experiment):
+
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_experiment'))
+
+    section_method = SubSection(
+        sub_section=SectionProxy('section_method'),
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_method'))
+
+
+m_package.__init_metainfo__()
diff --git a/nomad/datamodel/metainfo/general_experimental_sample.py b/nomad/datamodel/metainfo/general_experimental_sample.py
new file mode 100644
index 0000000000..d5595306f1
--- /dev/null
+++ b/nomad/datamodel/metainfo/general_experimental_sample.py
@@ -0,0 +1,127 @@
+import numpy as np            # pylint: disable=unused-import
+import typing                 # pylint: disable=unused-import
+from nomad.metainfo import (  # pylint: disable=unused-import
+    MSection, MCategory, Category, Package, Quantity, Section, SubSection, SectionProxy,
+    Reference
+)
+from nomad.metainfo.legacy import LegacyDefinition
+
+from nomad.datamodel.metainfo import general_experimental
+
+m_package = Package(
+    name='general_experimental_sample_nomadmetainfo_json',
+    description='None',
+    a_legacy=LegacyDefinition(name='general.experimental.sample.nomadmetainfo.json'))
+
+
+class section_sample(MSection):
+    '''
+    The section for all sample related (meta)data that was used in the experiment.
+    '''
+
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_sample'))
+
+    sample_description = Quantity(
+        type=str,
+        shape=[],
+        unit='dimensionless',
+        description='''
+        Description of the sample used in the experiment.
+        ''',
+        a_legacy=LegacyDefinition(name='sample_description'))
+
+    sample_id = Quantity(
+        type=str,
+        shape=[],
+        unit='dimensionless',
+        description='''
+        Identification number or signatures of the sample used.
+        ''',
+        a_legacy=LegacyDefinition(name='sample_id'))
+
+    sample_state = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        The physical state of the sample.
+        ''',
+        a_legacy=LegacyDefinition(name='sample_state'))
+
+    sample_chemical_formula = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        The chemical formula that describes the sample
+        ''',
+        a_legacy=LegacyDefinition(name='sample_chemical_formula'))
+
+    sample_chemical_name = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        The chemical name that describes the sample
+        ''',
+        a_legacy=LegacyDefinition(name='sample_chemical_name'))
+
+    sample_atom_labels = Quantity(
+        type=str,
+        shape=['n'],
+        description='''
+        The chemical name that describes the sample
+        ''',
+        a_legacy=LegacyDefinition(name='sample_atom_labels'))
+
+    number_of_elements = Quantity(
+        type=int,
+        shape=[],
+        description='''
+        Number of distinct chemical elements in the sample.
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_elements'))
+
+    sample_space_group = Quantity(
+        type=np.dtype(np.int32),
+        shape=[],
+        unit='dimensionless',
+        description='''
+        Space group of the sample compound (if crystalline).
+        ''',
+        a_legacy=LegacyDefinition(name='sample_space_group'))
+
+    sample_temperature = Quantity(
+        type=np.dtype(np.float64),
+        shape=[],
+        unit='kelvin',
+        description='''
+        The temperature of the sample during the experiment in K.
+        ''',
+        a_legacy=LegacyDefinition(name='sample_temperature'))
+
+    sample_microstructure = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        The sample microstructure
+        ''',
+        a_legacy=LegacyDefinition(name='sample_microstructure'))
+
+    sample_constituents = Quantity(
+        type=str,
+        shape=[],
+        description='''
+        The constituents
+        ''',
+        a_legacy=LegacyDefinition(name='sample_constituents'))
+
+
+class section_experiment(general_experimental.section_experiment):
+
+    m_def = Section(validate=False, extends_base_section=True, a_legacy=LegacyDefinition(name='section_experiment'))
+
+    section_sample = SubSection(
+        sub_section=SectionProxy('section_sample'),
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_sample'))
+
+
+m_package.__init_metainfo__()
diff --git a/nomad/datamodel/metainfo/public.py b/nomad/datamodel/metainfo/public.py
index f58404cf1c..cc22bfc99e 100644
--- a/nomad/datamodel/metainfo/public.py
+++ b/nomad/datamodel/metainfo/public.py
@@ -4,9 +4,13 @@ from nomad.metainfo import (  # pylint: disable=unused-import
     MSection, MCategory, Category, Package, Quantity, Section, SubSection, SectionProxy,
     Reference
 )
+from nomad.metainfo.legacy import LegacyDefinition
 
 
-m_package = Package(name='public', description='None')
+m_package = Package(
+    name='public_nomadmetainfo_json',
+    description='None',
+    a_legacy=LegacyDefinition(name='public.nomadmetainfo.json'))
 
 
 class accessory_info(MCategory):
@@ -15,6 +19,9 @@ class accessory_info(MCategory):
     timing).
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='accessory_info'))
+
 
 class atom_forces_type(MCategory):
     '''
@@ -22,6 +29,9 @@ class atom_forces_type(MCategory):
     of energy with respect to the atom position).
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='atom_forces_type'))
+
 
 class basis_set_description(MCategory):
     '''
@@ -29,12 +39,18 @@ class basis_set_description(MCategory):
     set, plane-waves or both).
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='basis_set_description'))
+
 
 class configuration_core(MCategory):
     '''
     Properties defining the current configuration.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='configuration_core'))
+
 
 class conserved_quantity(MCategory):
     '''
@@ -42,142 +58,218 @@ class conserved_quantity(MCategory):
     kinetic+potential energy during NVE).
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='conserved_quantity'))
 
-class energy_component_per_atom(MCategory):
+
+class energy_value(MCategory):
     '''
-    A value of an energy component per atom, concurring in defining the total energy per
-    atom.
+    This metadata stores an energy value.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='energy_value'))
 
-class energy_component(MCategory):
+
+class error_estimate_contribution(MCategory):
     '''
-    A value of an energy component, expected to be an extensive property.
+    An estimate of a partial quantity contributing to the error for a given quantity.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='error_estimate_contribution'))
 
-class energy_total_potential_per_atom(MCategory):
+
+class message_debug(MCategory):
     '''
-    A value of the total potential energy per atom. Note that a direct comparison may not
-    be possible because of a difference in the methods for computing total energies and
-    numerical implementations of various codes might leads to different energy zeros (see
-    section_energy_code_independent for a code-independent definition of the energy).
+    A debugging message of the computational program.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='message_debug'))
 
-class energy_total_potential(MCategory):
+
+class parsing_message_debug(MCategory):
     '''
-    A value of the total potential energy. Note that a direct comparison may not be
-    possible because of a difference in the methods for computing total energies and
-    numerical implementations of various codes might leads to different energy zeros (see
-    section_energy_code_independent for a code-independent definition of the energy).
+    This field is used for debugging messages of the parsing program.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='parsing_message_debug'))
 
-class energy_type_C(MCategory):
+
+class scf_info(MCategory):
     '''
-    This metadata stores the correlation (C) energy.
+    Contains information on the self-consistent field (SCF) procedure, i.e. the number of
+    SCF iterations (number_of_scf_iterations) or a section_scf_iteration section with
+    detailed information on the SCF procedure of specified quantities.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='scf_info'))
 
-class energy_type_reference(MCategory):
+
+class settings_numerical_parameter(MCategory):
     '''
-    This metadata stores an energy used as reference point.
+    A parameter that can influence the convergence, but not the physics (unlike
+    settings_physical_parameter)
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_numerical_parameter'))
 
-class energy_type_van_der_Waals(MCategory):
+
+class settings_physical_parameter(MCategory):
     '''
-    This metadata stores the converged van der Waals energy.
+    A parameter that defines the physical model used. Use settings_numerical_parameter for
+    parameters that that influence only the convergence/accuracy.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_physical_parameter'))
 
-class energy_type_XC(MCategory):
+
+class settings_potential_energy_surface(MCategory):
     '''
-    This metadata stores the exchange-correlation (XC) energy.
+    Contains parameters that control the potential energy surface.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_potential_energy_surface'))
 
-class energy_type_X(MCategory):
+
+class settings_run(MCategory):
     '''
-    This metadata stores the exchange (X) energy.
+    Contains parameters that control the whole run (but not the *single configuration
+    calculation*, see section_single_configuration_calculation).
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_run'))
 
-class energy_value(MCategory):
+
+class settings_sampling(MCategory):
     '''
-    This metadata stores an energy value.
+    Contains parameters controlling the sampling.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_sampling'))
 
-class error_estimate_contribution(MCategory):
+
+class settings_scf(MCategory):
     '''
-    An estimate of a partial quantity contributing to the error for a given quantity.
+    Contains parameters connected with the convergence of the self-consistent field (SCF)
+    iterations.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_scf'))
 
-class error_estimate(MCategory):
+
+class settings_smearing(MCategory):
     '''
-    An estimate of the error on the converged (final) value.
+    Contain parameters that control the smearing of the orbital occupation at finite
+    electronic temperatures.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_smearing'))
 
-class message_debug(MCategory):
+
+class settings_stress_tensor(MCategory):
     '''
-    A debugging message of the computational program.
+    Settings to calculate the stress tensor (stress_tensor) consistent with the total
+    energy of the system given in energy_total.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='settings_stress_tensor'))
 
-class message_error(MCategory):
+
+class stress_tensor_type(MCategory):
     '''
-    An error message of the computational program.
+    Contains the final value of the default stress tensor (stress_tensor) and/or the value
+    of the stress tensor (stress_tensor_value) of the kind defined in stress_tensor_kind.
     '''
 
+    m_def = Category(
+        a_legacy=LegacyDefinition(name='stress_tensor_type'))
 
-class message_info(MCategory):
+
+class energy_component_per_atom(MCategory):
     '''
-    An information message of the computational program.
+    A value of an energy component per atom, concurring in defining the total energy per
+    atom.
     '''
 
+    m_def = Category(
+        categories=[energy_value],
+        a_legacy=LegacyDefinition(name='energy_component_per_atom'))
 
-class message_warning(MCategory):
+
+class energy_component(MCategory):
     '''
-    A warning message of the computational program.
+    A value of an energy component, expected to be an extensive property.
     '''
 
+    m_def = Category(
+        categories=[energy_value],
+        a_legacy=LegacyDefinition(name='energy_component'))
 
-class parallelization_info(MCategory):
+
+class energy_type_reference(MCategory):
     '''
-    Contains information on the parallelization of the program, i.e. which parallel
-    programming language was used and its version, how many cores had been working on the
-    calculation and the flags and parameters needed to run the parallelization of the
-    code.
+    This metadata stores an energy used as reference point.
     '''
 
+    m_def = Category(
+        categories=[energy_value],
+        a_legacy=LegacyDefinition(name='energy_type_reference'))
 
-class parsing_message_debug(MCategory):
+
+class error_estimate(MCategory):
     '''
-    This field is used for debugging messages of the parsing program.
+    An estimate of the error on the converged (final) value.
     '''
 
+    m_def = Category(
+        categories=[error_estimate_contribution],
+        a_legacy=LegacyDefinition(name='error_estimate'))
 
-class parsing_message_error(MCategory):
+
+class message_info(MCategory):
     '''
-    This field is used for error messages of the parsing program.
+    An information message of the computational program.
     '''
 
+    m_def = Category(
+        categories=[message_debug],
+        a_legacy=LegacyDefinition(name='message_info'))
 
-class parsing_message_info(MCategory):
+
+class parallelization_info(MCategory):
     '''
-    This field is used for info messages of the parsing program.
+    Contains information on the parallelization of the program, i.e. which parallel
+    programming language was used and its version, how many cores had been working on the
+    calculation and the flags and parameters needed to run the parallelization of the
+    code.
     '''
 
+    m_def = Category(
+        categories=[accessory_info],
+        a_legacy=LegacyDefinition(name='parallelization_info'))
 
-class parsing_message_warning(MCategory):
+
+class parsing_message_info(MCategory):
     '''
-    This field is used for warning messages of the parsing program.
+    This field is used for info messages of the parsing program.
     '''
 
+    m_def = Category(
+        categories=[parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_info'))
+
 
 class program_info(MCategory):
     '''
@@ -186,143 +278,210 @@ class program_info(MCategory):
     children of this field.
     '''
 
-
-class scf_info(MCategory):
-    '''
-    Contains information on the self-consistent field (SCF) procedure, i.e. the number of
-    SCF iterations (number_of_scf_iterations) or a section_scf_iteration section with
-    detailed information on the SCF procedure of specified quantities.
-    '''
+    m_def = Category(
+        categories=[accessory_info],
+        a_legacy=LegacyDefinition(name='program_info'))
 
 
-class settings_barostat(MCategory):
+class settings_geometry_optimization(MCategory):
     '''
-    Contains parameters controlling the barostat in a molecular dynamics calculation.
+    Contains parameters controlling the geometry optimization.
     '''
 
+    m_def = Category(
+        categories=[settings_sampling],
+        a_legacy=LegacyDefinition(name='settings_geometry_optimization'))
 
-class settings_coupled_cluster(MCategory):
-    '''
-    Contains parameters for the coupled-cluster method (CC) in the post Hartree-Fock step.
-    '''
 
-
-class settings_geometry_optimization(MCategory):
+class settings_k_points(MCategory):
     '''
-    Contains parameters controlling the geometry optimization.
+    Contains parameters that control the $k$-point mesh.
     '''
 
+    m_def = Category(
+        categories=[settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_k_points'))
 
-class settings_GW(MCategory):
+
+class settings_metadynamics(MCategory):
     '''
-    Contains parameters for the GW-method in the post Hartree-Fock step, that expands the
-    self-energy in terms of the single particle Green's function $G$ and the screened
-    Coulomb interaction $W$.
+    Contains parameters that control the metadynamics sampling.
     '''
 
+    m_def = Category(
+        categories=[settings_sampling],
+        a_legacy=LegacyDefinition(name='settings_metadynamics'))
 
-class settings_integrator(MCategory):
+
+class settings_molecular_dynamics(MCategory):
     '''
-    Contains parameters that control the molecular dynamics (MD) integrator.
+    Contains parameters that control the molecular dynamics sampling.
     '''
 
+    m_def = Category(
+        categories=[settings_sampling],
+        a_legacy=LegacyDefinition(name='settings_molecular_dynamics'))
 
-class settings_k_points(MCategory):
+
+class settings_Monte_Carlo(MCategory):
     '''
-    Contains parameters that control the $k$-point mesh.
+    Contains parameters that control the Monte-Carlo sampling.
     '''
 
+    m_def = Category(
+        categories=[settings_sampling],
+        a_legacy=LegacyDefinition(name='settings_Monte_Carlo'))
 
-class settings_MCSCF(MCategory):
+
+class settings_XC(MCategory):
     '''
-    Contains parameters for the multi-configurational self-consistent-field (MCSCF)
-    method.
+    Contains parameters connected with the definition of the exchange-correlation (XC)
+    *method*. Here, the term *method* is a more general concept than just *functionals*
+    and include, e.g., post Hartree-Fock methods, too.
     '''
 
+    m_def = Category(
+        categories=[settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_XC'))
 
-class settings_metadynamics(MCategory):
+
+class time_info(MCategory):
     '''
-    Contains parameters that control the metadynamics sampling.
+    Stores information on the date and timings of the calculation. They are useful for,
+    e.g., debugging or visualization purposes.
     '''
 
+    m_def = Category(
+        categories=[accessory_info],
+        a_legacy=LegacyDefinition(name='time_info'))
 
-class settings_molecular_dynamics(MCategory):
+
+class energy_total_potential_per_atom(MCategory):
     '''
-    Contains parameters that control the molecular dynamics sampling.
+    A value of the total potential energy per atom. Note that a direct comparison may not
+    be possible because of a difference in the methods for computing total energies and
+    numerical implementations of various codes might leads to different energy zeros (see
+    section_energy_code_independent for a code-independent definition of the energy).
     '''
 
+    m_def = Category(
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_total_potential_per_atom'))
 
-class settings_moller_plesset_perturbation_theory(MCategory):
+
+class energy_total_potential(MCategory):
     '''
-    Contains parameters for Møller–Plesset perturbation theory.
+    A value of the total potential energy. Note that a direct comparison may not be
+    possible because of a difference in the methods for computing total energies and
+    numerical implementations of various codes might leads to different energy zeros (see
+    section_energy_code_independent for a code-independent definition of the energy).
     '''
 
+    m_def = Category(
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_total_potential'))
 
-class settings_Monte_Carlo(MCategory):
+
+class energy_type_C(MCategory):
     '''
-    Contains parameters that control the Monte-Carlo sampling.
+    This metadata stores the correlation (C) energy.
     '''
 
+    m_def = Category(
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_type_C'))
 
-class settings_multi_reference(MCategory):
+
+class energy_type_van_der_Waals(MCategory):
     '''
-    Contains parameters for the multi-reference single and double configuration
-    interaction method.
+    This metadata stores the converged van der Waals energy.
     '''
 
+    m_def = Category(
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_type_van_der_Waals'))
 
-class settings_numerical_parameter(MCategory):
+
+class energy_type_XC(MCategory):
     '''
-    A parameter that can influence the convergence, but not the physics (unlike
-    settings_physical_parameter)
+    This metadata stores the exchange-correlation (XC) energy.
     '''
 
+    m_def = Category(
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_type_XC'))
 
-class settings_physical_parameter(MCategory):
+
+class energy_type_X(MCategory):
     '''
-    A parameter that defines the physical model used. Use settings_numerical_parameter for
-    parameters that that influence only the convergence/accuracy.
+    This metadata stores the exchange (X) energy.
     '''
 
+    m_def = Category(
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_type_X'))
 
-class settings_post_hartree_fock(MCategory):
+
+class message_warning(MCategory):
     '''
-    Contains parameters for the post Hartree-Fock method.
+    A warning message of the computational program.
     '''
 
+    m_def = Category(
+        categories=[message_info, message_debug],
+        a_legacy=LegacyDefinition(name='message_warning'))
 
-class settings_potential_energy_surface(MCategory):
+
+class parsing_message_warning(MCategory):
     '''
-    Contains parameters that control the potential energy surface.
+    This field is used for warning messages of the parsing program.
     '''
 
+    m_def = Category(
+        categories=[parsing_message_info, parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_warning'))
 
-class settings_relativity(MCategory):
+
+class settings_barostat(MCategory):
     '''
-    Contains parameters and information connected with the relativistic treatment used in
-    the calculation.
+    Contains parameters controlling the barostat in a molecular dynamics calculation.
     '''
 
+    m_def = Category(
+        categories=[settings_sampling, settings_molecular_dynamics],
+        a_legacy=LegacyDefinition(name='settings_barostat'))
 
-class settings_run(MCategory):
+
+class settings_integrator(MCategory):
     '''
-    Contains parameters that control the whole run (but not the *single configuration
-    calculation*, see section_single_configuration_calculation).
+    Contains parameters that control the molecular dynamics (MD) integrator.
     '''
 
+    m_def = Category(
+        categories=[settings_sampling, settings_molecular_dynamics],
+        a_legacy=LegacyDefinition(name='settings_integrator'))
 
-class settings_sampling(MCategory):
+
+class settings_post_hartree_fock(MCategory):
     '''
-    Contains parameters controlling the sampling.
+    Contains parameters for the post Hartree-Fock method.
     '''
 
+    m_def = Category(
+        categories=[settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_post_hartree_fock'))
 
-class settings_scf(MCategory):
+
+class settings_relativity(MCategory):
     '''
-    Contains parameters connected with the convergence of the self-consistent field (SCF)
-    iterations.
+    Contains parameters and information connected with the relativistic treatment used in
+    the calculation.
     '''
 
+    m_def = Category(
+        categories=[settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_relativity'))
+
 
 class settings_self_interaction_correction(MCategory):
     '''
@@ -330,19 +489,9 @@ class settings_self_interaction_correction(MCategory):
     (SIC) method being used in self_interaction_correction_method.
     '''
 
-
-class settings_smearing(MCategory):
-    '''
-    Contain parameters that control the smearing of the orbital occupation at finite
-    electronic temperatures.
-    '''
-
-
-class settings_stress_tensor(MCategory):
-    '''
-    Settings to calculate the stress tensor (stress_tensor) consistent with the total
-    energy of the system given in energy_total.
-    '''
+    m_def = Category(
+        categories=[settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_self_interaction_correction'))
 
 
 class settings_thermostat(MCategory):
@@ -351,6 +500,10 @@ class settings_thermostat(MCategory):
     calculations.
     '''
 
+    m_def = Category(
+        categories=[settings_sampling, settings_molecular_dynamics],
+        a_legacy=LegacyDefinition(name='settings_thermostat'))
+
 
 class settings_van_der_Waals(MCategory):
     '''
@@ -358,6 +511,10 @@ class settings_van_der_Waals(MCategory):
     the calculation to compute the Van der Waals energy (energy_van_der_Waals).
     '''
 
+    m_def = Category(
+        categories=[settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_van_der_Waals'))
+
 
 class settings_XC_functional(MCategory):
     '''
@@ -365,42 +522,99 @@ class settings_XC_functional(MCategory):
     functional (see section_XC_functionals and XC_functional).
     '''
 
+    m_def = Category(
+        categories=[settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_XC_functional'))
 
-class settings_XC(MCategory):
+
+class message_error(MCategory):
     '''
-    Contains parameters connected with the definition of the exchange-correlation (XC)
-    *method*. Here, the term *method* is a more general concept than just *functionals*
-    and include, e.g., post Hartree-Fock methods, too.
+    An error message of the computational program.
+    '''
+
+    m_def = Category(
+        categories=[message_info, message_debug, message_warning],
+        a_legacy=LegacyDefinition(name='message_error'))
+
+
+class parsing_message_error(MCategory):
+    '''
+    This field is used for error messages of the parsing program.
+    '''
+
+    m_def = Category(
+        categories=[parsing_message_info, parsing_message_warning, parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_error'))
+
+
+class settings_coupled_cluster(MCategory):
+    '''
+    Contains parameters for the coupled-cluster method (CC) in the post Hartree-Fock step.
+    '''
+
+    m_def = Category(
+        categories=[settings_post_hartree_fock, settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_coupled_cluster'))
+
+
+class settings_GW(MCategory):
+    '''
+    Contains parameters for the GW-method in the post Hartree-Fock step, that expands the
+    self-energy in terms of the single particle Green's function $G$ and the screened
+    Coulomb interaction $W$.
+    '''
+
+    m_def = Category(
+        categories=[settings_post_hartree_fock, settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_GW'))
+
+
+class settings_MCSCF(MCategory):
+    '''
+    Contains parameters for the multi-configurational self-consistent-field (MCSCF)
+    method.
     '''
 
+    m_def = Category(
+        categories=[settings_post_hartree_fock, settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_MCSCF'))
 
-class stress_tensor_type(MCategory):
+
+class settings_moller_plesset_perturbation_theory(MCategory):
     '''
-    Contains the final value of the default stress tensor (stress_tensor) and/or the value
-    of the stress tensor (stress_tensor_value) of the kind defined in stress_tensor_kind.
+    Contains parameters for Møller–Plesset perturbation theory.
     '''
 
+    m_def = Category(
+        categories=[settings_post_hartree_fock, settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_moller_plesset_perturbation_theory'))
 
-class time_info(MCategory):
+
+class settings_multi_reference(MCategory):
     '''
-    Stores information on the date and timings of the calculation. They are useful for,
-    e.g., debugging or visualization purposes.
+    Contains parameters for the multi-reference single and double configuration
+    interaction method.
     '''
 
+    m_def = Category(
+        categories=[settings_post_hartree_fock, settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='settings_multi_reference'))
+
 
 class archive_context(MSection):
     '''
     Contains information relating to an archive.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='archive_context'))
 
     archive_gid = Quantity(
         type=str,
         shape=[],
         description='''
         unique identifier of an archive.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='archive_gid'))
 
 
 class calculation_context(MSection):
@@ -408,14 +622,15 @@ class calculation_context(MSection):
     Contains information relating to a calculation.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='calculation_context'))
 
     calculation_gid = Quantity(
         type=str,
         shape=[],
         description='''
         unique identifier of a calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_gid'))
 
 
 class section_atom_projected_dos(MSection):
@@ -424,7 +639,7 @@ class section_atom_projected_dos(MSection):
     evaluation.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_atom_projected_dos'))
 
     atom_projected_dos_energies = Quantity(
         type=np.dtype(np.float64),
@@ -433,7 +648,8 @@ class section_atom_projected_dos(MSection):
         description='''
         Array containing the set of discrete energy values for the atom-projected density
         (electronic-energy) of states (DOS).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_projected_dos_energies'))
 
     atom_projected_dos_lm = Quantity(
         type=np.dtype(np.int32),
@@ -446,7 +662,8 @@ class section_atom_projected_dos(MSection):
         different conventions is accepted (see the [m_kind wiki
         page](https://gitlab.rzg.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/m-kind).
         The adopted convention is specified by atom_projected_dos_m_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_projected_dos_lm'))
 
     atom_projected_dos_m_kind = Quantity(
         type=str,
@@ -455,7 +672,8 @@ class section_atom_projected_dos(MSection):
         String describing what the integer numbers of $m$ in atom_projected_dos_lm mean.
         The allowed values are listed in the [m_kind wiki
         page](https://gitlab.rzg.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/m-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_projected_dos_m_kind'))
 
     atom_projected_dos_values_lm = Quantity(
         type=np.dtype(np.float64),
@@ -466,7 +684,8 @@ class section_atom_projected_dos(MSection):
         from each $l,m$ channel for the atom-projected density (electronic-energy) of
         states. Here, there are as many atom-projected DOS as the number_of_atoms, the
         list of labels of the atoms and their meanings are in atom_labels.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_projected_dos_values_lm'))
 
     atom_projected_dos_values_total = Quantity(
         type=np.dtype(np.float64),
@@ -478,7 +697,8 @@ class section_atom_projected_dos(MSection):
         of states (DOS). Here, there are as many atom-projected DOS as the
         number_of_atoms, the list of labels of the atoms and their meanings are in
         atom_labels.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_projected_dos_values_total'))
 
     number_of_atom_projected_dos_values = Quantity(
         type=int,
@@ -486,7 +706,8 @@ class section_atom_projected_dos(MSection):
         description='''
         Gives the number of energy values for the atom-projected density of states (DOS)
         based on atom_projected_dos_values_lm and atom_projected_dos_values_total.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atom_projected_dos_values'))
 
     number_of_lm_atom_projected_dos = Quantity(
         type=int,
@@ -494,7 +715,8 @@ class section_atom_projected_dos(MSection):
         description='''
         Gives the number of $l$, $m$ combinations for the atom projected density of states
         (DOS) defined in section_atom_projected_dos.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_lm_atom_projected_dos'))
 
 
 class section_atomic_multipoles(MSection):
@@ -503,7 +725,7 @@ class section_atomic_multipoles(MSection):
     atom.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_atomic_multipoles'))
 
     atomic_multipole_kind = Quantity(
         type=str,
@@ -515,7 +737,8 @@ class section_atomic_multipoles(MSection):
         metadata. Allowed values are listed in the [atomic_multipole_kind wiki
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/atomic-
         multipole-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atomic_multipole_kind'))
 
     atomic_multipole_lm = Quantity(
         type=np.dtype(np.int32),
@@ -526,7 +749,8 @@ class section_atomic_multipoles(MSection):
         is specified by atomic_multipole_kind. The meaning of the integer number $l$ is
         monopole/charge for $l=0$, dipole for $l=1$, quadrupole for $l=2$, etc. The
         meaning of the integer numbers $m$ is specified by atomic_multipole_m_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atomic_multipole_lm'))
 
     atomic_multipole_m_kind = Quantity(
         type=str,
@@ -535,7 +759,8 @@ class section_atomic_multipoles(MSection):
         String describing the definition for each integer number $m$ in
         atomic_multipole_lm. Allowed values are listed in the [m_kind wiki
         page](https://gitlab.rzg.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/m-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atomic_multipole_m_kind'))
 
     atomic_multipole_values = Quantity(
         type=np.dtype(np.float64),
@@ -543,7 +768,8 @@ class section_atomic_multipoles(MSection):
         description='''
         Value of the multipoles (including the monopole/charge for $l$ = 0, the dipole for
         $l$ = 1, etc.) for each atom, calculated as described in atomic_multipole_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atomic_multipole_values'))
 
     number_of_lm_atomic_multipoles = Quantity(
         type=int,
@@ -551,7 +777,8 @@ class section_atomic_multipoles(MSection):
         description='''
         Gives the number of $l$, $m$ combinations for atomic multipoles
         atomic_multipole_lm.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_lm_atomic_multipoles'))
 
 
 class section_basis_functions_atom_centered(MSection):
@@ -560,7 +787,7 @@ class section_basis_functions_atom_centered(MSection):
     of the (atom-centered) basis set defined in section_basis_set_atom_centered.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_basis_functions_atom_centered'))
 
 
 class section_basis_set_atom_centered(MSection):
@@ -573,7 +800,7 @@ class section_basis_set_atom_centered(MSection):
     in the section_basis_functions_atom_centered section.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_basis_set_atom_centered'))
 
     basis_set_atom_centered_ls = Quantity(
         type=np.dtype(np.int32),
@@ -582,7 +809,8 @@ class section_basis_set_atom_centered(MSection):
         Azimuthal quantum number ($l$) values (of the angular part given by the spherical
         harmonic $Y_{lm}$) of the atom-centered basis function defined in the current
         section_basis_set_atom_centered.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_atom_centered_ls'))
 
     basis_set_atom_centered_radial_functions = Quantity(
         type=np.dtype(np.float64),
@@ -592,7 +820,8 @@ class section_basis_set_atom_centered(MSection):
         are numerically tabulated on a default 0.01-nm equally spaced grid from 0 to 4 nm.
         The 5 tabulated values are $r$, $f(r)$, $f'(r)$, $f(r) \\cdot r$,
         $\\frac{d}{dr}(f(r) \\cdot r)$.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_atom_centered_radial_functions'))
 
     basis_set_atom_centered_short_name = Quantity(
         type=str,
@@ -603,7 +832,8 @@ class section_basis_set_atom_centered(MSection):
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/basis-
         set-atom-centered-short-name), this name should not contain the *atom kind* (to
         simplify the use of a single name for multiple elements).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_atom_centered_short_name'))
 
     basis_set_atom_centered_unique_name = Quantity(
         type=str,
@@ -624,7 +854,8 @@ class section_basis_set_atom_centered(MSection):
         not contain the *atom kind* for which this basis set is intended for, in order to
         simplify the use of a single name for multiple *atom kinds* (see atom_labels for
         the actual meaning of *atom kind*).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_atom_centered_unique_name'))
 
     basis_set_atom_number = Quantity(
         type=np.dtype(np.int32),
@@ -632,7 +863,8 @@ class section_basis_set_atom_centered(MSection):
         description='''
         Atomic number (i.e., number of protons) of the atom for which this basis set is
         constructed (0 means unspecified or a pseudo atom).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_atom_number'))
 
     number_of_basis_functions_in_basis_set_atom_centered = Quantity(
         type=int,
@@ -641,7 +873,8 @@ class section_basis_set_atom_centered(MSection):
         Gives the number of different basis functions in a section_basis_set_atom_centered
         section. This equals the number of actual coefficients that are specified when
         using this basis set.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_basis_functions_in_basis_set_atom_centered'))
 
     number_of_kinds_in_basis_set_atom_centered = Quantity(
         type=int,
@@ -651,15 +884,18 @@ class section_basis_set_atom_centered(MSection):
         section_basis_set_atom_centered section. Specifically, basis functions with the
         same $n$ and $l$ quantum numbers are grouped in sets. Each set counts as one
         *kind*.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_kinds_in_basis_set_atom_centered'))
 
     section_basis_functions_atom_centered = SubSection(
         sub_section=SectionProxy('section_basis_functions_atom_centered'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_basis_functions_atom_centered'))
 
     section_gaussian_basis_group = SubSection(
         sub_section=SectionProxy('section_gaussian_basis_group'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_gaussian_basis_group'))
 
 
 class section_basis_set_cell_dependent(MSection):
@@ -671,7 +907,7 @@ class section_basis_set_cell_dependent(MSection):
     parameter(s), stored in basis_set_cell_dependent_name).
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_basis_set_cell_dependent'))
 
     basis_set_cell_dependent_kind = Quantity(
         type=str,
@@ -681,7 +917,8 @@ class section_basis_set_cell_dependent(MSection):
         centered such as plane-waves). Allowed values are listed in the
         [basis_set_cell_dependent_kind wiki page](https://gitlab.mpcdf.mpg.de/nomad-
         lab/nomad-meta-info/wikis/metainfo/basis-set-cell-dependent-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_cell_dependent_kind'))
 
     basis_set_cell_dependent_name = Quantity(
         type=str,
@@ -691,7 +928,8 @@ class section_basis_set_cell_dependent(MSection):
         plane-waves). Allowed values are listed in the [basis_set_cell_dependent_name wiki
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/basis-
         set-cell-dependent-name).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_cell_dependent_name'))
 
     basis_set_planewave_cutoff = Quantity(
         type=np.dtype(np.float64),
@@ -703,7 +941,8 @@ class section_basis_set_cell_dependent(MSection):
         set. Note that normally this basis set is used for the wavefunctions, and the
         density would have 4 times the cutoff, but this actually depends on the use of the
         basis set by the method.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_planewave_cutoff'))
 
 
 class section_basis_set(MSection):
@@ -732,7 +971,7 @@ class section_basis_set(MSection):
     set, where the same basis set can be assigned to more than one atom.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_basis_set'))
 
     basis_set_kind = Quantity(
         type=str,
@@ -742,7 +981,8 @@ class section_basis_set(MSection):
         function or an electron density. Allowed values are listed in the [basis_set_kind
         wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/basis-set-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_kind'))
 
     basis_set_name = Quantity(
         type=str,
@@ -752,7 +992,8 @@ class section_basis_set(MSection):
         string are specified in the [basis_set_name wiki
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/basis-
         set-name).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='basis_set_name'))
 
     mapping_section_basis_set_atom_centered = Quantity(
         type=Reference(SectionProxy('section_basis_set_atom_centered')),
@@ -763,7 +1004,8 @@ class section_basis_set(MSection):
         section_single_configuration_calculation. The actual definition of the atom-
         centered basis set is in the section_basis_set_atom_centered that is referred to
         by this metadata.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='mapping_section_basis_set_atom_centered'))
 
     mapping_section_basis_set_cell_dependent = Quantity(
         type=Reference(SectionProxy('section_basis_set_cell_dependent')),
@@ -772,14 +1014,16 @@ class section_basis_set(MSection):
         Assignment of the cell-dependent (i.e., non atom centered, e.g., plane-waves)
         parts of the basis set, which is defined (type, parameters) in
         section_basis_set_cell_dependent that is referred to by this metadata.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='mapping_section_basis_set_cell_dependent'))
 
     number_of_basis_functions = Quantity(
         type=int,
         shape=[],
         description='''
         Stores the total number of basis functions in a section_basis_set section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_basis_functions'))
 
 
 class section_restricted_uri(MSection):
@@ -788,14 +1032,15 @@ class section_restricted_uri(MSection):
     this calculation can be subject to restriction)
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_restricted_uri'))
 
     number_of_restricted_uri = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         The number of restricted uris in restricted_uri list.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_restricted_uri'))
 
     restricted_uri = Quantity(
         type=str,
@@ -803,7 +1048,8 @@ class section_restricted_uri(MSection):
         description='''
         The list of nomad uri(s) identifying the restricted info/file corresponding to
         this calculation
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='restricted_uri'))
 
     restricted_uri_reason = Quantity(
         type=str,
@@ -812,7 +1058,8 @@ class section_restricted_uri(MSection):
         The reason of restriction for the uri or file. The reason can be 'propriety
         license', 'open-source redistribution restricted license', 'other license', or
         'author restricted'.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='restricted_uri_reason'))
 
     restricted_uri_issue_authority = Quantity(
         type=str,
@@ -821,7 +1068,8 @@ class section_restricted_uri(MSection):
         The issue authority is the restriction owner for the uri or file. This can be
         license owner such as 'VASP' or 'AMBER', 'NOMAD', or the author of the uri. For
         example the repository user name of the author.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='restricted_uri_issue_authority'))
 
     restricted_uri_end_date = Quantity(
         type=str,
@@ -830,7 +1078,8 @@ class section_restricted_uri(MSection):
         The deadline date of the restriction for the uri or file. The end date can be in
         date format string for those restrictions set by authors or NOMAD otherwise it is
         set to 'unlimited' for the restriction related to license.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='restricted_uri_end_date'))
 
     restricted_uri_restriction = Quantity(
         type=str,
@@ -838,21 +1087,24 @@ class section_restricted_uri(MSection):
         description='''
         The type of restriction for the uri or file. The type can be 'any access' or
         'license permitted'.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='restricted_uri_restriction'))
 
     restricted_uri_license = Quantity(
         type=str,
         shape=[],
         description='''
         The info of the license that is the reason of restriction.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='restricted_uri_license'))
 
     number_of_restricted_uri_files = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         The number of restricted files in restricted_uri_files list.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_restricted_uri_files'))
 
 
 class section_calculation_to_calculation_refs(MSection):
@@ -873,7 +1125,7 @@ class section_calculation_to_calculation_refs(MSection):
     calculation_to_calculation_external_url.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_calculation_to_calculation_refs'))
 
     calculation_to_calculation_external_url = Quantity(
         type=str,
@@ -882,7 +1134,8 @@ class section_calculation_to_calculation_refs(MSection):
         URL used to reference an externally stored calculation. The kind of relationship
         between the present and the referenced section_single_configuration_calculation is
         specified by calculation_to_calculation_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_to_calculation_external_url'))
 
     calculation_to_calculation_kind = Quantity(
         type=str,
@@ -901,7 +1154,8 @@ class section_calculation_to_calculation_refs(MSection):
         connected calculations. The referenced calculation is identified via
         calculation_to_calculation_ref (typically used for a calculation in the same
         section_run) or calculation_to_calculation_external_url.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_to_calculation_kind'))
 
     calculation_to_calculation_ref = Quantity(
         type=Reference(SectionProxy('section_single_configuration_calculation')),
@@ -913,7 +1167,8 @@ class section_calculation_to_calculation_refs(MSection):
         calculation_to_calculation_external_url. The kind of relationship between the
         present and the referenced section_single_configuration_calculation is specified
         by calculation_to_calculation_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_to_calculation_ref'))
 
 
 class section_calculation_to_folder_refs(MSection):
@@ -923,7 +1178,7 @@ class section_calculation_to_folder_refs(MSection):
     calulations
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_calculation_to_folder_refs'))
 
     calculation_to_folder_external_url = Quantity(
         type=str,
@@ -933,7 +1188,8 @@ class section_calculation_to_folder_refs(MSection):
         relationship between the present and the referenced
         section_single_configuration_calculation is specified by
         calculation_to_folder_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_to_folder_external_url'))
 
     calculation_to_folder_kind = Quantity(
         type=str,
@@ -941,7 +1197,8 @@ class section_calculation_to_folder_refs(MSection):
         description='''
         String defining the relationship between the referenced
         section_single_configuration_calculation and a folder containing calculations.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_to_folder_kind'))
 
 
 class section_dos(MSection):
@@ -950,7 +1207,7 @@ class section_dos(MSection):
     of states (DOS) evaluation.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_dos'))
 
     dos_energies_normalized = Quantity(
         type=np.dtype(np.float64),
@@ -961,7 +1218,8 @@ class section_dos(MSection):
         valence band for the density (electronic-energy) of states (DOS). This is the
         total DOS, see atom_projected_dos_energies and species_projected_dos_energies for
         partial density of states.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_energies_normalized'))
 
     dos_energies = Quantity(
         type=np.dtype(np.float64),
@@ -972,14 +1230,16 @@ class section_dos(MSection):
         energy or vibrational energy) of states (DOS). This is the total DOS, see
         atom_projected_dos_energies and species_projected_dos_energies for partial density
         of states.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_energies'))
 
     dos_fermi_energy = Quantity(
         type=np.dtype(np.float64),
         shape=[],
         description='''
         Stores the Fermi energy of the density of states.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_fermi_energy'))
 
     dos_integrated_values = Quantity(
         type=np.dtype(np.float64),
@@ -988,7 +1248,8 @@ class section_dos(MSection):
         Integrated density of states (starting at $-\\infty$), pseudo potential
         calculations should start with the number of core electrons if they cover only the
         active electrons
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_integrated_values'))
 
     dos_kind = Quantity(
         type=str,
@@ -996,7 +1257,8 @@ class section_dos(MSection):
         description='''
         String to specify the kind of density of states (either electronic or
         vibrational).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_kind'))
 
     dos_lm = Quantity(
         type=np.dtype(np.int32),
@@ -1009,7 +1271,8 @@ class section_dos(MSection):
         accepted (see the [m_kind wiki page](https://gitlab.rzg.mpg.de/nomad-lab/nomad-
         meta-info/wikis/metainfo/m-kind). The actual adopted convention is specified by
         dos_m_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_lm'))
 
     dos_m_kind = Quantity(
         type=str,
@@ -1018,7 +1281,8 @@ class section_dos(MSection):
         String describing what the integer numbers of $m$ in dos_lm mean. The allowed
         values are listed in the [m_kind wiki page](https://gitlab.rzg.mpg.de/nomad-
         lab/nomad-meta-info/wikis/metainfo/m-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_m_kind'))
 
     dos_values_lm = Quantity(
         type=np.dtype(np.float64),
@@ -1028,7 +1292,8 @@ class section_dos(MSection):
         Array containing the density (electronic-energy) of states values projected on the
         various spherical harmonics (integrated on all atoms), see
         atom_projected_dos_values_lm for atom values.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_values_lm'))
 
     dos_values_normalized = Quantity(
         type=np.dtype(np.float64),
@@ -1036,7 +1301,8 @@ class section_dos(MSection):
         description='''
         Density of states (DOS) values divided by the unit cell volume and by the number
         of atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_values_normalized'))
 
     dos_values = Quantity(
         type=np.dtype(np.float64),
@@ -1046,7 +1312,8 @@ class section_dos(MSection):
         given in dos_energies) of density (electronic-energy or vibrational-energy) of
         states. This refers to the simulation cell, i.e. integrating over all energies
         will give the number of electrons in the simulation cell.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='dos_values'))
 
     number_of_dos_lms = Quantity(
         type=int,
@@ -1054,7 +1321,8 @@ class section_dos(MSection):
         description='''
         Gives the number of $l$, $m$ combinations for the given projected density of
         states (DOS) in dos_values and dos_values_lm.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_dos_lms'))
 
     number_of_dos_values = Quantity(
         type=int,
@@ -1062,7 +1330,8 @@ class section_dos(MSection):
         description='''
         Gives the number of energy values for the density of states (DOS), see
         dos_energies.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_dos_values'))
 
 
 class section_eigenvalues(MSection):
@@ -1075,7 +1344,7 @@ class section_eigenvalues(MSection):
     stored in eigenvalues_values and eigenvalues_occupation, respectively.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_eigenvalues'))
 
     eigenvalues_kind = Quantity(
         type=str,
@@ -1084,7 +1353,8 @@ class section_eigenvalues(MSection):
         A short string describing the kind of eigenvalues, as defined in the
         [eigenvalues_kind wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/eigenvalues-kind).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='eigenvalues_kind'))
 
     eigenvalues_kpoints_multiplicity = Quantity(
         type=np.dtype(np.float64),
@@ -1094,7 +1364,8 @@ class section_eigenvalues(MSection):
         expands to after applying all symmetries). This defaults to 1. If expansion is
         preformed then each point will have weight
         eigenvalues_kpoints_weights/eigenvalues_kpoints_multiplicity.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='eigenvalues_kpoints_multiplicity'))
 
     eigenvalues_kpoints_weights = Quantity(
         type=np.dtype(np.float64),
@@ -1103,7 +1374,8 @@ class section_eigenvalues(MSection):
         Weights of the $k$ points (in the basis of the reciprocal lattice vectors) used
         for the evaluation of the eigenvalues tabulated in eigenvalues_values, should
         account for symmetry too.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='eigenvalues_kpoints_weights'))
 
     eigenvalues_kpoints = Quantity(
         type=np.dtype(np.float64),
@@ -1111,7 +1383,8 @@ class section_eigenvalues(MSection):
         description='''
         Coordinates of the $k$ points (in the basis of the reciprocal lattice vectors)
         used for the evaluation of the eigenvalues tabulated in eigenvalues_values.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='eigenvalues_kpoints'))
 
     eigenvalues_occupation = Quantity(
         type=np.dtype(np.float64),
@@ -1120,7 +1393,8 @@ class section_eigenvalues(MSection):
         Occupation of the eigenstates. The corresponding eigenvalues (energy) are given in
         eigenvalues_values. The coordinates in the reciprocal space are defined in
         eigenvalues_kpoints.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='eigenvalues_occupation'))
 
     eigenvalues_values = Quantity(
         type=np.dtype(np.float64),
@@ -1130,14 +1404,16 @@ class section_eigenvalues(MSection):
         Values of the (electronic-energy) eigenvalues. The coordinates of the
         corresponding eigenstates in the reciprocal space are defined in
         eigenvalues_kpoints and their occupations are given in eigenvalues_occupation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='eigenvalues_values'))
 
     number_of_band_segment_eigenvalues = Quantity(
         type=int,
         shape=[],
         description='''
         Gives the number of eigenvalues in a band segment, see band_energies.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_band_segment_eigenvalues'))
 
     number_of_eigenvalues_kpoints = Quantity(
         type=int,
@@ -1145,14 +1421,16 @@ class section_eigenvalues(MSection):
         description='''
         Gives the number of $k$ points, see eigenvalues_kpoints. $k$ points are calculated
         within a run and are irreducible if a symmetry is used.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_eigenvalues_kpoints'))
 
     number_of_eigenvalues = Quantity(
         type=int,
         shape=[],
         description='''
         Gives the number of eigenvalues, see eigenvalues_values.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_eigenvalues'))
 
     number_of_normalized_band_segment_eigenvalues = Quantity(
         type=int,
@@ -1161,7 +1439,8 @@ class section_eigenvalues(MSection):
         Gives the number of normalized eigenvalues in a band segment, see
 
         band_energies_normalized.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_normalized_band_segment_eigenvalues'))
 
 
 class section_energy_code_independent(MSection):
@@ -1173,7 +1452,7 @@ class section_energy_code_independent(MSection):
     different codes and numerical settings.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_energy_code_independent'))
 
     energy_code_independent_kind = Quantity(
         type=str,
@@ -1184,7 +1463,8 @@ class section_energy_code_independent(MSection):
         codes and numerical settings. Details can be found on the [energy_code_independent
         wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/energy-code-independent).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='energy_code_independent_kind'))
 
     energy_code_independent_value = Quantity(
         type=np.dtype(np.float64),
@@ -1197,7 +1477,8 @@ class section_energy_code_independent(MSection):
         [energy_code_independent wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-
         meta-info/wikis/metainfo/energy-code-independent).
         ''',
-        categories=[energy_component, energy_value, energy_total_potential])
+        categories=[energy_component, energy_value, energy_total_potential],
+        a_legacy=LegacyDefinition(name='energy_code_independent_value'))
 
 
 class section_energy_van_der_Waals(MSection):
@@ -1211,7 +1492,7 @@ class section_energy_van_der_Waals(MSection):
     settings_van_der_Waals.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_energy_van_der_Waals'))
 
     energy_van_der_Waals_kind = Quantity(
         type=str,
@@ -1223,7 +1504,8 @@ class section_energy_van_der_Waals(MSection):
         section_single_configuration_calculation). The method used for van der Waals  (the
         one consistent with energy_current and, e.g., for evaluating the forces for a
         relaxation or dynamics) is defined in settings_van_der_Waals.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='energy_van_der_Waals_kind'))
 
     energy_van_der_Waals_value = Quantity(
         type=np.dtype(np.float64),
@@ -1238,7 +1520,8 @@ class section_energy_van_der_Waals(MSection):
         relaxation or dynamics, is given in energy_van_der_Waals and defined in
         settings_van_der_Waals.
         ''',
-        categories=[energy_value, energy_type_van_der_Waals, energy_component])
+        categories=[energy_type_van_der_Waals, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_van_der_Waals_value'))
 
     energy_van_der_Waals = Quantity(
         type=np.dtype(np.float64),
@@ -1250,7 +1533,8 @@ class section_energy_van_der_Waals(MSection):
         method consistent with, e.g., forces used for relaxation or dynamics. Alternative
         methods are listed in section_energy_van_der_Waals.
         ''',
-        categories=[energy_value, energy_type_van_der_Waals, energy_component])
+        categories=[energy_type_van_der_Waals, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_van_der_Waals'))
 
 
 class section_frame_sequence_user_quantity(MSection):
@@ -1258,7 +1542,7 @@ class section_frame_sequence_user_quantity(MSection):
     Section collecting some user-defined quantities evaluated along a sequence of frame.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_frame_sequence_user_quantity'))
 
     frame_sequence_user_quantity_frames = Quantity(
         type=np.dtype(np.int32),
@@ -1267,7 +1551,8 @@ class section_frame_sequence_user_quantity(MSection):
         Array containing the strictly increasing indices referring to the frames of
         frame_sequence_user_quantity. If not given it defaults to the trivial mapping
         0,1,...
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_user_quantity_frames'))
 
     frame_sequence_user_quantity_name = Quantity(
         type=str,
@@ -1281,7 +1566,8 @@ class section_frame_sequence_user_quantity(MSection):
         instantaneous temperature (frame_sequence_temperature) and pressure
         (frame_sequence_pressure). This metadata should be used for other quantities that
         are monitored along a sequence of frames.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_user_quantity_name'))
 
     frame_sequence_user_quantity_stats = Quantity(
         type=np.dtype(np.float64),
@@ -1290,7 +1576,8 @@ class section_frame_sequence_user_quantity(MSection):
         Average of frame_sequence_user_quantity and its standard deviation in this
         sequence of frames (i.e., a trajectory, a frame is one
         section_single_configuration_calculation).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_user_quantity_stats'))
 
     frame_sequence_user_quantity = Quantity(
         type=np.dtype(np.float64),
@@ -1303,7 +1590,8 @@ class section_frame_sequence_user_quantity(MSection):
         frame_sequence_kinetic_energy_frames. If not all frames have a value the indices
         of the frames that have a value are stored in
         frame_sequence_kinetic_energy_frames.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_user_quantity'))
 
     number_of_frame_sequence_user_quantity_components = Quantity(
         type=int,
@@ -1320,7 +1608,8 @@ class section_frame_sequence_user_quantity(MSection):
         frame_sequence_potential_energy](frame_sequence_kinetic_energy and
         frame_sequence_potential_energy)), the instantaneous temperature
         (frame_sequence_temperature) and the pressure (frame_sequence_pressure).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_frame_sequence_user_quantity_components'))
 
     number_of_user_quantity_evaluations_in_sequence = Quantity(
         type=int,
@@ -1330,7 +1619,8 @@ class section_frame_sequence_user_quantity(MSection):
         frame_sequence_user_quantity frames. A sequence is a trajectory, which can have
         number_of_frames_in_sequence each representing one
         section_single_configuration_calculation section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_user_quantity_evaluations_in_sequence'))
 
 
 class section_frame_sequence(MSection):
@@ -1346,7 +1636,7 @@ class section_frame_sequence(MSection):
     found in the section_single_configuration_calculation section.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_frame_sequence'))
 
     frame_sequence_conserved_quantity_frames = Quantity(
         type=np.dtype(np.int32),
@@ -1355,7 +1645,8 @@ class section_frame_sequence(MSection):
         Array containing the strictly increasing indices of the frames the
         frame_sequence_conserved_quantity values refers to. If not given it defaults to
         the trivial mapping 0,1,...
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_conserved_quantity_frames'))
 
     frame_sequence_conserved_quantity_stats = Quantity(
         type=np.dtype(np.float64),
@@ -1365,7 +1656,8 @@ class section_frame_sequence(MSection):
         Average value of energy-like frame_sequence_conserved_quantity, and its standard
         deviation, over this sequence of frames (i.e., a trajectory, a frame is one
         section_single_configuration_calculation).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_conserved_quantity_stats'))
 
     frame_sequence_conserved_quantity = Quantity(
         type=np.dtype(np.float64),
@@ -1377,7 +1669,8 @@ class section_frame_sequence(MSection):
         section_single_configuration_calculation), for example the total energy in the NVE
         ensemble. If not all frames have a value the indices of the frames that have a
         value are stored in frame_sequence_conserved_quantity_frames.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_conserved_quantity'))
 
     frame_sequence_continuation_kind = Quantity(
         type=Reference(SectionProxy('section_frame_sequence')),
@@ -1386,7 +1679,8 @@ class section_frame_sequence(MSection):
         Type of continuation that has been performed from the previous sequence of frames
         (i.e., a trajectory, a frame is one section_single_configuration_calculation),
         upon restart.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_continuation_kind'))
 
     frame_sequence_external_url = Quantity(
         type=str,
@@ -1402,7 +1696,8 @@ class section_frame_sequence(MSection):
         for this reference is described in the [frame_sequence_external_url wiki
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/frame-
         sequence-external-url).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_external_url'))
 
     frame_sequence_kinetic_energy_frames = Quantity(
         type=np.dtype(np.int32),
@@ -1411,7 +1706,8 @@ class section_frame_sequence(MSection):
         Array containing the strictly increasing indices referring to the frames of
         frame_sequence_kinetic_energy. If not given it defaults to the trivial mapping
         0,1,...
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_kinetic_energy_frames'))
 
     frame_sequence_kinetic_energy_stats = Quantity(
         type=np.dtype(np.float64),
@@ -1420,7 +1716,8 @@ class section_frame_sequence(MSection):
         description='''
         Average kinetic energy and its standard deviation over this sequence of frames
         (i.e., a trajectory, a frame is one section_single_configuration_calculation).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_kinetic_energy_stats'))
 
     frame_sequence_kinetic_energy = Quantity(
         type=np.dtype(np.float64),
@@ -1431,7 +1728,8 @@ class section_frame_sequence(MSection):
         (i.e., a trajectory, a frame is one section_single_configuration_calculation). If
         not all frames have a value the indices of the frames that have a value are stored
         in frame_sequence_kinetic_energy_frames.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_kinetic_energy'))
 
     frame_sequence_local_frames_ref = Quantity(
         type=Reference(SectionProxy('section_single_configuration_calculation')),
@@ -1445,7 +1743,8 @@ class section_frame_sequence(MSection):
         molecular dynamics trajectory, or geometry optimization. The full information for
         each frame is stored in section_single_configuration_calculation and this metadata
         establishes the link for each frame.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_local_frames_ref'))
 
     frame_sequence_potential_energy_frames = Quantity(
         type=np.dtype(np.int32),
@@ -1454,7 +1753,8 @@ class section_frame_sequence(MSection):
         Array containing the strictly increasing indices referring to the frames of
         frame_sequence_potential_energy. If not given it defaults to the trivial mapping
         0,1,...
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_potential_energy_frames'))
 
     frame_sequence_potential_energy_stats = Quantity(
         type=np.dtype(np.float64),
@@ -1463,7 +1763,8 @@ class section_frame_sequence(MSection):
         description='''
         Average potential energy and its standard deviation over this sequence of frames
         (i.e., a trajectory, a frame is one section_single_configuration_calculation).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_potential_energy_stats'))
 
     frame_sequence_potential_energy = Quantity(
         type=np.dtype(np.float64),
@@ -1476,7 +1777,8 @@ class section_frame_sequence(MSection):
         section_single_configuration_calculation and repeated here in a summary array for
         easier access. If not all frames have a value the indices of the frames that have
         a value are stored in frame_sequence_potential_energy_frames.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_potential_energy'))
 
     frame_sequence_pressure_frames = Quantity(
         type=np.dtype(np.int32),
@@ -1484,7 +1786,8 @@ class section_frame_sequence(MSection):
         description='''
         Array containing the strictly increasing indices referring to the frames of
         frame_sequence_pressure. If not given it defaults to the trivial mapping 0,1,...
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_pressure_frames'))
 
     frame_sequence_pressure_stats = Quantity(
         type=np.dtype(np.float64),
@@ -1494,7 +1797,8 @@ class section_frame_sequence(MSection):
         Average pressure (one third of the trace of the stress tensor) and standard
         deviation over this sequence of frames (i.e., a trajectory, a frame is one
         section_single_configuration_calculation).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_pressure_stats'))
 
     frame_sequence_pressure = Quantity(
         type=np.dtype(np.float64),
@@ -1506,7 +1810,8 @@ class section_frame_sequence(MSection):
         section_single_configuration_calculation). If not all frames have a value the
         indices of the frames that have a value are stored in
         frame_sequence_pressure_frames.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_pressure'))
 
     frame_sequence_temperature_frames = Quantity(
         type=np.dtype(np.int32),
@@ -1515,7 +1820,8 @@ class section_frame_sequence(MSection):
         Array containing the strictly increasing indices referring to the frames of
         frame_sequence_temperature. If not given it defaults to the trivial mapping
         0,1,...
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_temperature_frames'))
 
     frame_sequence_temperature_stats = Quantity(
         type=np.dtype(np.float64),
@@ -1524,7 +1830,8 @@ class section_frame_sequence(MSection):
         description='''
         Average temperature and its standard deviation over this sequence of frames (i.e.,
         a trajectory, a frame is one section_single_configuration_calculation).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_temperature_stats'))
 
     frame_sequence_temperature = Quantity(
         type=np.dtype(np.float64),
@@ -1537,7 +1844,8 @@ class section_frame_sequence(MSection):
         frame is one section_single_configuration_calculation). If not all frames have a
         value the indices of the frames that have a value are stored in
         frame_sequence_temperature_frames.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_temperature'))
 
     frame_sequence_time = Quantity(
         type=np.dtype(np.float64),
@@ -1547,7 +1855,8 @@ class section_frame_sequence(MSection):
         Time along this sequence of frames (i.e., a trajectory, a frame is one
         section_single_configuration_calculation). Time start is arbitrary, but when a
         sequence is a continuation of another time should be continued too.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_time'))
 
     frame_sequence_to_sampling_ref = Quantity(
         type=Reference(SectionProxy('section_sampling_method')),
@@ -1556,14 +1865,16 @@ class section_frame_sequence(MSection):
         Reference from the present section_frame_sequence to the section_sampling_method,
         that defines the parameters used in this sequence of frames (i.e., a trajectory, a
         frame is one section_single_configuration_calculation).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='frame_sequence_to_sampling_ref'))
 
     geometry_optimization_converged = Quantity(
         type=bool,
         shape=[],
         description='''
         Arrays specify whether a geometry optimization is converged.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='geometry_optimization_converged'))
 
     number_of_conserved_quantity_evaluations_in_sequence = Quantity(
         type=int,
@@ -1572,7 +1883,8 @@ class section_frame_sequence(MSection):
         Gives the number of conserved quantity evaluations in this sequence. A sequence is
         a trajectory, which can have number_of_frames_in_sequence each representing one
         section_single_configuration_calculation section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_conserved_quantity_evaluations_in_sequence'))
 
     number_of_frames_in_sequence = Quantity(
         type=int,
@@ -1581,7 +1893,8 @@ class section_frame_sequence(MSection):
         Gives the number of frames in a sequence. A sequence is a trajectory, which can
         have number_of_frames_in_sequence each representing one
         section_single_configuration_calculation section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_frames_in_sequence'))
 
     number_of_kinetic_energies_in_sequence = Quantity(
         type=int,
@@ -1589,7 +1902,8 @@ class section_frame_sequence(MSection):
         description='''
         Gives the number of kinetic energy evaluations in this sequence of frames, see
         frame_sequence_kinetic_energy.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_kinetic_energies_in_sequence'))
 
     number_of_potential_energies_in_sequence = Quantity(
         type=int,
@@ -1598,7 +1912,8 @@ class section_frame_sequence(MSection):
         Gives the number of potential energies evaluation in this sequence. A sequence is
         a trajectory, which can have number_of_frames_in_sequence each representing one
         section_single_configuration_calculation section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_potential_energies_in_sequence'))
 
     number_of_pressure_evaluations_in_sequence = Quantity(
         type=int,
@@ -1607,7 +1922,8 @@ class section_frame_sequence(MSection):
         Gives the number of pressure evaluations in this sequence. A sequence is a
         trajectory, which can have number_of_frames_in_sequence each representing one
         section_single_configuration_calculation section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_pressure_evaluations_in_sequence'))
 
     number_of_temperatures_in_sequence = Quantity(
         type=int,
@@ -1617,7 +1933,8 @@ class section_frame_sequence(MSection):
         section_frame_sequence. A sequence is a trajectory, which can have
         number_of_frames_in_sequence each representing one
         section_single_configuration_calculation section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_temperatures_in_sequence'))
 
     previous_sequence_ref = Quantity(
         type=Reference(SectionProxy('section_frame_sequence')),
@@ -1627,15 +1944,18 @@ class section_frame_sequence(MSection):
         can have number_of_frames_in_sequence each representing one
         section_single_configuration_calculation section. If not given, a start from an
         initial configuration is assumed.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='previous_sequence_ref'))
 
     section_frame_sequence_user_quantity = SubSection(
         sub_section=SectionProxy('section_frame_sequence_user_quantity'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_frame_sequence_user_quantity'))
 
     section_thermodynamical_properties = SubSection(
         sub_section=SectionProxy('section_thermodynamical_properties'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_thermodynamical_properties'))
 
 
 class section_gaussian_basis_group(MSection):
@@ -1655,7 +1975,7 @@ class section_gaussian_basis_group(MSection):
     of basis_set_atom_centered_radial_functions.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_gaussian_basis_group'))
 
     gaussian_basis_group_contractions = Quantity(
         type=np.dtype(np.float64),
@@ -1664,7 +1984,8 @@ class section_gaussian_basis_group(MSection):
         contraction coefficients $c_{i j}$ defining the contracted basis functions with
         respect to *normalized* primitive Gaussian functions. They define the Gaussian
         basis functions as described in section_gaussian_basis_group.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gaussian_basis_group_contractions'))
 
     gaussian_basis_group_exponents = Quantity(
         type=np.dtype(np.float64),
@@ -1673,7 +1994,8 @@ class section_gaussian_basis_group(MSection):
         description='''
         Exponents $\\alpha_j$ of the Gaussian functions defining this basis set
         $exp(-\\alpha_j r^2)$. One should be careful about the units of the coefficients.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gaussian_basis_group_exponents'))
 
     gaussian_basis_group_ls = Quantity(
         type=np.dtype(np.float64),
@@ -1681,7 +2003,8 @@ class section_gaussian_basis_group(MSection):
         description='''
         Azimuthal quantum number ($l$) values (of the angular part given by the spherical
         harmonic $Y_{l m}$ of the various contracted basis functions).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='gaussian_basis_group_ls'))
 
     number_of_gaussian_basis_group_contractions = Quantity(
         type=int,
@@ -1689,7 +2012,8 @@ class section_gaussian_basis_group(MSection):
         description='''
         Gives the number of different contractions, i.e. resulting basis functions in a
         section_gaussian_basis_group section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_gaussian_basis_group_contractions'))
 
     number_of_gaussian_basis_group_exponents = Quantity(
         type=int,
@@ -1697,7 +2021,8 @@ class section_gaussian_basis_group(MSection):
         description='''
         Gives the number of different Gaussian exponents in a section_gaussian_basis_group
         section.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_gaussian_basis_group_exponents'))
 
 
 class section_k_band_normalized(MSection):
@@ -1708,7 +2033,7 @@ class section_k_band_normalized(MSection):
     energy_total evaluations, can be found in the section_eigenvalues section.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_k_band_normalized'))
 
     k_band_path_normalized_is_standard = Quantity(
         type=bool,
@@ -1717,11 +2042,13 @@ class section_k_band_normalized(MSection):
         If the normalized path is along the default path defined in W. Setyawan and S.
         Curtarolo, [Comput. Mater. Sci. **49**, 299-312
         (2010)](http://dx.doi.org/10.1016/j.commatsci.2010.05.010).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='k_band_path_normalized_is_standard'))
 
     section_k_band_segment_normalized = SubSection(
         sub_section=SectionProxy('section_k_band_segment_normalized'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_k_band_segment_normalized'))
 
 
 class section_k_band_segment_normalized(MSection):
@@ -1739,7 +2066,7 @@ class section_k_band_segment_normalized(MSection):
     respectively. The labels for the segment are specified in band_segm_labels.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_k_band_segment_normalized'))
 
     band_energies_normalized = Quantity(
         type=np.dtype(np.float64),
@@ -1750,7 +2077,8 @@ class section_k_band_segment_normalized(MSection):
         with respect to the top of the valence band. This is a third-order tensor, with
         one dimension used for the spin channels, one for the $k$ points for each segment,
         and one for the eigenvalue sequence.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_energies_normalized'))
 
     band_k_points_normalized = Quantity(
         type=np.dtype(np.float64),
@@ -1758,7 +2086,8 @@ class section_k_band_segment_normalized(MSection):
         description='''
         Fractional coordinates of the $k$ points (in the basis of the reciprocal-lattice
         vectors) for which the normalized electronic energies are given.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_k_points_normalized'))
 
     band_occupations_normalized = Quantity(
         type=np.dtype(np.float64),
@@ -1767,7 +2096,8 @@ class section_k_band_segment_normalized(MSection):
         Occupation of the $k$-points along the normalized electronic band. The size of the
         dimensions of this third-order tensor are the same as for the tensor in
         band_energies.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_occupations_normalized'))
 
     band_segm_labels_normalized = Quantity(
         type=str,
@@ -1777,7 +2107,8 @@ class section_k_band_segment_normalized(MSection):
         sampled in the $k$-space, using the conventional symbols, e.g., Gamma, K, L. The
         coordinates (fractional, in the reciprocal space) of the start and end points for
         each segment are given in band_segm_start_end_normalized
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_segm_labels_normalized'))
 
     band_segm_start_end_normalized = Quantity(
         type=np.dtype(np.float64),
@@ -1786,7 +2117,8 @@ class section_k_band_segment_normalized(MSection):
         Fractional coordinates of the start and end point (in the basis of the reciprocal
         lattice vectors) of the segment sampled in the $k$ space. The conventional symbols
         (e.g., Gamma, K, L) of the same points are given in band_segm_labels
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_segm_start_end_normalized'))
 
     number_of_normalized_k_points_per_segment = Quantity(
         type=int,
@@ -1794,7 +2126,8 @@ class section_k_band_segment_normalized(MSection):
         description='''
         Gives the number of $k$ points in the segment of the normalized band structure
         (see section_k_band_segment_normalized).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_normalized_k_points_per_segment'))
 
 
 class section_k_band_segment(MSection):
@@ -1814,7 +2147,7 @@ class section_k_band_segment(MSection):
     specified in band_segm_labels.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_k_band_segment'))
 
     band_energies = Quantity(
         type=np.dtype(np.float64),
@@ -1826,7 +2159,8 @@ class section_k_band_segment(MSection):
         with one dimension used for the spin channels (1 in case of a vibrational band
         structure), one for the $k$ or $q$ points for each segment, and one for the
         eigenvalue sequence.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_energies'))
 
     band_k_points = Quantity(
         type=np.dtype(np.float64),
@@ -1834,7 +2168,8 @@ class section_k_band_segment(MSection):
         description='''
         Fractional coordinates of the $k$ or $q$ points (in the basis of the reciprocal-
         lattice vectors) for which the electronic energy are given.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_k_points'))
 
     band_occupations = Quantity(
         type=np.dtype(np.float64),
@@ -1842,7 +2177,8 @@ class section_k_band_segment(MSection):
         description='''
         Occupation of the $k$-points along the electronic band. The size of the dimensions
         of this third-order tensor are the same as for the tensor in band_energies.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_occupations'))
 
     band_segm_labels = Quantity(
         type=str,
@@ -1852,7 +2188,8 @@ class section_k_band_segment(MSection):
         sampled in the $k$-space or $q$-space, using the conventional symbols, e.g.,
         Gamma, K, L. The coordinates (fractional, in the reciprocal space) of the start
         and end points for each segment are given in band_segm_start_end
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_segm_labels'))
 
     band_segm_start_end = Quantity(
         type=np.dtype(np.float64),
@@ -1861,7 +2198,8 @@ class section_k_band_segment(MSection):
         Fractional coordinates of the start and end point (in the basis of the reciprocal
         lattice vectors) of the segment sampled in the $k$ space. The conventional symbols
         (e.g., Gamma, K, L) of the same points are given in band_segm_labels
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_segm_start_end'))
 
     number_of_k_points_per_segment = Quantity(
         type=int,
@@ -1869,7 +2207,8 @@ class section_k_band_segment(MSection):
         description='''
         Gives the number of $k$ points in the segment of the band structure, see
         section_k_band_segment.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_k_points_per_segment'))
 
 
 class section_k_band(MSection):
@@ -1880,18 +2219,20 @@ class section_k_band(MSection):
     used for energy_total evaluations, can be found in the section_eigenvalues section.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_k_band'))
 
     band_structure_kind = Quantity(
         type=str,
         shape=[],
         description='''
         String to specify the kind of band structure (either electronic or vibrational).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='band_structure_kind'))
 
     section_k_band_segment = SubSection(
         sub_section=SectionProxy('section_k_band_segment'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_k_band_segment'))
 
 
 class section_method_atom_kind(MSection):
@@ -1908,21 +2249,23 @@ class section_method_atom_kind(MSection):
     sections.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_method_atom_kind'))
 
     method_atom_kind_atom_number = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         Atomic number (number of protons) of this atom kind, use 0 if not an atom.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_atom_kind_atom_number'))
 
     method_atom_kind_explicit_electrons = Quantity(
         type=np.dtype(np.float64),
         shape=[],
         description='''
         Number of explicit electrons (often called valence).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_atom_kind_explicit_electrons'))
 
     method_atom_kind_label = Quantity(
         type=str,
@@ -1934,22 +2277,25 @@ class section_method_atom_kind(MSection):
         differently defined sets of atom-centered basis functions or two different pseudo-
         potentials). Atom kind is typically the symbol of the atomic species but it can be
         also a ghost or pseudo-atom.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_atom_kind_label'))
 
     method_atom_kind_mass = Quantity(
         type=np.dtype(np.float64),
         shape=[],
-        unit='atomic_mass_unit',
+        unit='unified_atomic_mass_unit',
         description='''
         Mass of the kind of this kind of atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_atom_kind_mass'))
 
     method_atom_kind_pseudopotential_name = Quantity(
         type=str,
         shape=[],
         description='''
         Name identifying the pseudopotential used.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_atom_kind_pseudopotential_name'))
 
 
 class section_method_to_method_refs(MSection):
@@ -1967,7 +2313,7 @@ class section_method_to_method_refs(MSection):
     the same section_run) or method_to_method_external_url.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_method_to_method_refs'))
 
     method_to_method_external_url = Quantity(
         type=str,
@@ -1976,7 +2322,8 @@ class section_method_to_method_refs(MSection):
         URL used to reference an externally stored section_method. The kind of
         relationship between the present and the referenced section_method is specified by
         method_to_method_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_to_method_external_url'))
 
     method_to_method_kind = Quantity(
         type=str,
@@ -1993,7 +2340,8 @@ class section_method_to_method_refs(MSection):
         Hence, the need of keeping track of these connected calculations. The referenced
         section_method is identified via method_to_method_ref (typically used for a
         section_method in the same section_run) or method_to_method_external_url.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_to_method_kind'))
 
     method_to_method_ref = Quantity(
         type=Reference(SectionProxy('section_method')),
@@ -2004,7 +2352,8 @@ class section_method_to_method_refs(MSection):
         of the value contained in method_to_method_external_url. The kind of relationship
         between the method defined in the present section_method and the referenced one is
         described by method_to_method_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='method_to_method_ref'))
 
 
 class section_method(MSection):
@@ -2017,7 +2366,7 @@ class section_method(MSection):
     optimization etc. See section frame_sequence for these other settings instead.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_method'))
 
     basis_set = Quantity(
         type=str,
@@ -2027,7 +2376,8 @@ class section_method(MSection):
         calculated with XC_method. It might identify a class of basis sets, often matches
         one of the strings given in any of basis_set_name.
         ''',
-        categories=[settings_potential_energy_surface, settings_numerical_parameter])
+        categories=[settings_numerical_parameter, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='basis_set'))
 
     calculation_method_current = Quantity(
         type=str,
@@ -2040,7 +2390,8 @@ class section_method(MSection):
         concatenating XC_method_current and basis_set. See [calculation_method_current
         wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/calculation-method-current) for the details.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_method_current'))
 
     calculation_method_kind = Quantity(
         type=str,
@@ -2053,7 +2404,8 @@ class section_method(MSection):
         - absolute
 
         - perturbative.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_method_kind'))
 
     calculation_method = Quantity(
         type=str,
@@ -2066,7 +2418,8 @@ class section_method(MSection):
         activate this, method_to_method_kind must have the value starting_point (see the
         [method_to_method_kind wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-
         meta-info/wikis/metainfo/method-to-method-kind)).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_method'))
 
     electronic_structure_method = Quantity(
         type=str,
@@ -2079,7 +2432,8 @@ class section_method(MSection):
         wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/electronic-structure-method).
         ''',
-        categories=[settings_potential_energy_surface, settings_XC])
+        categories=[settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='electronic_structure_method'))
 
     k_mesh_points = Quantity(
         type=np.dtype(np.float64),
@@ -2089,7 +2443,8 @@ class section_method(MSection):
         evaluate energy_total, and are in fractional coordinates (in the basis of the
         reciprocal-lattice vectors).
         ''',
-        categories=[settings_k_points, settings_potential_energy_surface])
+        categories=[settings_k_points, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='k_mesh_points'))
 
     k_mesh_weights = Quantity(
         type=np.dtype(np.float64),
@@ -2098,7 +2453,8 @@ class section_method(MSection):
         Weights of all the k points in the $k$-point mesh. These are the weights for
         k_mesh_points (i.e. the k point used to evaluate energy_total).
         ''',
-        categories=[settings_k_points, settings_potential_energy_surface])
+        categories=[settings_k_points, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='k_mesh_weights'))
 
     number_of_k_mesh_points = Quantity(
         type=int,
@@ -2106,14 +2462,16 @@ class section_method(MSection):
         description='''
         number of k points in the mesh (i.e. the k points used to evaluate energy_total).
         ''',
-        categories=[settings_k_points, settings_potential_energy_surface])
+        categories=[settings_k_points, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='number_of_k_mesh_points'))
 
     number_of_spin_channels = Quantity(
         type=int,
         shape=[],
         description='''
         Gives the number of spin channels, see section_method.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_spin_channels'))
 
     relativity_method = Quantity(
         type=str,
@@ -2122,7 +2480,8 @@ class section_method(MSection):
         Describes the relativistic treatment used for the calculation of the final energy
         and related quantities. If skipped or empty, no relativistic treatment is applied.
         ''',
-        categories=[settings_potential_energy_surface, settings_XC, settings_relativity])
+        categories=[settings_relativity, settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='relativity_method'))
 
     scf_max_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -2131,7 +2490,8 @@ class section_method(MSection):
         Specifies the maximum number of allowed self-consistent field (SCF) iterations in
         a calculation run, see section_run.
         ''',
-        categories=[settings_scf])
+        categories=[settings_scf],
+        a_legacy=LegacyDefinition(name='scf_max_iteration'))
 
     scf_threshold_energy_change = Quantity(
         type=np.dtype(np.float64),
@@ -2143,7 +2503,8 @@ class section_method(MSection):
         when the total-energy change between two SCF cycles is below the threshold
         (possibly in combination with other criteria).
         ''',
-        categories=[settings_scf])
+        categories=[settings_scf],
+        a_legacy=LegacyDefinition(name='scf_threshold_energy_change'))
 
     self_interaction_correction_method = Quantity(
         type=str,
@@ -2174,7 +2535,8 @@ class section_method(MSection):
         | `"SIC_MAURI_US"`          | A (scaled) correction proposed by Mauri and co-
         workers on the spin density / doublet unpaired orbital |
         ''',
-        categories=[settings_potential_energy_surface, settings_XC, settings_self_interaction_correction])
+        categories=[settings_self_interaction_correction, settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='self_interaction_correction_method'))
 
     smearing_kind = Quantity(
         type=str,
@@ -2202,7 +2564,8 @@ class section_method(MSection):
         | `"tetrahedra"`            | Interpolation of state energies and occupations
         (ignores smearing_width) |
         ''',
-        categories=[settings_smearing])
+        categories=[settings_smearing],
+        a_legacy=LegacyDefinition(name='smearing_kind'))
 
     smearing_width = Quantity(
         type=np.dtype(np.float64),
@@ -2213,7 +2576,8 @@ class section_method(MSection):
 
         *NOTE:* Not all methods specified in smearing_kind uses this value.
         ''',
-        categories=[settings_smearing])
+        categories=[settings_smearing],
+        a_legacy=LegacyDefinition(name='smearing_width'))
 
     spin_target_multiplicity = Quantity(
         type=np.dtype(np.int32),
@@ -2223,7 +2587,8 @@ class section_method(MSection):
         $S$ is the total spin. It is an integer number. This value is not necessarily the
         value obtained at the end of the calculation. See spin_S2 for the converged value
         of the spin moment.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='spin_target_multiplicity'))
 
     stress_tensor_method = Quantity(
         type=str,
@@ -2238,7 +2603,8 @@ class section_method(MSection):
 
         * analytic
         ''',
-        categories=[settings_stress_tensor])
+        categories=[settings_stress_tensor],
+        a_legacy=LegacyDefinition(name='stress_tensor_method'))
 
     total_charge = Quantity(
         type=np.dtype(np.int32),
@@ -2246,7 +2612,8 @@ class section_method(MSection):
         unit='coulomb',
         description='''
         Provides the total amount of charge of the system in a run.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='total_charge'))
 
     van_der_Waals_method = Quantity(
         type=str,
@@ -2285,7 +2652,8 @@ class section_method(MSection):
         | `"XC"`                | The method to calculate the Van der Waals energy uses a
         non-local functional which is described in section_XC_functionals. |
         ''',
-        categories=[settings_van_der_Waals, settings_potential_energy_surface, settings_XC])
+        categories=[settings_van_der_Waals, settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='van_der_Waals_method'))
 
     XC_functional = Quantity(
         type=str,
@@ -2301,7 +2669,8 @@ class section_method(MSection):
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/XC-
         functional).
         ''',
-        categories=[settings_physical_parameter, settings_XC_functional, settings_potential_energy_surface, settings_XC])
+        categories=[settings_potential_energy_surface, settings_physical_parameter, settings_XC_functional, settings_XC],
+        a_legacy=LegacyDefinition(name='XC_functional'))
 
     XC_method = Quantity(
         type=str,
@@ -2317,7 +2686,8 @@ class section_method(MSection):
         the XC method (XC_method) defined in section_method that is referred to by
         method_to_method_ref where method_to_method_kind = "starting_point_method".
         ''',
-        categories=[settings_potential_energy_surface, settings_XC])
+        categories=[settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='XC_method'))
 
     XC_method_current = Quantity(
         type=str,
@@ -2343,19 +2713,23 @@ class section_method(MSection):
         calculation). In this case, the string that contains both the perturbative and
         starting point method is stored in XC_method.
         ''',
-        categories=[settings_potential_energy_surface, settings_XC])
+        categories=[settings_XC, settings_potential_energy_surface],
+        a_legacy=LegacyDefinition(name='XC_method_current'))
 
     section_method_atom_kind = SubSection(
         sub_section=SectionProxy('section_method_atom_kind'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_method_atom_kind'))
 
     section_method_to_method_refs = SubSection(
         sub_section=SectionProxy('section_method_to_method_refs'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_method_to_method_refs'))
 
     section_XC_functionals = SubSection(
         sub_section=SectionProxy('section_XC_functionals'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_XC_functionals'))
 
 
 class section_original_system(MSection):
@@ -2363,7 +2737,7 @@ class section_original_system(MSection):
     Section containing symmetry information that is specific to the original system.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_original_system'))
 
     equivalent_atoms_original = Quantity(
         type=np.dtype(np.int32),
@@ -2371,14 +2745,16 @@ class section_original_system(MSection):
         description='''
         Gives a mapping table of atoms to symmetrically independent atoms in the original
         cell. This is used to find symmetrically equivalent atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='equivalent_atoms_original'))
 
     wyckoff_letters_original = Quantity(
         type=str,
         shape=['number_of_atoms'],
         description='''
         Wyckoff letters for atoms in the original cell.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='wyckoff_letters_original'))
 
 
 class section_primitive_system(MSection):
@@ -2389,21 +2765,23 @@ class section_primitive_system(MSection):
     https://atztogo.github.io/spglib/definition.html#transformation-to-the-primitive-cell
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_primitive_system'))
 
     atom_positions_primitive = Quantity(
         type=np.dtype(np.float64),
         shape=['number_of_atoms_primitive', 3],
         description='''
         Atom positions in the primitive cell in reduced units.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_positions_primitive'))
 
     atomic_numbers_primitive = Quantity(
         type=np.dtype(np.int32),
         shape=['number_of_atoms_primitive'],
         description='''
         Atomic numbers in the primitive cell.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atomic_numbers_primitive'))
 
     equivalent_atoms_primitive = Quantity(
         type=np.dtype(np.int32),
@@ -2411,7 +2789,8 @@ class section_primitive_system(MSection):
         description='''
         Gives a mapping table of atoms to symmetrically independent atoms in the primitive
         cell. This is used to find symmetrically equivalent atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='equivalent_atoms_primitive'))
 
     lattice_vectors_primitive = Quantity(
         type=np.dtype(np.float64),
@@ -2419,21 +2798,24 @@ class section_primitive_system(MSection):
         unit='meter',
         description='''
         Primitive lattice vectors. The vectors are the rows of this matrix.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='lattice_vectors_primitive'))
 
     number_of_atoms_primitive = Quantity(
         type=int,
         shape=[],
         description='''
         Number of atoms in primitive system.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atoms_primitive'))
 
     wyckoff_letters_primitive = Quantity(
         type=str,
         shape=['number_of_atoms_primitive'],
         description='''
         Wyckoff letters for atoms in the primitive cell.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='wyckoff_letters_primitive'))
 
 
 class section_processor_info(MSection):
@@ -2442,7 +2824,7 @@ class section_processor_info(MSection):
     current calculation.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_processor_info'))
 
     processor_id = Quantity(
         type=str,
@@ -2450,7 +2832,8 @@ class section_processor_info(MSection):
         description='''
         Id (name+version) of the processor that generated or added information to the
         current calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_id'))
 
     processor_number_of_evaluated_contexts = Quantity(
         type=np.dtype(np.int64),
@@ -2458,7 +2841,8 @@ class section_processor_info(MSection):
         description='''
         number of contexts evaluated with this processor in the current current
         calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_number_of_evaluated_contexts'))
 
     processor_number_of_failed_contexts = Quantity(
         type=np.dtype(np.int64),
@@ -2466,14 +2850,16 @@ class section_processor_info(MSection):
         description='''
         number of contexts in the current current calculation that had failure for this
         processor.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_number_of_failed_contexts'))
 
     processor_number_of_skipped_contexts = Quantity(
         type=np.dtype(np.int64),
         shape=[],
         description='''
         number of contexts skipped by this processor in the current current calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_number_of_skipped_contexts'))
 
     processor_number_of_successful_contexts = Quantity(
         type=np.dtype(np.int64),
@@ -2481,7 +2867,8 @@ class section_processor_info(MSection):
         description='''
         number of contexts in the current calculation that where successfully handled by
         this processor.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_number_of_successful_contexts'))
 
     processor_version_details = Quantity(
         type=typing.Any,
@@ -2489,7 +2876,8 @@ class section_processor_info(MSection):
         description='''
         detailed version information on the processor that generated or added information
         to the current calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_version_details'))
 
 
 class section_processor_log_event(MSection):
@@ -2497,7 +2885,7 @@ class section_processor_log_event(MSection):
     A log event
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_processor_log_event'))
 
     processor_log_event_level = Quantity(
         type=np.dtype(np.int32),
@@ -2506,14 +2894,16 @@ class section_processor_log_event(MSection):
         Level of the logging, a lower number has more priority. The levels are the same as
         log4j: FATAL -> 100, ERROR -> 200, WARN -> 300, INFO -> 400, DEBUG -> 500, TRACE
         -> 600
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_log_event_level'))
 
     processor_log_event_message = Quantity(
         type=str,
         shape=[],
         description='''
         The log message
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_log_event_message'))
 
 
 class section_processor_log(MSection):
@@ -2521,25 +2911,28 @@ class section_processor_log(MSection):
     log of a processor
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_processor_log'))
 
     processor_log_processor_id = Quantity(
         type=str,
         shape=[],
         description='''
         The processor id of the processor creating this log
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_log_processor_id'))
 
     processor_log_start = Quantity(
         type=str,
         shape=[],
         description='''
         Start of the log (in ansi notation YYYY-MM-TT...)
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='processor_log_start'))
 
     section_processor_log_event = SubSection(
         sub_section=SectionProxy('section_processor_log_event'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_processor_log_event'))
 
 
 class section_prototype(MSection):
@@ -2547,7 +2940,7 @@ class section_prototype(MSection):
     Information on the prototype corresponding to the current section.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_prototype'))
 
     prototype_aflow_id = Quantity(
         type=str,
@@ -2556,7 +2949,8 @@ class section_prototype(MSection):
         AFLOW id of the prototype (see
         http://aflowlib.org/CrystalDatabase/prototype_index.html) identified on the basis
         of the space_group and normalized_wyckoff.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='prototype_aflow_id'))
 
     prototype_aflow_url = Quantity(
         type=str,
@@ -2565,14 +2959,16 @@ class section_prototype(MSection):
         Url to the AFLOW definition of the prototype (see
         http://aflowlib.org/CrystalDatabase/prototype_index.html) identified on the basis
         of the space_group and normalized_wyckoff.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='prototype_aflow_url'))
 
     prototype_assignment_method = Quantity(
         type=str,
         shape=[],
         description='''
         Method used to identify the prototype.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='prototype_assignment_method'))
 
     prototype_label = Quantity(
         type=str,
@@ -2581,7 +2977,8 @@ class section_prototype(MSection):
         Label of the prototype identified on the basis of the space_group and
         normalized_wyckoff. The label is in the same format as in the read_prototypes
         function: <space_group_number>-<prototype_name>-<Pearson's symbol>).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='prototype_label'))
 
 
 class section_run(MSection):
@@ -2592,7 +2989,7 @@ class section_run(MSection):
     ](program_info)).
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_run'))
 
     calculation_file_uri = Quantity(
         type=str,
@@ -2600,7 +2997,8 @@ class section_run(MSection):
         description='''
         Contains the nomad uri of a raw the data file connected to the current run. There
         should be an value for the main_file_uri and all ancillary files.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='calculation_file_uri'))
 
     message_debug_run = Quantity(
         type=str,
@@ -2608,7 +3006,8 @@ class section_run(MSection):
         description='''
         A debugging message of the computational program, associated with a run.
         ''',
-        categories=[message_debug])
+        categories=[message_debug],
+        a_legacy=LegacyDefinition(name='message_debug_run'))
 
     message_error_run = Quantity(
         type=str,
@@ -2616,7 +3015,8 @@ class section_run(MSection):
         description='''
         An error message of the computational program, associated with a run.
         ''',
-        categories=[message_info, message_debug, message_warning, message_error])
+        categories=[message_info, message_debug, message_error, message_warning],
+        a_legacy=LegacyDefinition(name='message_error_run'))
 
     message_info_run = Quantity(
         type=str,
@@ -2624,7 +3024,8 @@ class section_run(MSection):
         description='''
         An information message of the computational program, associated with a run.
         ''',
-        categories=[message_info, message_debug])
+        categories=[message_info, message_debug],
+        a_legacy=LegacyDefinition(name='message_info_run'))
 
     message_warning_run = Quantity(
         type=str,
@@ -2632,7 +3033,8 @@ class section_run(MSection):
         description='''
         A warning message of the computational program, associated with a run.
         ''',
-        categories=[message_info, message_debug, message_warning])
+        categories=[message_info, message_debug, message_warning],
+        a_legacy=LegacyDefinition(name='message_warning_run'))
 
     parsing_message_debug_run = Quantity(
         type=str,
@@ -2641,7 +3043,8 @@ class section_run(MSection):
         This field is used for debugging messages of the parsing program associated with a
         single configuration calculation, see section_single_configuration_calculation.
         ''',
-        categories=[parsing_message_debug])
+        categories=[parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_debug_run'))
 
     parsing_message_error_run = Quantity(
         type=str,
@@ -2650,7 +3053,8 @@ class section_run(MSection):
         This field is used for error messages of the parsing program associated with a
         run, see section_run.
         ''',
-        categories=[parsing_message_info, parsing_message_error, parsing_message_warning, parsing_message_debug])
+        categories=[parsing_message_info, parsing_message_error, parsing_message_warning, parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_error_run'))
 
     parsing_message_info_run = Quantity(
         type=str,
@@ -2659,7 +3063,8 @@ class section_run(MSection):
         This field is used for info messages of the parsing program associated with a run,
         see section_run.
         ''',
-        categories=[parsing_message_info, parsing_message_debug])
+        categories=[parsing_message_info, parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_info_run'))
 
     parsing_message_warning_run = Quantity(
         type=str,
@@ -2668,7 +3073,8 @@ class section_run(MSection):
         This field is used for warning messages of the parsing program associated with a
         run, see section_run.
         ''',
-        categories=[parsing_message_info, parsing_message_warning, parsing_message_debug])
+        categories=[parsing_message_info, parsing_message_warning, parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_warning_run'))
 
     program_basis_set_type = Quantity(
         type=str,
@@ -2691,7 +3097,8 @@ class section_run(MSection):
         * Real-space grid
 
         * Local-orbital minimum-basis
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='program_basis_set_type'))
 
     program_compilation_datetime = Quantity(
         type=np.dtype(np.float64),
@@ -2702,7 +3109,8 @@ class section_run(MSection):
         1 January 1970) in seconds. For date and times without a timezone, the default
         timezone GMT is used.
         ''',
-        categories=[accessory_info, program_info])
+        categories=[accessory_info, program_info],
+        a_legacy=LegacyDefinition(name='program_compilation_datetime'))
 
     program_compilation_host = Quantity(
         type=str,
@@ -2710,7 +3118,8 @@ class section_run(MSection):
         description='''
         Specifies the host on which the program was compiled.
         ''',
-        categories=[accessory_info, program_info])
+        categories=[accessory_info, program_info],
+        a_legacy=LegacyDefinition(name='program_compilation_host'))
 
     program_name = Quantity(
         type=str,
@@ -2718,7 +3127,8 @@ class section_run(MSection):
         description='''
         Specifies the name of the program that generated the data.
         ''',
-        categories=[accessory_info, program_info])
+        categories=[accessory_info, program_info],
+        a_legacy=LegacyDefinition(name='program_name'))
 
     program_version = Quantity(
         type=str,
@@ -2728,7 +3138,8 @@ class section_run(MSection):
         number of an official release, the version tag or a commit id as well as the
         location of the repository.
         ''',
-        categories=[accessory_info, program_info])
+        categories=[accessory_info, program_info],
+        a_legacy=LegacyDefinition(name='program_version'))
 
     run_clean_end = Quantity(
         type=bool,
@@ -2736,7 +3147,8 @@ class section_run(MSection):
         description='''
         Indicates whether this run terminated properly (true), or if it was killed or
         exited with an error code unequal to zero (false).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='run_clean_end'))
 
     run_hosts = Quantity(
         type=typing.Any,
@@ -2746,14 +3158,16 @@ class section_run(MSection):
         associative list that contains program-dependent information (*key*) on how the
         host was used (*value*). Useful for debugging purposes.
         ''',
-        categories=[accessory_info, parallelization_info])
+        categories=[parallelization_info, accessory_info],
+        a_legacy=LegacyDefinition(name='run_hosts'))
 
     raw_id = Quantity(
         type=str,
         shape=[],
         description='''
         An optional calculation id, if one is found in the code input/output files.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='raw_id'))
 
     time_run_cpu1_end = Quantity(
         type=np.dtype(np.float64),
@@ -2762,7 +3176,8 @@ class section_run(MSection):
         description='''
         Stores the end time of the run on CPU 1.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_run_cpu1_end'))
 
     time_run_cpu1_start = Quantity(
         type=np.dtype(np.float64),
@@ -2771,7 +3186,8 @@ class section_run(MSection):
         description='''
         Stores the start time of the run on CPU 1.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_run_cpu1_start'))
 
     time_run_date_end = Quantity(
         type=np.dtype(np.float64),
@@ -2782,7 +3198,8 @@ class section_run(MSection):
         January 1970) in seconds. For date and times without a timezone, the default
         timezone GMT is used.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_run_date_end'))
 
     time_run_date_start = Quantity(
         type=np.dtype(np.float64),
@@ -2793,7 +3210,8 @@ class section_run(MSection):
         January 1970) in seconds. For date and times without a timezone, the default
         timezone GMT is used.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_run_date_start'))
 
     time_run_wall_end = Quantity(
         type=np.dtype(np.float64),
@@ -2802,7 +3220,8 @@ class section_run(MSection):
         description='''
         Stores the internal wall-clock time at the end of the run.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_run_wall_end'))
 
     time_run_wall_start = Quantity(
         type=np.dtype(np.float64),
@@ -2811,35 +3230,43 @@ class section_run(MSection):
         description='''
         Stores the internal wall-clock time from the start of the run.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_run_wall_start'))
 
     section_basis_set_atom_centered = SubSection(
         sub_section=SectionProxy('section_basis_set_atom_centered'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_basis_set_atom_centered'))
 
     section_basis_set_cell_dependent = SubSection(
         sub_section=SectionProxy('section_basis_set_cell_dependent'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_basis_set_cell_dependent'))
 
     section_frame_sequence = SubSection(
         sub_section=SectionProxy('section_frame_sequence'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_frame_sequence'))
 
     section_method = SubSection(
         sub_section=SectionProxy('section_method'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_method'))
 
     section_sampling_method = SubSection(
         sub_section=SectionProxy('section_sampling_method'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_sampling_method'))
 
     section_single_configuration_calculation = SubSection(
         sub_section=SectionProxy('section_single_configuration_calculation'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_single_configuration_calculation'))
 
     section_system = SubSection(
         sub_section=SectionProxy('section_system'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_system'))
 
 
 class section_sampling_method(MSection):
@@ -2851,7 +3278,7 @@ class section_sampling_method(MSection):
     frames, section_frame_sequence.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_sampling_method'))
 
     ensemble_type = Quantity(
         type=str,
@@ -2860,7 +3287,8 @@ class section_sampling_method(MSection):
         Kind of sampled ensemble stored in section_frame_sequence; valid values are
         defined in [ensemble_type wiki page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-
         meta-info/wikis/metainfo/ensemble-type).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='ensemble_type'))
 
     geometry_optimization_energy_change = Quantity(
         type=np.dtype(np.float64),
@@ -2873,7 +3301,8 @@ class section_sampling_method(MSection):
         geometry optimization steps is below the threshold (possibly in combination with
         other criteria)
         ''',
-        categories=[settings_sampling, settings_geometry_optimization])
+        categories=[settings_geometry_optimization, settings_sampling],
+        a_legacy=LegacyDefinition(name='geometry_optimization_energy_change'))
 
     geometry_optimization_geometry_change = Quantity(
         type=np.dtype(np.float64),
@@ -2886,7 +3315,8 @@ class section_sampling_method(MSection):
         displacements of the nuclei between two geometry optimization steps is below the
         threshold (possibly in combination with other criteria)
         ''',
-        categories=[settings_sampling, settings_geometry_optimization])
+        categories=[settings_geometry_optimization, settings_sampling],
+        a_legacy=LegacyDefinition(name='geometry_optimization_geometry_change'))
 
     geometry_optimization_method = Quantity(
         type=str,
@@ -2896,7 +3326,8 @@ class section_sampling_method(MSection):
         [geometry_optimization_method wiki page](https://gitlab.mpcdf.mpg.de/nomad-
         lab/nomad-meta-info/wikis/metainfo/geometry-optimization-method).
         ''',
-        categories=[settings_sampling, settings_geometry_optimization])
+        categories=[settings_geometry_optimization, settings_sampling],
+        a_legacy=LegacyDefinition(name='geometry_optimization_method'))
 
     geometry_optimization_threshold_force = Quantity(
         type=np.dtype(np.float64),
@@ -2908,7 +3339,8 @@ class section_sampling_method(MSection):
         the maximum of the moduli of the force on each of the atoms is below this
         threshold (possibly in combination with other criteria)
         ''',
-        categories=[settings_sampling, settings_geometry_optimization])
+        categories=[settings_geometry_optimization, settings_sampling],
+        a_legacy=LegacyDefinition(name='geometry_optimization_threshold_force'))
 
     sampling_method_expansion_order = Quantity(
         type=np.dtype(np.int32),
@@ -2916,7 +3348,8 @@ class section_sampling_method(MSection):
         description='''
         Order up to which the potential energy surface was expanded in a Taylor series
         (see sampling_method).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='sampling_method_expansion_order'))
 
     sampling_method = Quantity(
         type=str,
@@ -2951,7 +3384,8 @@ class section_sampling_method(MSection):
 
         | `"taylor_expansion"`           | Taylor expansion of the potential energy
         surface |
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='sampling_method'))
 
 
 class section_scf_iteration(MSection):
@@ -2961,7 +3395,7 @@ class section_scf_iteration(MSection):
     quantities.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_scf_iteration'))
 
     electronic_kinetic_energy_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -2971,7 +3405,8 @@ class section_scf_iteration(MSection):
         Electronic kinetic energy as defined in XC_method during the self-consistent field
         (SCF) iterations.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='electronic_kinetic_energy_scf_iteration'))
 
     energy_change_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -2981,7 +3416,8 @@ class section_scf_iteration(MSection):
         Stores the change of total energy with respect to the previous self-consistent
         field (SCF) iteration.
         ''',
-        categories=[energy_value, error_estimate_contribution])
+        categories=[error_estimate_contribution, energy_value],
+        a_legacy=LegacyDefinition(name='energy_change_scf_iteration'))
 
     energy_correction_entropy_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -2993,7 +3429,8 @@ class section_scf_iteration(MSection):
         in account. The array lists the values of the entropy correction for each self-
         consistent field (SCF) iteration. Defined consistently with XC_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_correction_entropy_scf_iteration'))
 
     energy_correction_hartree_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3005,7 +3442,8 @@ class section_scf_iteration(MSection):
         density electrostatic energy during the self-consistent field (SCF) iterations.
         Defined consistently with XC_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_correction_hartree_scf_iteration'))
 
     energy_electrostatic_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3015,7 +3453,8 @@ class section_scf_iteration(MSection):
         Total electrostatic energy (nuclei + electrons) during each self-consistent field
         (SCF) iteration.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_electrostatic_scf_iteration'))
 
     energy_free_per_atom_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3026,7 +3465,8 @@ class section_scf_iteration(MSection):
         calculated with smearing_kind) calculated with XC_method during the self-
         consistent field (SCF) iterations.
         ''',
-        categories=[energy_value, energy_component_per_atom])
+        categories=[energy_component_per_atom, energy_value],
+        a_legacy=LegacyDefinition(name='energy_free_per_atom_scf_iteration'))
 
     energy_free_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3037,7 +3477,8 @@ class section_scf_iteration(MSection):
         smearing_kind) calculated with the method described in XC_method during the self-
         consistent field (SCF) iterations.
         ''',
-        categories=[energy_component, energy_value, energy_total_potential])
+        categories=[energy_component, energy_value, energy_total_potential],
+        a_legacy=LegacyDefinition(name='energy_free_scf_iteration'))
 
     energy_hartree_error_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3047,7 +3488,8 @@ class section_scf_iteration(MSection):
         Error in the Hartree (electrostatic) potential energy during each self-consistent
         field (SCF) iteration. Defined consistently with XC_method.
         ''',
-        categories=[energy_value, error_estimate_contribution])
+        categories=[error_estimate_contribution, energy_value],
+        a_legacy=LegacyDefinition(name='energy_hartree_error_scf_iteration'))
 
     energy_sum_eigenvalues_per_atom_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3058,7 +3500,8 @@ class section_scf_iteration(MSection):
         eigenvalues of the Hamiltonian matrix given by XC_method, during each self-
         consistent field (SCF) iteration.
         ''',
-        categories=[energy_value, energy_component_per_atom])
+        categories=[energy_component_per_atom, energy_value],
+        a_legacy=LegacyDefinition(name='energy_sum_eigenvalues_per_atom_scf_iteration'))
 
     energy_sum_eigenvalues_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3068,7 +3511,8 @@ class section_scf_iteration(MSection):
         Sum of the eigenvalues of the Hamiltonian matrix defined by XC_method, during each
         self-consistent field (SCF) iteration.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_sum_eigenvalues_scf_iteration'))
 
     energy_total_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3078,7 +3522,8 @@ class section_scf_iteration(MSection):
         Value of the total electronic energy calculated with the method described in
         XC_method during each self-consistent field (SCF) iteration.
         ''',
-        categories=[energy_component, energy_value, energy_total_potential])
+        categories=[energy_component, energy_value, energy_total_potential],
+        a_legacy=LegacyDefinition(name='energy_total_scf_iteration'))
 
     energy_total_T0_per_atom_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3089,7 +3534,8 @@ class section_scf_iteration(MSection):
         atom extrapolated to $T=0$, based on a free-electron gas argument, during each
         self-consistent field (SCF) iteration.
         ''',
-        categories=[energy_total_potential_per_atom, energy_value, energy_component])
+        categories=[energy_total_potential_per_atom, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_total_T0_per_atom_scf_iteration'))
 
     energy_total_T0_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3100,7 +3546,8 @@ class section_scf_iteration(MSection):
         method described in XC_method and extrapolated to $T=0$, based on a free-electron
         gas argument, during each self-consistent field (SCF) iteration.
         ''',
-        categories=[energy_component, energy_value, energy_total_potential])
+        categories=[energy_component, energy_value, energy_total_potential],
+        a_legacy=LegacyDefinition(name='energy_total_T0_scf_iteration'))
 
     energy_XC_potential_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3113,7 +3560,8 @@ class section_scf_iteration(MSection):
         eigenvalues. Values are given for each self-consistent field (SCF) iteration
         (i.e., not the converged value, the latter being stored in energy_XC_potential).
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_XC_potential_scf_iteration'))
 
     energy_XC_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3123,7 +3571,8 @@ class section_scf_iteration(MSection):
         Value for exchange-correlation (XC) energy obtained during each self-consistent
         field (SCF) iteration, using the method described in XC_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_XC_scf_iteration'))
 
     spin_S2_scf_iteration = Quantity(
         type=np.dtype(np.float64),
@@ -3132,7 +3581,8 @@ class section_scf_iteration(MSection):
         Stores the value of the total spin moment operator $S^2$ during the self-
         consistent field (SCF) iterations of the XC_method. It can be used to calculate
         the spin contamination in spin-unrestricted calculations.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='spin_S2_scf_iteration'))
 
     time_scf_iteration_cpu1_end = Quantity(
         type=np.dtype(np.float64),
@@ -3141,7 +3591,8 @@ class section_scf_iteration(MSection):
         description='''
         Stores the end time of a self-consistent field (SCF) iteration on CPU 1.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_scf_iteration_cpu1_end'))
 
     time_scf_iteration_cpu1_start = Quantity(
         type=np.dtype(np.float64),
@@ -3150,7 +3601,8 @@ class section_scf_iteration(MSection):
         description='''
         Stores the start time of a self-consistent field (SCF) iteration on CPU 1.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_scf_iteration_cpu1_start'))
 
     time_scf_iteration_date_end = Quantity(
         type=np.dtype(np.float64),
@@ -3161,7 +3613,8 @@ class section_scf_iteration(MSection):
         *Unix epoch* (00:00:00 UTC on 1 January 1970) in seconds. For date and times
         without a timezone, the default timezone GMT is used.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_scf_iteration_date_end'))
 
     time_scf_iteration_date_start = Quantity(
         type=np.dtype(np.float64),
@@ -3172,7 +3625,8 @@ class section_scf_iteration(MSection):
         *Unix epoch* (00:00:00 UTC on 1 January 1970) in seconds. For date and times
         without a timezone, the default timezone GMT is used.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_scf_iteration_date_start'))
 
     time_scf_iteration_wall_end = Quantity(
         type=np.dtype(np.float64),
@@ -3182,7 +3636,8 @@ class section_scf_iteration(MSection):
         Stores the internal wall-clock time at the end of a self-consistent field (SCF)
         iteration.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_scf_iteration_wall_end'))
 
     time_scf_iteration_wall_start = Quantity(
         type=np.dtype(np.float64),
@@ -3192,7 +3647,8 @@ class section_scf_iteration(MSection):
         Stores the internal wall-clock time from the start of a self-consistent field
         (SCF) iteration.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_scf_iteration_wall_start'))
 
 
 class section_single_configuration_calculation(MSection):
@@ -3213,7 +3669,7 @@ class section_single_configuration_calculation(MSection):
     with the same computational method. This storage strategy avoids redundancies.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_single_configuration_calculation'))
 
     atom_forces_free_raw = Quantity(
         type=np.dtype(np.float64),
@@ -3231,7 +3687,8 @@ class section_single_configuration_calculation(MSection):
         such as fixed atoms, distances, angles, dihedrals, etc. are also considered
         separately (see atom_forces_free for the filtered counterpart).
         ''',
-        categories=[atom_forces_type])
+        categories=[atom_forces_type],
+        a_legacy=LegacyDefinition(name='atom_forces_free_raw'))
 
     atom_forces_free = Quantity(
         type=np.dtype(np.float64),
@@ -3250,7 +3707,8 @@ class section_single_configuration_calculation(MSection):
         such as fixed atoms, distances, angles, dihedrals, etc. are included (see
         atom_forces_free_raw for the unfiltered counterpart).
         ''',
-        categories=[atom_forces_type])
+        categories=[atom_forces_type],
+        a_legacy=LegacyDefinition(name='atom_forces_free'))
 
     atom_forces_raw = Quantity(
         type=np.dtype(np.float64),
@@ -3266,7 +3724,8 @@ class section_single_configuration_calculation(MSection):
         dihedrals, etc. are also considered separately (see atom_forces for the filtered
         counterpart).
         ''',
-        categories=[atom_forces_type])
+        categories=[atom_forces_type],
+        a_legacy=LegacyDefinition(name='atom_forces_raw'))
 
     atom_forces_T0_raw = Quantity(
         type=np.dtype(np.float64),
@@ -3282,7 +3741,8 @@ class section_single_configuration_calculation(MSection):
         angles, dihedrals, etc. are also considered separately (see atom_forces_T0 for the
         filtered counterpart).
         ''',
-        categories=[atom_forces_type])
+        categories=[atom_forces_type],
+        a_legacy=LegacyDefinition(name='atom_forces_T0_raw'))
 
     atom_forces_T0 = Quantity(
         type=np.dtype(np.float64),
@@ -3298,7 +3758,8 @@ class section_single_configuration_calculation(MSection):
         such as fixed atoms, distances, angles, dihedrals, etc. are also included (see
         atom_forces_free_T0_raw for the unfiltered counterpart).
         ''',
-        categories=[atom_forces_type])
+        categories=[atom_forces_type],
+        a_legacy=LegacyDefinition(name='atom_forces_T0'))
 
     atom_forces = Quantity(
         type=np.dtype(np.float64),
@@ -3314,7 +3775,8 @@ class section_single_configuration_calculation(MSection):
         such as fixed atoms, distances, angles, dihedrals, etc. are included (see
         atom_forces_raw for the unfiltered counterpart).
         ''',
-        categories=[atom_forces_type])
+        categories=[atom_forces_type],
+        a_legacy=LegacyDefinition(name='atom_forces'))
 
     electronic_kinetic_energy = Quantity(
         type=np.dtype(np.float64),
@@ -3323,7 +3785,8 @@ class section_single_configuration_calculation(MSection):
         description='''
         Self-consistent electronic kinetic energy as defined in XC_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='electronic_kinetic_energy'))
 
     energy_C = Quantity(
         type=np.dtype(np.float64),
@@ -3332,7 +3795,8 @@ class section_single_configuration_calculation(MSection):
         description='''
         Correlation (C) energy calculated with the method described in XC_functional.
         ''',
-        categories=[energy_value, energy_type_C, energy_component])
+        categories=[energy_component, energy_value, energy_type_C],
+        a_legacy=LegacyDefinition(name='energy_C'))
 
     energy_correction_entropy = Quantity(
         type=np.dtype(np.float64),
@@ -3343,7 +3807,8 @@ class section_single_configuration_calculation(MSection):
         occupation so that forces at finite T do not need to keep the change of occupation
         in account. Defined consistently with XC_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_correction_entropy'))
 
     energy_correction_hartree = Quantity(
         type=np.dtype(np.float64),
@@ -3354,7 +3819,8 @@ class section_single_configuration_calculation(MSection):
         (that uses the mixed density on one side), and the fully consistent density-
         density electrostatic energy. Defined consistently with XC_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_correction_hartree'))
 
     energy_current = Quantity(
         type=np.dtype(np.float64),
@@ -3371,7 +3837,8 @@ class section_single_configuration_calculation(MSection):
         page](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-info/wikis/metainfo/energy-
         current).
         ''',
-        categories=[energy_component, energy_value, energy_total_potential])
+        categories=[energy_component, energy_value, energy_total_potential],
+        a_legacy=LegacyDefinition(name='energy_current'))
 
     energy_electrostatic = Quantity(
         type=np.dtype(np.float64),
@@ -3381,7 +3848,8 @@ class section_single_configuration_calculation(MSection):
         Total electrostatic energy (nuclei + electrons), defined consistently with
         calculation_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_electrostatic'))
 
     energy_free_per_atom = Quantity(
         type=np.dtype(np.float64),
@@ -3391,7 +3859,8 @@ class section_single_configuration_calculation(MSection):
         Free energy per atom (whose minimum gives the smeared occupation density
         calculated with smearing_kind) calculated with XC_method.
         ''',
-        categories=[energy_value, energy_component_per_atom])
+        categories=[energy_component_per_atom, energy_value],
+        a_legacy=LegacyDefinition(name='energy_free_per_atom'))
 
     energy_free = Quantity(
         type=np.dtype(np.float64),
@@ -3402,7 +3871,8 @@ class section_single_configuration_calculation(MSection):
         density calculated with smearing_kind) calculated with the method described in
         XC_method.
         ''',
-        categories=[energy_component, energy_value, energy_total_potential])
+        categories=[energy_component, energy_value, energy_total_potential],
+        a_legacy=LegacyDefinition(name='energy_free'))
 
     energy_hartree_error = Quantity(
         type=np.dtype(np.float64),
@@ -3412,7 +3882,8 @@ class section_single_configuration_calculation(MSection):
         Error in the Hartree (electrostatic) potential energy. Defined consistently with
         XC_method.
         ''',
-        categories=[energy_value, error_estimate_contribution])
+        categories=[error_estimate_contribution, energy_value],
+        a_legacy=LegacyDefinition(name='energy_hartree_error'))
 
     energy_hartree_fock_X_scaled = Quantity(
         type=np.dtype(np.float64),
@@ -3426,7 +3897,8 @@ class section_single_configuration_calculation(MSection):
         hybrid functional would be stored in this metadata. Defined consistently with
         XC_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_hartree_fock_X_scaled'))
 
     energy_hartree_fock_X = Quantity(
         type=np.dtype(np.float64),
@@ -3436,7 +3908,8 @@ class section_single_configuration_calculation(MSection):
         Converged exact-exchange (Hartree-Fock) energy. Defined consistently with
         XC_method.
         ''',
-        categories=[energy_type_X, energy_value, energy_component])
+        categories=[energy_type_X, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_hartree_fock_X'))
 
     energy_method_current = Quantity(
         type=np.dtype(np.float64),
@@ -3447,7 +3920,8 @@ class section_single_configuration_calculation(MSection):
         Depending on calculation_method_kind it might be a total energy or only a
         correction.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_method_current'))
 
     energy_sum_eigenvalues_per_atom = Quantity(
         type=np.dtype(np.float64),
@@ -3457,7 +3931,8 @@ class section_single_configuration_calculation(MSection):
         Value of the energy per atom, where the energy is defined as the sum of the
         eigenvalues of the Hamiltonian matrix given by XC_method.
         ''',
-        categories=[energy_value, energy_component_per_atom])
+        categories=[energy_component_per_atom, energy_value],
+        a_legacy=LegacyDefinition(name='energy_sum_eigenvalues_per_atom'))
 
     energy_sum_eigenvalues = Quantity(
         type=np.dtype(np.float64),
@@ -3466,7 +3941,8 @@ class section_single_configuration_calculation(MSection):
         description='''
         Sum of the eigenvalues of the Hamiltonian matrix defined by XC_method.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_sum_eigenvalues'))
 
     energy_T0_per_atom = Quantity(
         type=np.dtype(np.float64),
@@ -3476,7 +3952,8 @@ class section_single_configuration_calculation(MSection):
         Value of the total energy per atom, calculated with the method described in
         XC_method and extrapolated to $T=0$, based on a free-electron gas argument.
         ''',
-        categories=[energy_total_potential_per_atom, energy_value, energy_component])
+        categories=[energy_total_potential_per_atom, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_T0_per_atom'))
 
     energy_total_T0_per_atom = Quantity(
         type=np.dtype(np.float64),
@@ -3486,7 +3963,8 @@ class section_single_configuration_calculation(MSection):
         Value of the total energy, calculated with the method described in XC_method per
         atom extrapolated to $T=0$, based on a free-electron gas argument.
         ''',
-        categories=[energy_total_potential_per_atom, energy_value, energy_component])
+        categories=[energy_total_potential_per_atom, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_total_T0_per_atom'))
 
     energy_total_T0 = Quantity(
         type=np.dtype(np.float64),
@@ -3497,7 +3975,8 @@ class section_single_configuration_calculation(MSection):
         method described in XC_method and extrapolated to $T=0$, based on a free-electron
         gas argument.
         ''',
-        categories=[energy_component, energy_value, energy_total_potential])
+        categories=[energy_component, energy_value, energy_total_potential],
+        a_legacy=LegacyDefinition(name='energy_total_T0'))
 
     energy_total = Quantity(
         type=np.dtype(np.float64),
@@ -3507,7 +3986,8 @@ class section_single_configuration_calculation(MSection):
         Value of the total energy, calculated with the method described in XC_method and
         extrapolated to $T=0$, based on a free-electron gas argument.
         ''',
-        categories=[energy_component, energy_value, energy_total_potential])
+        categories=[energy_component, energy_value, energy_total_potential],
+        a_legacy=LegacyDefinition(name='energy_total'))
 
     energy_XC_functional = Quantity(
         type=np.dtype(np.float64),
@@ -3517,7 +3997,8 @@ class section_single_configuration_calculation(MSection):
         Value of the exchange-correlation (XC) energy calculated with the functional
         stored in XC_functional.
         ''',
-        categories=[energy_type_XC, energy_value, energy_component])
+        categories=[energy_type_XC, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_XC_functional'))
 
     energy_XC_potential = Quantity(
         type=np.dtype(np.float64),
@@ -3530,7 +4011,8 @@ class section_single_configuration_calculation(MSection):
         eigenvalues. Value associated with the configuration, should be the most converged
         value.
         ''',
-        categories=[energy_value, energy_component])
+        categories=[energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_XC_potential'))
 
     energy_XC = Quantity(
         type=np.dtype(np.float64),
@@ -3540,7 +4022,8 @@ class section_single_configuration_calculation(MSection):
         Value of the exchange-correlation (XC) energy calculated with the method described
         in XC_method.
         ''',
-        categories=[energy_type_XC, energy_value, energy_component])
+        categories=[energy_type_XC, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_XC'))
 
     energy_X = Quantity(
         type=np.dtype(np.float64),
@@ -3550,7 +4033,8 @@ class section_single_configuration_calculation(MSection):
         Value fo the exchange (X) energy calculated with the method described in
         XC_method.
         ''',
-        categories=[energy_type_X, energy_value, energy_component])
+        categories=[energy_type_X, energy_component, energy_value],
+        a_legacy=LegacyDefinition(name='energy_X'))
 
     energy_zero_point = Quantity(
         type=np.dtype(np.float64),
@@ -3558,14 +4042,16 @@ class section_single_configuration_calculation(MSection):
         description='''
         Value for the converged zero-point vibrations energy calculated using the method
         described in zero_point_method , and used in energy_current .
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='energy_zero_point'))
 
     hessian_matrix = Quantity(
         type=np.dtype(np.float64),
         shape=['number_of_atoms', 'number_of_atoms', 3, 3],
         description='''
         The matrix with the second derivative with respect to atom displacements.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='hessian_matrix'))
 
     message_debug_evaluation = Quantity(
         type=str,
@@ -3574,7 +4060,8 @@ class section_single_configuration_calculation(MSection):
         A debugging message of the computational program, associated with a *single
         configuration calculation* (see section_single_configuration_calculation).
         ''',
-        categories=[message_debug])
+        categories=[message_debug],
+        a_legacy=LegacyDefinition(name='message_debug_evaluation'))
 
     message_error_evaluation = Quantity(
         type=str,
@@ -3583,7 +4070,8 @@ class section_single_configuration_calculation(MSection):
         An error message of the computational program, associated with a *single
         configuration calculation* (see section_single_configuration_calculation).
         ''',
-        categories=[message_info, message_debug, message_warning, message_error])
+        categories=[message_info, message_debug, message_error, message_warning],
+        a_legacy=LegacyDefinition(name='message_error_evaluation'))
 
     message_info_evaluation = Quantity(
         type=str,
@@ -3592,7 +4080,8 @@ class section_single_configuration_calculation(MSection):
         An information message of the computational program, associated with a *single
         configuration calculation* (see section_single_configuration_calculation).
         ''',
-        categories=[message_info, message_debug])
+        categories=[message_info, message_debug],
+        a_legacy=LegacyDefinition(name='message_info_evaluation'))
 
     message_warning_evaluation = Quantity(
         type=str,
@@ -3600,7 +4089,8 @@ class section_single_configuration_calculation(MSection):
         description='''
         A warning message of the computational program.
         ''',
-        categories=[message_info, message_debug, message_warning])
+        categories=[message_info, message_debug, message_warning],
+        a_legacy=LegacyDefinition(name='message_warning_evaluation'))
 
     number_of_scf_iterations = Quantity(
         type=int,
@@ -3609,7 +4099,8 @@ class section_single_configuration_calculation(MSection):
         Gives the number of performed self-consistent field (SCF) iterations at a specfied
         level of theory.
         ''',
-        categories=[scf_info])
+        categories=[scf_info],
+        a_legacy=LegacyDefinition(name='number_of_scf_iterations'))
 
     parsing_message_debug_evaluation = Quantity(
         type=str,
@@ -3618,7 +4109,8 @@ class section_single_configuration_calculation(MSection):
         This field is used for debugging messages of the parsing program associated with a
         run, see section_run.
         ''',
-        categories=[parsing_message_debug])
+        categories=[parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_debug_evaluation'))
 
     parsing_message_error_single_configuration = Quantity(
         type=str,
@@ -3627,7 +4119,8 @@ class section_single_configuration_calculation(MSection):
         This field is used for error messages of the parsing program associated with a
         single configuration calculation, see section_single_configuration_calculation.
         ''',
-        categories=[parsing_message_info, parsing_message_error, parsing_message_warning, parsing_message_debug])
+        categories=[parsing_message_info, parsing_message_error, parsing_message_warning, parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_error_single_configuration'))
 
     parsing_message_info_single_configuration = Quantity(
         type=str,
@@ -3636,7 +4129,8 @@ class section_single_configuration_calculation(MSection):
         This field is used for info messages of the parsing program associated with a
         single configuration calculation, see section_single_configuration_calculation.
         ''',
-        categories=[parsing_message_info, parsing_message_debug])
+        categories=[parsing_message_info, parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_info_single_configuration'))
 
     parsing_message_warning_evaluation = Quantity(
         type=str,
@@ -3645,7 +4139,8 @@ class section_single_configuration_calculation(MSection):
         This field is used for warning messages of the parsing program associated with a
         run, see section_run.
         ''',
-        categories=[parsing_message_info, parsing_message_warning, parsing_message_debug])
+        categories=[parsing_message_info, parsing_message_warning, parsing_message_debug],
+        a_legacy=LegacyDefinition(name='parsing_message_warning_evaluation'))
 
     single_configuration_calculation_converged = Quantity(
         type=bool,
@@ -3653,7 +4148,8 @@ class section_single_configuration_calculation(MSection):
         description='''
         Determines whether a *single configuration calculation* in
         section_single_configuration_calculation is converged.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='single_configuration_calculation_converged'))
 
     single_configuration_calculation_to_system_ref = Quantity(
         type=Reference(SectionProxy('section_system')),
@@ -3661,7 +4157,8 @@ class section_single_configuration_calculation(MSection):
         description='''
         Reference to the system (atomic configuration, cell, ...) that is calculated in
         section_single_configuration_calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='single_configuration_calculation_to_system_ref'))
 
     single_configuration_to_calculation_method_ref = Quantity(
         type=Reference(SectionProxy('section_method')),
@@ -3669,7 +4166,8 @@ class section_single_configuration_calculation(MSection):
         description='''
         Reference to the method used for the calculation in
         section_single_configuration_calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='single_configuration_to_calculation_method_ref'))
 
     spin_S2 = Quantity(
         type=np.dtype(np.float64),
@@ -3678,7 +4176,8 @@ class section_single_configuration_calculation(MSection):
         Stores the value of the total spin moment operator $S^2$ for the converged
         wavefunctions calculated with the XC_method. It can be used to calculate the spin
         contamination in spin-unrestricted calculations.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='spin_S2'))
 
     stress_tensor = Quantity(
         type=np.dtype(np.float64),
@@ -3692,7 +4191,8 @@ class section_single_configuration_calculation(MSection):
         optimization. Alternative definitions of the stress tensor can be assigned with
         stress_tensor_kind
         ''',
-        categories=[stress_tensor_type])
+        categories=[stress_tensor_type],
+        a_legacy=LegacyDefinition(name='stress_tensor'))
 
     time_calculation = Quantity(
         type=np.dtype(np.float64),
@@ -3703,7 +4203,8 @@ class section_single_configuration_calculation(MSection):
         calculation_method_current. Basically, it tracks the real time that has been
         elapsed from start to end.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_calculation'))
 
     time_single_configuration_calculation_cpu1_end = Quantity(
         type=np.dtype(np.float64),
@@ -3713,7 +4214,8 @@ class section_single_configuration_calculation(MSection):
         Stores the end time of the *single configuration calculation* (see
         section_single_configuration_calculation) on CPU 1.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_single_configuration_calculation_cpu1_end'))
 
     time_single_configuration_calculation_cpu1_start = Quantity(
         type=np.dtype(np.float64),
@@ -3723,7 +4225,8 @@ class section_single_configuration_calculation(MSection):
         Stores the start time of the *single configuration calculation* (see
         section_single_configuration_calculation) on CPU 1.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_single_configuration_calculation_cpu1_start'))
 
     time_single_configuration_calculation_date_end = Quantity(
         type=np.dtype(np.float64),
@@ -3735,7 +4238,8 @@ class section_single_configuration_calculation(MSection):
         UTC on 1 January 1970) in seconds. For date and times without a timezone, the
         default timezone GMT is used.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_single_configuration_calculation_date_end'))
 
     time_single_configuration_calculation_date_start = Quantity(
         type=np.dtype(np.float64),
@@ -3747,7 +4251,8 @@ class section_single_configuration_calculation(MSection):
         UTC on 1 January 1970) in seconds. For date and times without a timezone, the
         default timezone GMT is used.
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_single_configuration_calculation_date_start'))
 
     time_single_configuration_calculation_wall_end = Quantity(
         type=np.dtype(np.float64),
@@ -3757,7 +4262,8 @@ class section_single_configuration_calculation(MSection):
         Stores the internal wall-clock time at the end of the *single configuration
         calculation* (see section_single_configuration_calculation).
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_single_configuration_calculation_wall_end'))
 
     time_single_configuration_calculation_wall_start = Quantity(
         type=np.dtype(np.float64),
@@ -3767,7 +4273,8 @@ class section_single_configuration_calculation(MSection):
         Stores the internal wall-clock time from the start of the *single configuration
         calculation* (see section_single_configuration_calculation).
         ''',
-        categories=[accessory_info, time_info])
+        categories=[time_info, accessory_info],
+        a_legacy=LegacyDefinition(name='time_single_configuration_calculation_wall_start'))
 
     zero_point_method = Quantity(
         type=str,
@@ -3775,67 +4282,83 @@ class section_single_configuration_calculation(MSection):
         description='''
         Describes the zero-point vibrations method. If skipped or an empty string is used,
         it means no zero-point vibrations correction is applied.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='zero_point_method'))
 
     section_atom_projected_dos = SubSection(
         sub_section=SectionProxy('section_atom_projected_dos'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_atom_projected_dos'))
 
     section_atomic_multipoles = SubSection(
         sub_section=SectionProxy('section_atomic_multipoles'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_atomic_multipoles'))
 
     section_basis_set = SubSection(
         sub_section=SectionProxy('section_basis_set'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_basis_set'))
 
     section_calculation_to_calculation_refs = SubSection(
         sub_section=SectionProxy('section_calculation_to_calculation_refs'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_calculation_to_calculation_refs'))
 
     section_calculation_to_folder_refs = SubSection(
         sub_section=SectionProxy('section_calculation_to_folder_refs'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_calculation_to_folder_refs'))
 
     section_dos = SubSection(
         sub_section=SectionProxy('section_dos'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_dos'))
 
     section_eigenvalues = SubSection(
         sub_section=SectionProxy('section_eigenvalues'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_eigenvalues'))
 
     section_energy_code_independent = SubSection(
         sub_section=SectionProxy('section_energy_code_independent'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_energy_code_independent'))
 
     section_energy_van_der_Waals = SubSection(
         sub_section=SectionProxy('section_energy_van_der_Waals'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_energy_van_der_Waals'))
 
     section_k_band_normalized = SubSection(
         sub_section=SectionProxy('section_k_band_normalized'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_k_band_normalized'))
 
     section_k_band = SubSection(
         sub_section=SectionProxy('section_k_band'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_k_band'))
 
     section_scf_iteration = SubSection(
         sub_section=SectionProxy('section_scf_iteration'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_scf_iteration'))
 
     section_species_projected_dos = SubSection(
         sub_section=SectionProxy('section_species_projected_dos'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_species_projected_dos'))
 
     section_stress_tensor = SubSection(
         sub_section=SectionProxy('section_stress_tensor'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_stress_tensor'))
 
     section_volumetric_data = SubSection(
         sub_section=SectionProxy('section_volumetric_data'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_volumetric_data'))
 
 
 class section_species_projected_dos(MSection):
@@ -3844,7 +4367,7 @@ class section_species_projected_dos(MSection):
     evaluation.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_species_projected_dos'))
 
     number_of_lm_species_projected_dos = Quantity(
         type=int,
@@ -3852,7 +4375,8 @@ class section_species_projected_dos(MSection):
         description='''
         Gives the number of $l$, $m$ combinations for the species-projected density of
         states (DOS) defined in section_species_projected_dos.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_lm_species_projected_dos'))
 
     number_of_species_projected_dos_values = Quantity(
         type=int,
@@ -3860,7 +4384,8 @@ class section_species_projected_dos(MSection):
         description='''
         Gives the number of energy values for the species-projected density of states
         (DOS) defined in section_species_projected_dos.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_species_projected_dos_values'))
 
     number_of_species = Quantity(
         type=int,
@@ -3868,7 +4393,8 @@ class section_species_projected_dos(MSection):
         description='''
         Gives the number of species for the species-projected density of states (DOS)
         defined in section_species_projected_dos.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_species'))
 
     species_projected_dos_energies_normalized = Quantity(
         type=np.dtype(np.float64),
@@ -3878,7 +4404,8 @@ class section_species_projected_dos(MSection):
         Contains the set of discrete energy values with respect to the top of the valence
         band for the species-projected density of states (DOS). It is derived from the
         species_projected_dos_energies species field.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='species_projected_dos_energies_normalized'))
 
     species_projected_dos_energies = Quantity(
         type=np.dtype(np.float64),
@@ -3887,7 +4414,8 @@ class section_species_projected_dos(MSection):
         description='''
         Contains the set of discrete energy values for the species-projected density of
         states (DOS).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='species_projected_dos_energies'))
 
     species_projected_dos_lm = Quantity(
         type=np.dtype(np.int32),
@@ -3900,7 +4428,8 @@ class section_species_projected_dos(MSection):
         quantum number $m$, besides the conventional use as magnetic quantum number ($l+1$
         integer values from $-l$ to $l$), a set of different conventions is accepted. The
         adopted convention is specified by atom_projected_dos_m_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='species_projected_dos_lm'))
 
     species_projected_dos_m_kind = Quantity(
         type=str,
@@ -3921,7 +4450,8 @@ class section_species_projected_dos(MSection):
         * integrated
 
         functions or values.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='species_projected_dos_m_kind'))
 
     species_projected_dos_species_label = Quantity(
         type=str,
@@ -3935,7 +4465,8 @@ class section_species_projected_dos(MSection):
         refer to actual atomic species, i.e. belonging to the periodic table of elements.
         Thus, the species-projected DOS are expected to be as many as the different atomic
         species in the system.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='species_projected_dos_species_label'))
 
     species_projected_dos_values_lm = Quantity(
         type=np.dtype(np.float64),
@@ -3947,7 +4478,8 @@ class section_species_projected_dos(MSection):
         Here, there are as many species-projected DOS as the number of species,
         number_of_species. The list of labels of the species is given in
         species_projected_dos_species_label.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='species_projected_dos_values_lm'))
 
     species_projected_dos_values_total = Quantity(
         type=np.dtype(np.float64),
@@ -3959,7 +4491,8 @@ class section_species_projected_dos(MSection):
         Here, there are as many species-projected DOS as the number of species,
         number_of_species. The list of labels of the species is given in
         species_projected_dos_species_label.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='species_projected_dos_values_total'))
 
 
 class section_springer_material(MSection):
@@ -3970,28 +4503,31 @@ class section_springer_material(MSection):
     section_springer_references
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_springer_material'))
 
     springer_id = Quantity(
         type=str,
         shape=[],
         description='''
         Id of the classified material according to Springer Materials
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='springer_id'))
 
     springer_alphabetical_formula = Quantity(
         type=str,
         shape=[],
         description='''
         The alphabetical formula of the material according to Springer Materials Database
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='springer_alphabetical_formula'))
 
     springer_url = Quantity(
         type=str,
         shape=[],
         description='''
         Url to the source page in Springer Materials describing the current entry
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='springer_url'))
 
     springer_compound_class = Quantity(
         type=str,
@@ -3999,7 +4535,8 @@ class section_springer_material(MSection):
         description='''
         Name of a class of the current compound, as defined in by Springer Materials. This
         is a property of the chemical formula of the compound
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='springer_compound_class'))
 
     springer_classification = Quantity(
         type=str,
@@ -4007,11 +4544,13 @@ class section_springer_material(MSection):
         description='''
         Contains the classification name of the current material according to Springer
         Materials
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='springer_classification'))
 
     section_springer_id = SubSection(
         sub_section=SectionProxy('section_springer_id'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_springer_id'))
 
 
 class section_springer_id(MSection):
@@ -4019,7 +4558,7 @@ class section_springer_id(MSection):
     Identifiers used by Springer Materials
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_springer_id'))
 
 
 class section_std_system(MSection):
@@ -4029,21 +4568,23 @@ class section_std_system(MSection):
     from https://arxiv.org/abs/1506.01455
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_std_system'))
 
     atom_positions_std = Quantity(
         type=np.dtype(np.float64),
         shape=['number_of_atoms_std', 3],
         description='''
         Standardized atom positions in reduced units.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_positions_std'))
 
     atomic_numbers_std = Quantity(
         type=np.dtype(np.int32),
         shape=['number_of_atoms_std'],
         description='''
         Atomic numbers of the atoms in the standardized cell.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atomic_numbers_std'))
 
     equivalent_atoms_std = Quantity(
         type=np.dtype(np.int32),
@@ -4051,7 +4592,8 @@ class section_std_system(MSection):
         description='''
         Gives a mapping table of atoms to symmetrically independent atoms in the
         standardized cell. This is used to find symmetrically equivalent atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='equivalent_atoms_std'))
 
     lattice_vectors_std = Quantity(
         type=np.dtype(np.float64),
@@ -4060,21 +4602,24 @@ class section_std_system(MSection):
         description='''
         Standardized lattice vectors of the conventional cell. The vectors are the rows of
         this matrix.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='lattice_vectors_std'))
 
     number_of_atoms_std = Quantity(
         type=int,
         shape=[],
         description='''
         Number of atoms in standardized system.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atoms_std'))
 
     wyckoff_letters_std = Quantity(
         type=str,
         shape=['number_of_atoms_std'],
         description='''
         Wyckoff letters for atoms in the standardized cell.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='wyckoff_letters_std'))
 
 
 class section_stress_tensor(MSection):
@@ -4086,7 +4631,7 @@ class section_stress_tensor(MSection):
     geometry optimization (if needed).
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_stress_tensor'))
 
     stress_tensor_kind = Quantity(
         type=str,
@@ -4099,7 +4644,8 @@ class section_stress_tensor(MSection):
         This field allows for multiple definitions and evaluated values of the stress
         tensor, while only one definition is used for, e.g., molecular dynamics and
         geometry optimization.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='stress_tensor_kind'))
 
     stress_tensor_value = Quantity(
         type=np.dtype(np.float64),
@@ -4113,7 +4659,8 @@ class section_stress_tensor(MSection):
         tensor, while only one definition is used for, e.g., molecular dynamics and
         geometry optimization.
         ''',
-        categories=[stress_tensor_type])
+        categories=[stress_tensor_type],
+        a_legacy=LegacyDefinition(name='stress_tensor_value'))
 
 
 class section_symmetry(MSection):
@@ -4121,7 +4668,7 @@ class section_symmetry(MSection):
     Section containing information about the symmetry properties of the system.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_symmetry'))
 
     bravais_lattice = Quantity(
         type=str,
@@ -4133,7 +4680,8 @@ class section_symmetry(MSection):
         second uppercase letter identifies the centring and can be one of the following: P
         (primitive), S (face centred), I (body centred), R (rhombohedral centring) or F
         (all faces centred).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='bravais_lattice'))
 
     choice = Quantity(
         type=str,
@@ -4142,7 +4690,8 @@ class section_symmetry(MSection):
         String that specifies the centering, origin and basis vector settings of the 3D
         space group that defines the symmetry group of the simulated physical system (see
         section_system). Values are as defined by spglib.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='choice'))
 
     crystal_system = Quantity(
         type=str,
@@ -4150,21 +4699,24 @@ class section_symmetry(MSection):
         description='''
         Name of the crystal system. Can be one of the following: triclinic, monoclinic,
         orthorhombic, tetragonal, trigonal, hexagonal or cubic.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='crystal_system'))
 
     hall_number = Quantity(
         type=np.dtype(np.int32),
         shape=[],
         description='''
         The Hall number for this system.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='hall_number'))
 
     hall_symbol = Quantity(
         type=str,
         shape=[],
         description='''
         The Hall symbol for this system.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='hall_symbol'))
 
     international_short_symbol = Quantity(
         type=str,
@@ -4172,7 +4724,8 @@ class section_symmetry(MSection):
         description='''
         Specifies the International Union of Crystallography (IUC) short symbol of the 3D
         space group of this system
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='international_short_symbol'))
 
     origin_shift = Quantity(
         type=np.dtype(np.float64),
@@ -4183,14 +4736,16 @@ class section_symmetry(MSection):
         space_group_3D_transformation_matrix, the transformation between the standardized
         coordinates $\\mathbf{x}_s$ and original coordinates $\\mathbf{x}$ is then given by
         $\\mathbf{x}_s = \\mathbf{P} \\mathbf{x} + \\mathbf{p}$.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='origin_shift'))
 
     point_group = Quantity(
         type=str,
         shape=[],
         description='''
         Symbol of the crystallographic point group in the Hermann-Mauguin notation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='point_group'))
 
     space_group_number = Quantity(
         type=np.dtype(np.int32),
@@ -4198,7 +4753,8 @@ class section_symmetry(MSection):
         description='''
         Specifies the International Union of Crystallography (IUC) number of the 3D space
         group of this system.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='space_group_number'))
 
     symmetry_method = Quantity(
         type=str,
@@ -4206,7 +4762,8 @@ class section_symmetry(MSection):
         description='''
         Identifies the source of the symmetry information contained within this section.
         If equal to 'spg_normalized' the information comes from a normalization step.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='symmetry_method'))
 
     transformation_matrix = Quantity(
         type=np.dtype(np.float64),
@@ -4217,19 +4774,23 @@ class section_symmetry(MSection):
         space_group_3D_origin_shift, the transformation between the standardized
         coordinates $\\mathbf{x}_s$ and original coordinates $\\mathbf{x}$ is then given by
         $\\mathbf{x}_s = \\mathbf{P} \\mathbf{x} + \\mathbf{p}$.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='transformation_matrix'))
 
     section_original_system = SubSection(
         sub_section=SectionProxy('section_original_system'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_original_system'))
 
     section_primitive_system = SubSection(
         sub_section=SectionProxy('section_primitive_system'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_primitive_system'))
 
     section_std_system = SubSection(
         sub_section=SectionProxy('section_std_system'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_std_system'))
 
 
 class section_system_to_system_refs(MSection):
@@ -4245,7 +4806,7 @@ class section_system_to_system_refs(MSection):
     via system_to_system_ref.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_system_to_system_refs'))
 
     system_to_system_kind = Quantity(
         type=str,
@@ -4257,7 +4818,8 @@ class section_system_to_system_refs(MSection):
         larger supercell but properties such as the phonon band structure are still
         calculated for the primitive cell. Hence, the need of keeping track of these
         connected systems. The referenced system is identified via system_to_system_ref.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='system_to_system_kind'))
 
     system_to_system_ref = Quantity(
         type=Reference(SectionProxy('section_system')),
@@ -4265,7 +4827,8 @@ class section_system_to_system_refs(MSection):
         description='''
         Reference to another system. The kind of relationship between the present and the
         referenced section_system is specified by system_to_system_kind.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='system_to_system_ref'))
 
 
 class section_system(MSection):
@@ -4275,14 +4838,15 @@ class section_system(MSection):
     (if present), the external potentials and other parameters.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_system'))
 
     atom_atom_number = Quantity(
         type=np.dtype(np.int32),
         shape=['number_of_sites'],
         description='''
         Atomic number Z of the atom.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_atom_number'))
 
     atom_concentrations = Quantity(
         type=np.dtype(np.float64),
@@ -4290,7 +4854,8 @@ class section_system(MSection):
         description='''
         concentration of the atom species in a variable composition, by default it should
         be considered an array of ones. Summing these should give the number_of_sites
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_concentrations'))
 
     atom_labels = Quantity(
         type=str,
@@ -4306,7 +4871,8 @@ class section_system(MSection):
         atom-centered basis sets). This metadata defines a configuration and is therefore
         required.
         ''',
-        categories=[configuration_core])
+        categories=[configuration_core],
+        a_legacy=LegacyDefinition(name='atom_labels'))
 
     atom_positions = Quantity(
         type=np.dtype(np.float64),
@@ -4318,7 +4884,8 @@ class section_system(MSection):
         species are given for each site in the unit cell, it stores the position of the
         sites.
         ''',
-        categories=[configuration_core])
+        categories=[configuration_core],
+        a_legacy=LegacyDefinition(name='atom_positions'))
 
     atom_species = Quantity(
         type=np.dtype(np.int32),
@@ -4326,7 +4893,8 @@ class section_system(MSection):
         description='''
         Species of the atom (normally the atomic number Z, 0 or negative for unidentifed
         species or particles that are not atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_species'))
 
     atom_velocities = Quantity(
         type=np.dtype(np.float64),
@@ -4335,7 +4903,8 @@ class section_system(MSection):
         description='''
         Velocities of the nuclei, defined as the change in Cartesian coordinates of the
         nuclei with respect to time.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='atom_velocities'))
 
     configuration_periodic_dimensions = Quantity(
         type=bool,
@@ -4347,7 +4916,8 @@ class section_system(MSection):
         section_single_configuration_calculation where it is defined for all subsequent
         section_single_configuration_calculation in section_run, until redefined.
         ''',
-        categories=[configuration_core])
+        categories=[configuration_core],
+        a_legacy=LegacyDefinition(name='configuration_periodic_dimensions'))
 
     configuration_raw_gid = Quantity(
         type=str,
@@ -4356,7 +4926,8 @@ class section_system(MSection):
         checksum of the configuration_core, i.e. the geometry of the system. The values
         are not normalized in any way so equivalent configurations might have different
         values
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='configuration_raw_gid'))
 
     embedded_system = Quantity(
         type=bool,
@@ -4364,7 +4935,8 @@ class section_system(MSection):
         description='''
         Is the system embedded into a host geometry?.
         ''',
-        categories=[configuration_core])
+        categories=[configuration_core],
+        a_legacy=LegacyDefinition(name='embedded_system'))
 
     lattice_vectors = Quantity(
         type=np.dtype(np.float64),
@@ -4375,7 +4947,8 @@ class section_system(MSection):
         last (fastest) index runs over the $x,y,z$ Cartesian coordinates, and the first
         index runs over the 3 lattice vectors.
         ''',
-        categories=[configuration_core])
+        categories=[configuration_core],
+        a_legacy=LegacyDefinition(name='lattice_vectors'))
 
     local_rotations = Quantity(
         type=np.dtype(np.float64),
@@ -4384,7 +4957,8 @@ class section_system(MSection):
         A rotation matrix defining the orientation of each atom. If the rotation matrix
         only needs to be specified for some atoms, the remaining atoms should set it to
         the zero matrix (not the identity!)
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='local_rotations'))
 
     number_of_atoms = Quantity(
         type=int,
@@ -4393,7 +4967,8 @@ class section_system(MSection):
         Stores the total number of atoms used in the calculation. For alloys where
         concentrations of species are given for each site in the unit cell, it stores the
         number of sites.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_atoms'))
 
     number_of_sites = Quantity(
         type=int,
@@ -4401,7 +4976,8 @@ class section_system(MSection):
         description='''
         number of sites in a variable composition representation. By default (no variable
         composition) it is the same as number_of_atoms.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_sites'))
 
     SC_matrix = Quantity(
         type=np.dtype(np.int32),
@@ -4409,7 +4985,8 @@ class section_system(MSection):
         description='''
         Specifies the matrix that transforms the unit-cell into the super-cell in which
         the actual calculation is performed.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='SC_matrix'))
 
     simulation_cell = Quantity(
         type=np.dtype(np.float64),
@@ -4421,14 +4998,16 @@ class section_system(MSection):
         $x,y,z$ Cartesian coordinates, and the first index runs over the 3 lattice
         vectors.
         ''',
-        categories=[configuration_core])
+        categories=[configuration_core],
+        a_legacy=LegacyDefinition(name='simulation_cell'))
 
     symmorphic = Quantity(
         type=bool,
         shape=[],
         description='''
         Is the space group symmorphic? Set to True if all translations are zero.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='symmorphic'))
 
     system_composition = Quantity(
         type=str,
@@ -4436,14 +5015,16 @@ class section_system(MSection):
         description='''
         Composition, i.e. cumulative chemical formula with atoms ordered by decreasing
         atomic number Z.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='system_composition'))
 
     system_configuration_consistent = Quantity(
         type=bool,
         shape=[],
         description='''
         Flag set is the configuration is consistent
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='system_configuration_consistent'))
 
     system_name = Quantity(
         type=str,
@@ -4451,7 +5032,8 @@ class section_system(MSection):
         description='''
         Specifies the name of the system. This information is provided by the user in some
         codes and is stored here for debugging or visualization purposes.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='system_name'))
 
     system_reweighted_composition = Quantity(
         type=str,
@@ -4460,35 +5042,40 @@ class section_system(MSection):
         Composition, i.e. cumulative chemical with atoms ordered by decreasing atomic
         number Z reweighted so that the sum is close to 100, and values are rounded up,
         and are stable (i.e. it is a fixed point).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='system_reweighted_composition'))
 
     system_type = Quantity(
         type=str,
         shape=[],
         description='''
         Type of the system
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='system_type'))
 
     time_reversal_symmetry = Quantity(
         type=bool,
         shape=[],
         description='''
         Is time-reversal symmetry present?
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='time_reversal_symmetry'))
 
     chemical_composition = Quantity(
         type=str,
         shape=[],
         description='''
         The chemical composition as full formula of the system, based on atom species.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='chemical_composition'))
 
     chemical_composition_reduced = Quantity(
         type=str,
         shape=[],
         description='''
         The chemical composition as reduced formula of the system, based on atom species.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='chemical_composition_reduced'))
 
     chemical_composition_bulk_reduced = Quantity(
         type=str,
@@ -4496,23 +5083,28 @@ class section_system(MSection):
         description='''
         The chemical composition as reduced bulk formula of the system, based on atom
         species.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='chemical_composition_bulk_reduced'))
 
     section_prototype = SubSection(
         sub_section=SectionProxy('section_prototype'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_prototype'))
 
     section_springer_material = SubSection(
         sub_section=SectionProxy('section_springer_material'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_springer_material'))
 
     section_symmetry = SubSection(
         sub_section=SectionProxy('section_symmetry'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_symmetry'))
 
     section_system_to_system_refs = SubSection(
         sub_section=SectionProxy('section_system_to_system_refs'),
-        repeats=True)
+        repeats=True,
+        a_legacy=LegacyDefinition(name='section_system_to_system_refs'))
 
 
 class section_thermodynamical_properties(MSection):
@@ -4521,7 +5113,7 @@ class section_thermodynamical_properties(MSection):
     section_frame_sequence.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_thermodynamical_properties'))
 
     helmholz_free_energy = Quantity(
         type=np.dtype(np.float64),
@@ -4530,7 +5122,8 @@ class section_thermodynamical_properties(MSection):
         description='''
         Stores the Helmholtz free energy per unit cell at constant volume of a
         thermodynamic calculation.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='helmholz_free_energy'))
 
     number_of_thermodynamical_property_values = Quantity(
         type=int,
@@ -4538,7 +5131,8 @@ class section_thermodynamical_properties(MSection):
         description='''
         Gives the number of thermal properties values available in
         section_thermodynamical_properties.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='number_of_thermodynamical_property_values'))
 
     thermodynamical_properties_calculation_method = Quantity(
         type=str,
@@ -4549,7 +5143,8 @@ class section_thermodynamical_properties(MSection):
         Valid values:
 
         * harmonic
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='thermodynamical_properties_calculation_method'))
 
     thermodynamical_property_heat_capacity_C_v = Quantity(
         type=np.dtype(np.float64),
@@ -4557,7 +5152,8 @@ class section_thermodynamical_properties(MSection):
         unit='joule / kelvin',
         description='''
         Stores the heat capacity per cell unit at constant volume.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='thermodynamical_property_heat_capacity_C_v'))
 
     thermodynamical_property_temperature = Quantity(
         type=np.dtype(np.float64),
@@ -4566,7 +5162,8 @@ class section_thermodynamical_properties(MSection):
         description='''
         Specifies the temperatures at which properties such as the Helmholtz free energy
         are calculated.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='thermodynamical_property_temperature'))
 
     vibrational_free_energy_at_constant_volume = Quantity(
         type=np.dtype(np.float64),
@@ -4574,7 +5171,8 @@ class section_thermodynamical_properties(MSection):
         unit='joule',
         description='''
         Holds the vibrational free energy per atom at constant volume.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='vibrational_free_energy_at_constant_volume'))
 
 
 class section_volumetric_data(MSection):
@@ -4612,7 +5210,7 @@ class section_volumetric_data(MSection):
     Rules for more complex spins are to be decided when necessary.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_volumetric_data'))
 
     volumetric_data_displacements = Quantity(
         type=np.dtype(np.float64),
@@ -4623,7 +5221,8 @@ class section_volumetric_data(MSection):
         lattice_vectors.  In many cases, displacements and number of points are related to
         lattice_vectors through: [displacement] * [number of points + N] =
         [lattice_vector],where N is 1 for periodic directions and 0 for non-periodic ones
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='volumetric_data_displacements'))
 
     volumetric_data_kind = Quantity(
         type=str,
@@ -4634,35 +5233,40 @@ class section_volumetric_data(MSection):
         are 1/m^3 and potentials are J/m^3.  See [full specification on the
         wiki](https://gitlab.mpcdf.mpg.de/nomad-lab/nomad-meta-
         info/wikis/metainfo/volumetric-data).
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='volumetric_data_kind'))
 
     volumetric_data_multiplicity = Quantity(
         type=int,
         shape=[],
         description='''
         number of functions stored
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='volumetric_data_multiplicity'))
 
     volumetric_data_nx = Quantity(
         type=int,
         shape=[],
         description='''
         number of points along x axis
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='volumetric_data_nx'))
 
     volumetric_data_ny = Quantity(
         type=int,
         shape=[],
         description='''
         number of points along y axis
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='volumetric_data_ny'))
 
     volumetric_data_nz = Quantity(
         type=int,
         shape=[],
         description='''
         number of points along z axis
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='volumetric_data_nz'))
 
     volumetric_data_origin = Quantity(
         type=np.dtype(np.float64),
@@ -4670,7 +5274,8 @@ class section_volumetric_data(MSection):
         description='''
         location of the first grid point; same coordinate system as atom_positions when
         applicable.
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='volumetric_data_origin'))
 
     volumetric_data_values = Quantity(
         type=np.dtype(np.float64),
@@ -4679,7 +5284,8 @@ class section_volumetric_data(MSection):
         Array of shape (multiplicity, nx, ny, nz) containing the values.  The units of
         these values depend on which kind of data the values represent; see
         "volumetric_data_kind".
-        ''')
+        ''',
+        a_legacy=LegacyDefinition(name='volumetric_data_values'))
 
 
 class section_XC_functionals(MSection):
@@ -4688,7 +5294,7 @@ class section_XC_functionals(MSection):
     section_method that are combined to form the XC_functional.
     '''
 
-    m_def = Section(validate=False)
+    m_def = Section(validate=False, a_legacy=LegacyDefinition(name='section_XC_functionals'))
 
     XC_functional_name = Quantity(
         type=str,
@@ -4704,7 +5310,8 @@ class section_XC_functionals(MSection):
         *NOTE*: This value should refer to a correlation, an exchange or an exchange-
         correlation functional only.
         ''',
-        categories=[settings_physical_parameter])
+        categories=[settings_physical_parameter],
+        a_legacy=LegacyDefinition(name='XC_functional_name'))
 
     XC_functional_parameters = Quantity(
         type=typing.Any,
@@ -4725,7 +5332,8 @@ class section_XC_functionals(MSection):
         If this metadata is not given, the default parameter values for the
         XC_functional_name are assumed.
         ''',
-        categories=[settings_physical_parameter])
+        categories=[settings_physical_parameter],
+        a_legacy=LegacyDefinition(name='XC_functional_parameters'))
 
     XC_functional_weight = Quantity(
         type=np.dtype(np.float64),
@@ -4741,7 +5349,8 @@ class section_XC_functionals(MSection):
 
         If not specified then the default is set to 1.
         ''',
-        categories=[settings_physical_parameter])
+        categories=[settings_physical_parameter],
+        a_legacy=LegacyDefinition(name='XC_functional_weight'))
 
 
 m_package.__init_metainfo__()
diff --git a/nomad/metainfo/__init__.py b/nomad/metainfo/__init__.py
index 2c8858d5d8..7d7ca15ee6 100644
--- a/nomad/metainfo/__init__.py
+++ b/nomad/metainfo/__init__.py
@@ -276,6 +276,7 @@ A more complex example
 
 
 from .metainfo import (
+    MSectionBound,
     MSection,
     MCategory,
     Definition,
diff --git a/nomad/metainfo/legacy.py b/nomad/metainfo/legacy.py
index 5bfaa9591e..47a36236c2 100644
--- a/nomad/metainfo/legacy.py
+++ b/nomad/metainfo/legacy.py
@@ -1,10 +1,28 @@
+# Copyright 2018 Markus Scheidgen
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an"AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+'''
+This module contains functionality to use old 'legacy' NOMAD CoE parsers with the
+new nomad@fairdi infrastructure. This covers aspects like the new metainfo, a unifying
+wrapper for parsers, parser logging, and a parser backend.
+'''
 
 from typing import cast, Dict, List, Union, Any, Set, Iterable, Tuple
 import numpy as np
 from pint.errors import UndefinedUnitError
 import os.path
-from jinja2 import Environment as JinjaEnvironment, PackageLoader, select_autoescape
-import textwrap
+
 
 from nomadcore.local_meta_info import loadJsonFile, InfoKindEl, InfoKindEnv
 import nomad_meta_info
@@ -12,8 +30,7 @@ import nomad_meta_info
 from nomad import utils
 from nomad.metainfo import (
     Definition, SubSection, Package, Quantity, Category, Section, Reference, units,
-    Environment, MEnum, MProxy)
-
+    Environment, MEnum, MSection, DefinitionAnnotation)
 
 logger = utils.get_logger(__name__)
 
@@ -23,22 +40,51 @@ _ignored_packages = [
     'repository.nomadmetainfo.json']
 
 
+class LegacyDefinition(DefinitionAnnotation):
+
+    def __init__(self, name: str):
+        self.name = name
+
+
+class LegacyPackage(LegacyDefinition):
+    def __init__(self, name, python_module, python_path):
+        super().__init__(name)
+
+        self.python_module = python_module
+        self.python_path = python_path
+
+
+def normalize_name(name: str):
+    return name.replace('.', '_').replace('-', '_')
+
+
+def normalized_package_name(name: str):
+    '''
+    Transforms legacy metainfo '.nomadmetainfo.json' filenames into proper (python)
+    identifier.
+    '''
+    name = name.replace('.nomadmetainfo.json', '')
+    return normalize_name(name)
+
+
 def python_package_mapping(metainfo_package_name: str) -> Tuple[str, str]:
     '''
     Compute the python package for the given metainfo package name. It returns
-    a tuple containing a file path and a package name. The filepath denotes the file
+    a tuple containing a package name and a file path. The filepath denotes the file
     for this package within the nomad git project.
     '''
+    prefix = metainfo_package_name.replace('.nomadmetainfo.json', '').split('.')[0]
+    metainfo_package_name = normalized_package_name(metainfo_package_name)
 
-    split_mi_package_name = metainfo_package_name.split('_')
-    prefix = split_mi_package_name[0]
-
-    if prefix in ['common', 'general', 'public']:
+    if prefix in ['common', 'general', 'public', 'dft', 'ems']:
         directory = 'nomad/datamodel/metainfo'
         python_package_name = 'nomad.datamodel.metainfo.%s' % metainfo_package_name
 
     else:
-        directory = 'dependencies/parsers/%s/%sparser/metainfo' % (prefix, prefix)
+        parser_dir = prefix.replace('_', '-')
+        prefix = prefix.replace('_', '')
+
+        directory = 'dependencies/parsers/%s/%sparser/metainfo' % (parser_dir, prefix)
         python_package_name = '%sparser.metainfo.%s' % (prefix, metainfo_package_name)
 
     path = '%s/%s.py' % (directory, metainfo_package_name)
@@ -58,12 +104,12 @@ class LegacyMetainfoEnvironment(Environment):
         ''' Creates a legacy metainfo objects for the given definition. '''
         super_names: List[str] = list()
         result: Dict[str, Any] = dict(
-            name=definition.name,
+            name=definition.a_legacy.name,
             description=definition.description,
             superNames=super_names)
 
         for category in definition.categories:
-            super_names.append(category.name)
+            super_names.append(category.a_legacy.name)
 
         if isinstance(definition, Section):
             result['kindStr'] = 'type_section'
@@ -72,7 +118,7 @@ class LegacyMetainfoEnvironment(Environment):
                 for sub_section in self.resolve_definitions(definition.name, SubSection))
 
             for sub_section in self.resolve_definitions(definition.name, SubSection):
-                super_names.append(sub_section.m_parent_as(Definition).name)
+                super_names.append(sub_section.m_parent_as(Definition).a_legacy.name)
 
         elif isinstance(definition, Quantity):
             result['kindStr'] = 'document_content'
@@ -88,12 +134,8 @@ class LegacyMetainfoEnvironment(Environment):
                 dtype_str = 'C'
             elif isinstance(definition.type, Reference):
                 dtype_str = 'r'
-                if isinstance(definition.type.target_section_def, MProxy):
-                    proxy = definition.type.target_section_def
-                    proxy.m_proxy_section = definition
-                    proxy.m_proxy_quantity = Quantity.type
-                    definition.type.target_section_def = proxy.m_proxy_resolve()
-                result['referencedSections'] = [definition.type.target_section_def.name]
+                result['referencedSections'] = [
+                    definition.type.target_section_def.m_resolved().a_legacy.name]
             elif isinstance(definition.type, MEnum):
                 dtype_str = 'C'
             elif type(definition.type) == np.dtype:
@@ -106,11 +148,17 @@ class LegacyMetainfoEnvironment(Environment):
             result['dtypeStr'] = dtype_str
             if definition.unit is not None:
                 result['units'] = str(definition.unit)
-            super_names.append(definition.m_parent_as(Definition).name)
+            super_names.append(definition.m_parent_as(Definition).a_legacy.name)
 
         elif isinstance(definition, Category):
             result['kindStr'] = 'abstract_document_content'
 
+        package = cast(MSection, definition)
+        while not isinstance(package, Package):
+            package = package.m_parent
+
+        result['package'] = package.name
+
         return InfoKindEl(*args, **result, **kwargs)
 
     def legacy_info_env(self, packages: List[Package] = None, *args, **kwargs) -> InfoKindEnv:
@@ -134,8 +182,9 @@ class LegacyMetainfoEnvironment(Environment):
 class EnvironmentConversion:
     def __init__(self, legacy_env_or_path: Union[InfoKindEnv, str]):
         if isinstance(legacy_env_or_path, str):
-            legacy_env_or_path = os.path.normpath(os.path.join(
-                os.path.dirname(nomad_meta_info.__file__), legacy_env_or_path))
+            if not os.path.exists(legacy_env_or_path):
+                legacy_env_or_path = os.path.normpath(os.path.join(
+                    os.path.dirname(nomad_meta_info.__file__), legacy_env_or_path))
             self.legacy_env, _ = loadJsonFile(filePath=legacy_env_or_path)
 
         else:
@@ -148,7 +197,7 @@ class EnvironmentConversion:
         for legacy_def in self.legacy_env.infoKindEls():
             if legacy_def.package in _ignored_packages:
                 continue
-            legacy_def.package = legacy_def.package.replace('.nomadmetainfo.json', '').replace('.', '_')
+            # legacy_def.package = normalized_package_name(legacy_def.package)
             package_conversion = self.package_conversions.get(legacy_def.package)
             if package_conversion is None:
                 package_conversion = PackageConversion(self, legacy_def.package)
@@ -167,7 +216,7 @@ class EnvironmentConversion:
 
     def create_env(self) -> LegacyMetainfoEnvironment:
         env = LegacyMetainfoEnvironment()
-        env.legacy_package_name = self.legacy_env.name.replace('.nomadmetainfo.json', '').replace('.', '_')
+        env.legacy_package_name = normalized_package_name(self.legacy_env.name)
         for package_conv in self.package_conversions.values():
             package = package_conv.package
             errors, warnings = package.m_all_validate()
@@ -237,25 +286,33 @@ class PackageConversion:
         self.env_conversion = env_conversion
         self.legacy_defs: List[InfoKindEl] = []
 
-        python_package, python_path = python_package_mapping(name)
+        python_module, python_path = python_package_mapping(name)
+
+        self.package = Package(
+            name=normalize_name(name),
+            a_legacy=LegacyPackage(name, python_module, python_path))
 
-        self.package = Package(name=name, a_python=(python_package, python_path))
         self.quantities: Dict[str, Quantity] = {}
 
         self.logger = logger.bind(package=name)
 
     def create_definitions(self):
         for legacy_def in self.legacy_defs:
-            name = legacy_def.name
+            name = normalize_name(legacy_def.name)
 
             if legacy_def.kindStr == 'type_abstract_document_content':
-                self.package.m_create(Category, name=name)
+                self.package.m_create(
+                    Category, name=name, a_legacy=LegacyDefinition(name=legacy_def.name))
 
             elif legacy_def.kindStr == 'type_section':
-                self.package.m_create(Section, name=name)
+                self.package.m_create(
+                    Section, name=name,
+                    a_legacy=LegacyDefinition(name=legacy_def.name))
 
             elif legacy_def.kindStr in ['type_dimension', 'type_document_content']:
-                definition = Quantity(name=name)
+                definition = Quantity(
+                    name=name,
+                    a_legacy=LegacyDefinition(name=legacy_def.name))
                 self.quantities[name] = (definition)
 
             else:
@@ -275,7 +332,9 @@ class PackageConversion:
                 continue
 
             if create_extends and isinstance(definition, Section):
-                extending_def = self.package.m_create(Section, name=definition.name)
+                extending_def = self.package.m_create(
+                    Section, name=definition.name,
+                    a_legacy=LegacyDefinition(name=definition.a_legacy.name))
                 extending_def.base_sections = [definition]
                 extending_def.extends_base_section = True
                 return extending_def
@@ -286,25 +345,28 @@ class PackageConversion:
 
     def set_super_names(self):
         for legacy_def in self.legacy_defs:
-            definition = self.__resolve(legacy_def.name)
-            assert definition is not None, 'definition %s must exist' % legacy_def.name
+            name = normalize_name(legacy_def.name)
+            definition = self.__resolve(name)
+            assert definition is not None, 'definition %s must exist' % name
 
             if isinstance(definition, Section):
                 parent_section: Section = None
                 for super_name in legacy_def.superNames:
-                    super_def = self.__resolve(super_name, create_extends=True)
+                    super_def = self.__resolve(normalize_name(super_name), create_extends=True)
                     if isinstance(super_def, Section):
                         parent_section = cast(Section, super_def)
 
                 if parent_section is not None:
-                    sub_section = parent_section.m_create(SubSection, name=definition.name)
+                    sub_section = parent_section.m_create(
+                        SubSection, name=definition.name,
+                        a_legacy=LegacyDefinition(name=legacy_def.name))
                     sub_section.sub_section = definition
                     sub_section.repeats = legacy_def.repeats is None or legacy_def.repeats
 
             if isinstance(definition, Quantity):
                 parent_section: Section = None
                 for super_name in legacy_def.superNames:
-                    super_def = self.__resolve(super_name, create_extends=True)
+                    super_def = self.__resolve(normalize_name(super_name), create_extends=True)
                     if isinstance(super_def, Section):
                         parent_section = cast(Section, super_def)
 
@@ -312,18 +374,20 @@ class PackageConversion:
 
     def init_definitions(self):
         for legacy_def in self.legacy_defs:
-            definition = self.__resolve(legacy_def.name)
-            assert definition is not None, 'definition %s must exist' % legacy_def.name
+            name = normalize_name(legacy_def.name)
+            definition = self.__resolve(name)
+            assert definition is not None, 'definition %s must exist' % name
             logger = self.logger.bind(definition=definition.name)
 
             # common properties
-            definition.description = legacy_def.description
+            if legacy_def.description is not None and legacy_def.description.strip() != '':
+                definition.description = legacy_def.description
 
             if isinstance(definition, Definition):
                 # deal with categories
                 categories: List[Category] = []
                 for super_name in legacy_def.superNames:
-                    super_def = self.__resolve(super_name)
+                    super_def = self.__resolve(normalize_name(super_name))
                     if isinstance(super_def, Category):
                         categories.append(super_def)
 
@@ -343,7 +407,7 @@ class PackageConversion:
 
                 elif len(referenced_sections) > 1:
                     logger.error(
-                        'higher dimensional references not yet supported: %s' % legacy_def.name)
+                        'higher dimensional references not yet supported: %s' % name)
                     definition.type = np.dtype(int)
 
                 elif legacy_def.kindStr == 'type_dimension':
@@ -353,7 +417,7 @@ class PackageConversion:
                 elif legacy_def.dtypeStr == 'C':
                     definition.type = str
                 elif legacy_def.dtypeStr == 'r':
-                    logger.error('r typed quantity %s  doesn\'t have referencedSections' % legacy_def.name)
+                    logger.error('r typed quantity %s  doesn\'t have referencedSections' % name)
                     definition.type = int
                 elif legacy_def.dtypeStr == 'b':
                     definition.type = bool
@@ -400,6 +464,8 @@ def generate_metainfo_code(metainfo_env: LegacyMetainfoEnvironment):
             is the working directory. The path will be used to form the module prefix
             for generated Python modules.
     '''
+    from jinja2 import Environment as JinjaEnvironment, PackageLoader, select_autoescape
+    import textwrap
 
     def format_description(description, indent=0, width=90):
         paragraphs = [paragraph.strip() for paragraph in description.split('\n')]
@@ -416,16 +482,21 @@ def generate_metainfo_code(metainfo_env: LegacyMetainfoEnvironment):
 
     def format_type(pkg, mi_type):
         if type(mi_type) == np.dtype:
+            if mi_type == np.dtype('U'):
+                return 'np.dtype(\'U\')'
+
             return 'np.dtype(np.%s)' % mi_type
+
         if mi_type in [int, float, str, bool]:
             return mi_type.__name__
+
         if isinstance(mi_type, Reference):
             if pkg == mi_type.target_section_def.m_parent:
                 return "Reference(SectionProxy('%s'))" % mi_type.target_section_def.name
 
             else:
-                python_pkg, _ = mi_type.target_section_def.m_parent.a_python
-                return '%s.%s' % (python_pkg.split('.')[-1], mi_type.target_section_def.name)
+                python_module = mi_type.target_section_def.m_parent.a_legacy.python_module
+                return '%s.%s' % (python_module.split('.')[-1], mi_type.target_section_def.name)
 
         else:
             return str(mi_type)
@@ -438,20 +509,24 @@ def generate_metainfo_code(metainfo_env: LegacyMetainfoEnvironment):
             if pkg == definition.m_parent:
                 return definition.name
             else:
-                python_pkg, _ = definition.m_parent.a_python
-                return '%s.%s' % (python_pkg.split('.')[-1], definition.name)
+                python_module = definition.m_parent.a_legacy.python_module
+                return '%s.%s' % (python_module.split('.')[-1], definition.name)
 
         return ', '.join([format_definition_ref(definition) for definition in definitions])
 
     def fromat_package_import(pkg):
-        python_package, _ = pkg.a_python
-        packages = python_package.split('.')
-        return 'from %s import %s' % ('.'.join(packages[:-1]), packages[-1])
+        python_module = pkg.a_legacy.python_module
+        modules = python_module.split('.')
+        return 'from %s import %s' % ('.'.join(modules[:-1]), modules[-1])
+
+    def order_categories(categories):
+        return sorted(categories, key=lambda c: len(c.categories))
 
     env = JinjaEnvironment(
         loader=PackageLoader('nomad.metainfo', 'templates'),
         autoescape=select_autoescape(['python']))
     env.globals.update(
+        order_categories=order_categories,
         format_description=format_description,
         format_type=format_type,
         format_unit=format_unit,
@@ -459,7 +534,7 @@ def generate_metainfo_code(metainfo_env: LegacyMetainfoEnvironment):
         fromat_package_import=fromat_package_import)
 
     for package in metainfo_env.packages:
-        _, path = package.a_python
+        path = package.a_legacy.python_path
         if not os.path.exists(os.path.dirname(path)):
             os.makedirs(os.path.dirname(path))
 
diff --git a/nomad/metainfo/metainfo.py b/nomad/metainfo/metainfo.py
index 4647ade4e3..46560c889b 100644
--- a/nomad/metainfo/metainfo.py
+++ b/nomad/metainfo/metainfo.py
@@ -265,6 +265,12 @@ class _QuantityType(DataType):
         if isinstance(value, Section):
             return value
 
+        if isinstance(value, Reference) and isinstance(value.target_section_def, MProxy):
+            proxy = value.target_section_def
+            proxy.m_proxy_section = section
+            proxy.m_proxy_quantity = quantity_def
+            return value
+
         if isinstance(value, DataType):
             return value
 
@@ -277,6 +283,8 @@ class _QuantityType(DataType):
                 return Reference(section)
 
         if isinstance(value, MProxy):
+            value.m_proxy_section = section
+            value.m_proxy_quantity = quantity_def
             return value
 
         raise MetainfoError(
@@ -399,6 +407,9 @@ class _Datetime(DataType):
         elif isinstance(value, (int, float)):
             value = datetime.fromtimestamp(value)
 
+        elif isinstance(value, pint.Quantity):
+            value = datetime.fromtimestamp(value.magnitude)
+
         if not isinstance(value, datetime):
             raise TypeError('%s is not a datetime.' % value)
 
@@ -475,18 +486,28 @@ def constraint(warning):
 
 
 class MResource():
-    '''Represents a collection of related metainfo data, i.e. a set of :class:`MSection` instances.
-
-    MResource allows to keep related objects together and resolve sections of certain
-    section definitions.
     '''
+    Represents a collection of related metainfo data, i.e. a set of :class:`MSection` instances.
+    '''
+
     def __init__(self):
         self.__data: Dict['Section', List['MSection']] = dict()
         self.contents: List['MSection'] = []
 
     def create(self, section_cls: Type[MSectionBound], *args, **kwargs) -> MSectionBound:
-        ''' Create an instance of the given section class and adds it to this resource. '''
+        '''
+        Create an instance of the given section class and adds it to this resource as
+        a root section. The m_parent_index will be set sequentially among root sections of
+        the same section definition starting with 0.
+        '''
+        index = 0
+        for content in self.contents:
+            if content.m_follows(section_cls.m_def):
+                index = max(index, content.m_parent_index + 1)
+
         result = section_cls(*args, **kwargs)
+        result.m_parent_index = index
+
         self.add(result)
         return cast(MSectionBound, result)
 
@@ -497,6 +518,8 @@ class MResource():
             self.contents.append(section)
 
     def remove(self, section):
+        import traceback
+        traceback.print_stack()
         assert section.m_resource == self, 'Can only remove section from the resource that contains it.'
         section.m_resource = None
         self.__data.get(section.m_def).remove(section)
@@ -516,6 +539,16 @@ class MResource():
 
         # TODO break actual references via quantities
 
+    def m_to_dict(self, filter: TypingCallable[['MSection'], bool] = None):
+        if filter is None:
+            def filter(_):  # pylint: disable=function-redefined
+                return True
+
+        return {
+            section.m_def.name: section.m_to_dict()
+            for section in self.contents
+            if filter(section)}
+
 
 class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclass of collections.abs.Mapping
     '''Base class for all section instances on all meta-info levels.
@@ -991,6 +1024,8 @@ class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclas
 
     def m_follows(self, definition: 'Section') -> bool:
         ''' Determines if this section's definition is or is derived from the given definition. '''
+        if not isinstance(definition, Section):
+            raise TypeError('%s is of class Section' % definition)
         return self.m_def == definition or definition in self.m_def.all_base_sections
 
     def m_to_dict(self, with_meta: bool = False, include_defaults: bool = False) -> Dict[str, Any]:
@@ -1192,6 +1227,26 @@ class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclas
         if include_self and depth_first:
             yield self
 
+    def m_traverse(self):
+        '''
+        Performs a depth-first traversal and yield tuples of section, property def,
+        parent index for all set properties.
+        '''
+        for key in self.__dict__:
+            property_def = self.m_def.all_properties.get(key)
+            if property_def is None:
+                continue
+
+            if isinstance(property_def, SubSection):
+                for sub_section in self.m_get_sub_sections(property_def):
+                    for i in sub_section.m_traverse():
+                        yield i
+
+                    yield self, property_def, sub_section.m_parent_index
+
+            else:
+                yield self, property_def, -1
+
     def m_pretty_print(self, indent=None):
         ''' Pretty prints the containment hierarchy '''
         if indent is None:
@@ -1282,6 +1337,9 @@ class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclas
 
             if isinstance(prop_def, SubSection):
                 if prop_def.repeats:
+                    if len(path_stack) == 0:
+                        return context.m_get_sub_sections(prop_def)  # type: ignore
+
                     try:
                         index = int(path_stack.pop())
                     except ValueError:
@@ -1306,7 +1364,11 @@ class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclas
             elif isinstance(prop_def, Quantity):
                 if len(path_stack) > 0:
                     raise ReferenceError(
-                        'Could not resolve %s, %s is not a sub section' % (path, prop_name))
+                        'Could not resolve %s, %s is not a property' % (path, prop_name))
+
+                if not context.m_is_set(prop_def):
+                    raise ReferenceError(
+                        'Could not resolve %s, %s is not set on %s' % (path, prop_name, context))
 
                 return context.m_get(prop_def)
 
@@ -1404,6 +1466,16 @@ class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclas
 
         return errors, warnings
 
+    def m_copy(self: MSectionBound) -> MSectionBound:
+        # TODO this a shallow copy, but should be a deep copy
+        copy = self.m_def.section_cls()
+        copy.__dict__.update(**self.__dict__)
+        copy.m_parent = None
+        copy.m_parent_index = -1
+        copy.m_parent_sub_section = None
+        copy.m_resource = None
+        return cast(MSectionBound, copy)
+
     def m_all_validate(self):
         ''' Evaluates all constraints in the whole section hierarchy, incl. this section. '''
         errors: List[str] = []
@@ -1428,8 +1500,11 @@ class MSection(metaclass=MObjectMeta):  # TODO find a way to make this a subclas
         return '%s:%s' % (name, m_section_name)
 
     def __getitem__(self, key):
-        key = key.replace('.', '/')
-        return self.m_resolve(key)
+        try:
+            key = key.replace('.', '/')
+            return self.m_resolve(key)
+        except ReferenceError:
+            raise KeyError()
 
     def __iter__(self):
         return self.m_def.all_properties.__iter__()
@@ -2418,6 +2493,6 @@ class Environment(MSection):
         if len(defs) == 1:
             return defs[0]
         elif len(defs) > 1:
-            raise KeyError('Could not uniquely identify %s' % name)
+            raise KeyError('Could not uniquely identify %s, candidates are %s' % (name, defs))
         else:
             raise KeyError('Could not resolve %s' % name)
diff --git a/nomad/metainfo/templates/environment.j2 b/nomad/metainfo/templates/environment.j2
index 36c874093c..013874f889 100644
--- a/nomad/metainfo/templates/environment.j2
+++ b/nomad/metainfo/templates/environment.j2
@@ -3,12 +3,12 @@ from nomad.metainfo import Environment
 from nomad.metainfo.legacy import LegacyMetainfoEnvironment
 
 {%- for package in env.packages %}
-import {{ package.a_python[0] }}
+import {{ package.a_legacy.python_module }}
 {%- endfor %}
 
 m_env = LegacyMetainfoEnvironment()
 
 {%- for package in env.packages %}
-m_env.m_add_sub_section(Environment.packages, sys.modules['{{ package.a_python[0] }}'].m_package)  # type: ignore
+m_env.m_add_sub_section(Environment.packages, sys.modules['{{ package.a_legacy.python_module }}'].m_package)  # type: ignore
 {%- endfor %}
 
diff --git a/nomad/metainfo/templates/package.j2 b/nomad/metainfo/templates/package.j2
index 731cb210f6..b6945e4b24 100644
--- a/nomad/metainfo/templates/package.j2
+++ b/nomad/metainfo/templates/package.j2
@@ -4,24 +4,30 @@ from nomad.metainfo import (  # pylint: disable=unused-import
     MSection, MCategory, Category, Package, Quantity, Section, SubSection, SectionProxy,
     Reference
 )
+from nomad.metainfo.legacy import LegacyDefinition
 {% for dependency in pkg.dependencies %}
 {{ fromat_package_import(dependency) }}
 {%- endfor %}
 
-m_package = Package(name='{{ pkg.name }}', description='{{ pkg.description }}')
-{% for category in pkg.category_definitions %}
+m_package = Package(
+    name='{{ pkg.name }}',
+    description='{{ pkg.description }}',
+    a_legacy=LegacyDefinition(name='{{pkg.a_legacy.name}}'))
+{% for category in order_categories(pkg.category_definitions) %}
 
 class {{ category.name }}(MCategory):
     {% if category.description is not none -%}
     '''
     {{ format_description(category.description, indent=1) }}
     '''
-    {% elif category.categories | length > 0 %}
-    m_def = Category(categories=[{{ format_definition_refs(pkg, category.categories) }}])
-    {% else %}
-    pass
-    {% endif %}
-{%- endfor -%}
+    {%- endif %}
+
+    m_def = Category(
+        {% if category.categories | length > 0 -%}
+        categories=[{{ format_definition_refs(pkg, category.categories) }}],
+        {% endif -%}
+        a_legacy=LegacyDefinition(name='{{category.a_legacy.name}}'))
+{% endfor -%}
 
 {% for section in pkg.section_definitions %}
 
@@ -31,7 +37,7 @@ class {{ section.name }}({%- if section.extends_base_section -%}{{ format_defini
     {{ format_description(section.description, indent=1) }}
     '''
     {% endif %}
-    m_def = Section(validate=False{%- if section.extends_base_section -%}, extends_base_section=True{%- endif -%})
+    m_def = Section(validate=False{%- if section.extends_base_section -%}, extends_base_section=True{%- endif -%}, a_legacy=LegacyDefinition(name='{{section.a_legacy.name}}'))
     {% for quantity in section.quantities %}
     {{ quantity.name }} = Quantity(
         type={{ format_type(pkg, quantity.type) }},
@@ -45,7 +51,8 @@ class {{ section.name }}({%- if section.extends_base_section -%}{{ format_defini
         '''{%- endif -%}
         {%- if quantity.categories | length > 0 -%},
         categories=[{{ format_definition_refs(pkg, quantity.categories) }}]
-        {%- endif -%})
+        {%- endif -%},
+        a_legacy=LegacyDefinition(name='{{quantity.a_legacy.name}}'))
     {% endfor -%}
 
     {%- for sub_section in section.sub_sections %}
@@ -55,7 +62,8 @@ class {{ section.name }}({%- if section.extends_base_section -%}{{ format_defini
         {%- if sub_section.description is not none -%},
         description='''
         {{ format_description(sub_section.description, indent=2) }}
-        '''{%- endif -%})
+        '''{%- endif -%},
+        a_legacy=LegacyDefinition(name='{{sub_section.a_legacy.name}}'))
     {% endfor -%}
 {%- endfor %}
 
diff --git a/nomad/normalizing/dos.py b/nomad/normalizing/dos.py
index e8e40b62f0..e2163b3f01 100644
--- a/nomad/normalizing/dos.py
+++ b/nomad/normalizing/dos.py
@@ -52,7 +52,7 @@ class DosNormalizer(Normalizer):
                     return
 
                 number_of_atoms = np.shape(atom_positions)[0]
-                unit_cell_volume = np.linalg.det(lattice_vectors)
+                unit_cell_volume = np.linalg.det(lattice_vectors.magnitude)
 
                 # Final quantities
                 dos_normed = dos / (number_of_atoms * unit_cell_volume)
diff --git a/nomad/normalizing/fhiaims.py b/nomad/normalizing/fhiaims.py
index 9c16617fd4..ba9867cf33 100644
--- a/nomad/normalizing/fhiaims.py
+++ b/nomad/normalizing/fhiaims.py
@@ -92,9 +92,12 @@ class FhiAimsBaseNormalizer(Normalizer):
         super().normalize(logger)
 
         for index in self._backend.get_sections('section_method'):
-            to_compare = self._backend.get_value(controlIn_basis_set, index)
-            if to_compare is None:
-                # not fhi aims data
+            try:
+                to_compare = self._backend.get_value(controlIn_basis_set, index)
+                if to_compare is None:
+                    # not fhi aims data
+                    continue
+            except KeyError:
                 continue
 
             matrix_hits_int = dict.fromkeys(pure_types_json, 0)
diff --git a/nomad/normalizing/normalizer.py b/nomad/normalizing/normalizer.py
index ea0d70f2bf..c621f0b56c 100644
--- a/nomad/normalizing/normalizer.py
+++ b/nomad/normalizing/normalizer.py
@@ -89,21 +89,19 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
         '''
         # Try to find a frame sequence, only first found is considered
         try:
-            frame_seq = self._backend['section_frame_sequence'][0]
-            sampling_method_idx = frame_seq['frame_sequence_to_sampling_ref']
-            sec_sampling_method = self._backend['section_sampling_method'][sampling_method_idx]
+            frame_seq = self._backend['section_frame_sequence'][-1]
+            sec_sampling_method = frame_seq['frame_sequence_to_sampling_ref']
             sampling_method = sec_sampling_method['sampling_method']
             frames = frame_seq['frame_sequence_local_frames_ref']
             if sampling_method == 'molecular_dynamics':
-                scc_idx = frames[0]
+                scc = frames[0]
             else:
-                scc_idx = frames[-1]
-            scc = self._backend['section_single_configuration_calculation'][scc_idx]
+                scc = frames[-1]
             return scc['single_configuration_calculation_to_system_ref']
         except Exception:
             pass
 
-        # If no frame sequences detected, try to find scc
+        # If no frame sequences detected, try use system of last scc
         try:
             sccs = self._backend['section_single_configuration_calculation']
             scc = sccs[-1]
@@ -111,9 +109,9 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
         except Exception:
             pass
 
-        # If no sccs exist, try to find systems
+        # If no sccs exist, use last system
         try:
-            systems = self._backend.get_sections('section_system')
+            systems = self._backend['section_system']
             return systems[-1]
         except Exception:
             pass
@@ -141,16 +139,15 @@ class SystemBasedNormalizer(Normalizer, metaclass=ABCMeta):
     def normalize(self, logger=None) -> None:
         super().normalize(logger)
 
-        all_systems = self._backend.get_sections('section_system')
-
         # Process representative system first
-        representative_system_idx = self.__representative_system()
-        if representative_system_idx is not None:
+        representative_system = self.__representative_system()
+        if representative_system is not None:
+            representative_system_idx = representative_system.m_parent_index
             self.logger.info('chose "representative" section system')
             self.__normalize_system(representative_system_idx, True, logger)
 
         # All the rest if requested
         if not self.only_representatives:
-            for g_index in all_systems:
-                if g_index != representative_system_idx:
-                    self.__normalize_system(g_index, False, logger)
+            for system in self._backend['section_system']:
+                if system != representative_system:
+                    self.__normalize_system(system.m_parent_index, False, logger)
diff --git a/nomad/normalizing/optimade.py b/nomad/normalizing/optimade.py
index 30bd8735b0..8f26c17093 100644
--- a/nomad/normalizing/optimade.py
+++ b/nomad/normalizing/optimade.py
@@ -130,4 +130,6 @@ class OptimadeNormalizer(SystemBasedNormalizer):
             return True
 
         except Exception as e:
+            import traceback
+            traceback.print_exc()
             self.logger.warn('could not acquire optimade data', exc_info=e)
diff --git a/nomad/normalizing/system.py b/nomad/normalizing/system.py
index 2bc0cd03ec..b8e8ce01b6 100644
--- a/nomad/normalizing/system.py
+++ b/nomad/normalizing/system.py
@@ -211,7 +211,7 @@ class SystemNormalizer(SystemBasedNormalizer):
                 n_atom_positions=len(atom_positions), n_atoms=atoms.get_number_of_atoms())
             return False
         try:
-            atoms.set_positions(1e10 * atom_positions)
+            atoms.set_positions(1e10 * atom_positions.magnitude)
         except Exception as e:
             self.logger.error(
                 'cannot use positions with ase atoms', exc_info=e, error=str(e))
@@ -228,7 +228,7 @@ class SystemNormalizer(SystemBasedNormalizer):
                 self.logger.error('no lattice vectors but periodicity', pbc=pbc)
         else:
             try:
-                atoms.set_cell(1e10 * np.array(lattice_vectors))
+                atoms.set_cell(1e10 * lattice_vectors.magnitude)
             except Exception as e:
                 self.logger.error(
                     'cannot use lattice_vectors with ase atoms', exc_info=e, error=str(e))
diff --git a/nomad/parsing/__init__.py b/nomad/parsing/__init__.py
index 5e9174b97a..f92d76016c 100644
--- a/nomad/parsing/__init__.py
+++ b/nomad/parsing/__init__.py
@@ -60,14 +60,13 @@ Parsers and calculation files are matched via regular expressions.
 .. autofunction:: nomad.parsing.match_parser
 
 Parsers in NOMAD-coe use a *backend* to create output. There are different NOMAD-coe
-basends. In nomad@FAIRDI, we only currently only use a single backed. A version of
-NOMAD-coe's *LocalBackend*. It stores all parser results in memory. The following
+basends. In nomad@FAIRDI, we only currently only use a single backed. The following
 classes provide a interface definition for *backends* as an ABC and a concrete implementation
-based on NOMAD-coe's *python-common* module.
+based on nomad@fairdi's metainfo:
 
 .. autoclass:: nomad.parsing.AbstractParserBackend
     :members:
-.. autoclass:: nomad.parsing.LocalBackend
+.. autoclass:: nomad.parsing.Backend
     :members:
 '''
 
@@ -78,12 +77,13 @@ import bz2
 import lzma
 import os.path
 
-from nomad import files, config
+from nomad import config
 
-from nomad.parsing.backend import AbstractParserBackend, LocalBackend, LegacyLocalBackend, JSONStreamWriter, BadContextURI, WrongContextState
-from nomad.parsing.metainfo import MetainfoBackend
-from nomad.parsing.parser import Parser, LegacyParser, VaspOutcarParser, BrokenParser, MissingParser, MatchingParser
-from nomad.parsing.artificial import TemplateParser, GenerateRandomParser, ChaosParser, EmptyParser
+from nomad.parsing.legacy import (
+    AbstractParserBackend, Backend, BackendError, BadContextUri, LegacyParser, VaspOutcarParser)
+from nomad.parsing.parser import Parser, BrokenParser, MissingParser, MatchingParser
+from nomad.parsing.artificial import (
+    TemplateParser, GenerateRandomParser, ChaosParser, EmptyParser)
 
 
 _compressions = {
@@ -95,7 +95,7 @@ _compressions = {
 encoding_magic = magic.Magic(mime_encoding=True)
 
 
-def match_parser(mainfile: str, upload_files: Union[str, files.StagingUploadFiles], strict=True) -> 'Parser':
+def match_parser(mainfile_path: str, strict=True) -> 'Parser':
     '''
     Performs parser matching. This means it take the given mainfile and potentially
     opens it with the given callback and tries to identify a parser that can parse
@@ -105,21 +105,15 @@ def match_parser(mainfile: str, upload_files: Union[str, files.StagingUploadFile
     and beginning file contents.
 
     Arguments:
-        mainfile: The upload relative path to the mainfile
-        upload_files: Either a :class:`files.StagingUploadFiles` object or a directory name.
-            Directory name + mainfile needs to point to the file.
+        mainfile_path: Path to the mainfile
         strict: Only match strict parsers, e.g. no artificial parsers for missing or empty entries.
 
     Returns: The parser, or None if no parser could be matched.
     '''
+    mainfile = os.path.basename(mainfile_path)
     if mainfile.startswith('.') or mainfile.startswith('~'):
         return None
 
-    if isinstance(upload_files, str):
-        mainfile_path = os.path.join(upload_files, mainfile)
-    else:
-        mainfile_path = upload_files.raw_file_object(mainfile).os_path
-
     with open(mainfile_path, 'rb') as f:
         compression, open_compressed = _compressions.get(f.read(3), (None, open))
 
diff --git a/nomad/parsing/artificial.py b/nomad/parsing/artificial.py
index fe85e9bf53..6830ae9a2b 100644
--- a/nomad/parsing/artificial.py
+++ b/nomad/parsing/artificial.py
@@ -27,16 +27,10 @@ import time
 import os
 import signal
 
-from nomadcore.local_meta_info import loadJsonFile, InfoKindEl
-import nomad_meta_info
+from nomad import metainfo
 
-from nomad.parsing.backend import LocalBackend
-from nomad.parsing.parser import Parser, MatchingParser
-
-
-file_dir = os.path.dirname(os.path.abspath(nomad_meta_info.__file__))
-meta_info_path = os.path.normpath(os.path.join(file_dir, 'vasp.nomadmetainfo.json'))
-meta_info_env, _ = loadJsonFile(filePath=meta_info_path, dependencyLoader=None, extraArgsHandling=InfoKindEl.ADD_EXTRA_ARGS, uri=None)
+from .legacy import Backend
+from .parser import Parser, MatchingParser
 
 
 class ArtificalParser(Parser):
@@ -46,7 +40,7 @@ class ArtificalParser(Parser):
         self.backend = None
 
     def init_backend(self):
-        self.backend = LocalBackend(metaInfoEnv=meta_info_env, debug=False)
+        self.backend = Backend(metainfo='vasp')
 
     @property
     def name(self):
@@ -57,8 +51,8 @@ class EmptyParser(MatchingParser):
     '''
     Implementation that produces an empty code_run
     '''
-    def run(self, mainfile: str, logger=None) -> LocalBackend:
-        backend = LocalBackend(metaInfoEnv=meta_info_env, debug=False)  # type: ignore
+    def run(self, mainfile: str, logger=None) -> Backend:
+        backend = Backend(metainfo='vasp')
         backend.openSection('section_run')
         backend.addValue('program_name', self.code_name)
         backend.closeSection('section_run', 0)
@@ -100,8 +94,8 @@ class TemplateParser(ArtificalParser):
             else:
                 value = self.transform_value(key, value)
                 if isinstance(value, list):
-                    shape = meta_info_env[key].get('shape')
-                    if shape is None or len(shape) == 0:
+                    quantity_def = self.backend.env.resolve_definition(key, metainfo.Quantity)
+                    if quantity_def.is_scalar:
                         for single_value in value:
                             self.backend.addValue(key, single_value, index)
                     else:
@@ -111,7 +105,7 @@ class TemplateParser(ArtificalParser):
 
         self.backend.closeSection(name, index)
 
-    def run(self, mainfile: str, logger=None) -> LocalBackend:
+    def run(self, mainfile: str, logger=None) -> Backend:
         # tell tests about received logger
         if logger is not None:
             logger.debug('received logger')
@@ -147,7 +141,7 @@ class ChaosParser(ArtificalParser):
             compression: str = None) -> bool:
         return filename.endswith('chaos.json')
 
-    def run(self, mainfile: str, logger=None) -> LocalBackend:
+    def run(self, mainfile: str, logger=None) -> Backend:
         self.init_backend()
 
         chaos_json = json.load(open(mainfile, 'r'))
@@ -243,7 +237,7 @@ class GenerateRandomParser(TemplateParser):
         else:
             return value
 
-    def run(self, mainfile: str, logger=None) -> LocalBackend:
+    def run(self, mainfile: str, logger=None) -> Backend:
         # tell tests about received logger
         if logger is not None:
             logger.debug('received logger')
diff --git a/nomad/parsing/backend.py b/nomad/parsing/backend.py
deleted file mode 100644
index 67c373c8ad..0000000000
--- a/nomad/parsing/backend.py
+++ /dev/null
@@ -1,608 +0,0 @@
-# Copyright 2018 Markus Scheidgen
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an"AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from typing import TextIO, Tuple, List, Any, Callable, Dict, Iterable
-from abc import ABCMeta, abstractmethod
-from io import StringIO
-import json
-import re
-import io
-
-from nomadcore.local_backend import LocalBackend as LegacyLocalBackend
-from nomadcore.local_backend import Section, Results
-
-from nomad.utils import get_logger
-from nomad.metainfo import MSection, Section as MI2Section
-
-logger = get_logger(__name__)
-
-ParserStatus = Tuple[str, List[str]]
-
-
-class DelegatingMeta(ABCMeta):
-    def __new__(meta, name, bases, dct):
-        abstract_method_names = frozenset.union(*(base.__abstractmethods__ for base in bases))
-        for name in abstract_method_names:
-            if name not in dct:
-                dct[name] = DelegatingMeta._make_delegator_method(name)
-
-        return super(DelegatingMeta, meta).__new__(meta, name, bases, dct)
-
-    @staticmethod
-    def _make_delegator_method(name):
-        def delegator(self, *args, **kwargs):
-            return getattr(self._delegate, name)(*args, **kwargs)
-        return delegator
-
-
-class BadContextURI(Exception):
-    pass
-
-
-class WrongContextState(Exception):
-    pass
-
-
-class AbstractParserBackend(metaclass=ABCMeta):
-    '''
-    This ABS provides the parser backend interface used by the NOMAD-coe parsers
-    and normalizers.
-    '''
-    @abstractmethod
-    def metaInfoEnv(self):
-        ''' Returns the meta info used by this backend. '''
-        pass
-
-    @abstractmethod
-    def startedParsingSession(
-            self, mainFileUri, parserInfo, parserStatus=None, parserErrors=None):
-        '''
-        Should be called when the parsing starts.
-        ParserInfo should be a valid json dictionary.
-        '''
-        pass
-
-    @abstractmethod
-    def finishedParsingSession(
-            self, parserStatus, parserErrors, mainFileUri=None, parserInfo=None,
-            parsingStats=None):
-        ''' Called when the parsing finishes. '''
-        pass
-
-    @abstractmethod
-    def openContext(self, contextUri: str):
-        ''' Open existing archive data to introduce new data into an existing section. '''
-        pass
-
-    @abstractmethod
-    def closeContext(self, contextUri: str):
-        ''' Close priorly opened existing archive data again. '''
-        pass
-
-    @abstractmethod
-    def openSection(self, metaName, parent_index=-1):
-        ''' Opens a new section and returns its new unique gIndex. '''
-        pass
-
-    @abstractmethod
-    def closeSection(self, metaName, gIndex):
-        '''
-        Closes the section with the given meta name and index. After this, no more
-        value can be added to this section.
-        '''
-        pass
-
-    @abstractmethod
-    def openNonOverlappingSection(self, metaName):
-        ''' Opens a new non overlapping section. '''
-        pass
-
-    @abstractmethod
-    def setSectionInfo(self, metaName, gIndex, references):
-        '''
-        Sets info values of an open section references should be a dictionary with the
-        gIndexes of the root sections this section refers to.
-        '''
-        pass
-
-    @abstractmethod
-    def closeNonOverlappingSection(self, metaName):
-        '''
-        Closes the current non overlapping section for the given meta name. After
-        this, no more value can be added to this section.
-        '''
-        pass
-
-    @abstractmethod
-    def openSections(self):
-        ''' Returns the sections that are still open as metaName, gIndex tuples. '''
-        pass
-
-    @abstractmethod
-    def addValue(self, metaName, value, gIndex=-1):
-        '''
-        Adds a json value for the given metaName. The gIndex is used to identify
-        the right parent section.
-        '''
-        pass
-
-    @abstractmethod
-    def addRealValue(self, metaName, value, gIndex=-1):
-        '''
-        Adds a float value for the given metaName. The gIndex is used to identify
-        the right parent section.
-        '''
-        pass
-
-    @abstractmethod
-    def addArray(self, metaName, shape, gIndex=-1):
-        '''
-        Adds an unannitialized array of the given shape for the given metaName.
-        The gIndex is used to identify the right parent section.
-        This is neccessary before array values can be set with :func:`setArrayValues`.
-        '''
-
-    @abstractmethod
-    def setArrayValues(self, metaName, values, offset=None, gIndex=-1):
-        '''
-        Adds values of the given numpy array to the last array added for the given
-        metaName and parent gIndex.
-        '''
-        pass
-
-    @abstractmethod
-    def addArrayValues(self, metaName, values, gIndex=-1, override: bool = False):
-        '''
-        Adds an array with the given numpy array values for the given metaName and
-        parent section gIndex. Override determines whether to rewrite exisiting values
-        in the backend.
-        '''
-        pass
-
-    @abstractmethod
-    def pwarn(self, msg):
-        ''' Used to catch parser warnings. '''
-        pass
-
-    # The following are extensions to the origin NOMAD-coe parser backend. And allow
-    # access to existing data
-
-    @property
-    @abstractmethod
-    def data(self) -> Results:
-        pass
-
-    @abstractmethod
-    def get_sections(self, meta_name: str, g_index: int = -1) -> List[int]:
-        ''' Return all gIndices for existing sections of the given meta_name and parent section index. '''
-        pass
-
-    @abstractmethod
-    def get_value(self, metaName: str, g_index=-1) -> Any:
-        '''
-        Return the value set to the given meta_name in its parent section of the given index.
-        An index of -1 (default) is only allowed if there is exactly one parent section.
-        '''
-        pass
-
-    def write_json(
-            self, out: TextIO, pretty=True, filter: Callable[[str, Any], Any] = None,
-            root_sections: List[str] = ['section_run', 'section_entry_info']):
-        ''' Writes the backend contents. '''
-        pass
-
-    def add_mi2_section(self, section: MSection):
-        ''' Allows to mix a metainfo2 style section into backend. '''
-        pass
-
-    def get_mi2_section(self, section_def: MI2Section):
-        ''' Allows to mix a metainfo2 style section into backend. '''
-        pass
-
-    def traverse(self, *args, **kwargs) -> Iterable[Tuple[str, str, Any]]:
-        ''' Traverses the backend data and yiels tuples with metainfo name, event type,
-        and value '''
-        pass
-
-
-class JSONStreamWriter():
-    START = 0
-    OBJECT = 1
-    ARRAY = 2
-    KEY_VALUE = 3
-
-    '''
-    A generator that allows to output JSON based on calling 'event' functions.
-    Its pure python and could be replaced by some faster implementation, e.g. yajl-py.
-    It uses standard json decode to write values. This allows to mix streaming with
-    normal encoding. Furthermore, this writer understands numpy values and encodes
-    them properly.
-
-    Arguments:
-        file: A file like to write to.
-        pretty: True to indent and use separators.
-
-    Raises:
-        AssertionError: If methods were called in a non JSON fashion. Call :func:`close`
-        to make sure everything was closed properly.
-    '''
-    def __init__(self, file, pretty=False):
-        self._fp = file
-        self._pretty = pretty
-
-        self._indent = ''  # the current indent
-        self._separators = ['']  # a stack of the next necessary separator
-        self._states = [JSONStreamWriter.START]  # a stack of what is currenty open
-
-    def _write(self, str):
-        self._fp.write(str)
-
-    def _write_seperator(self):
-        self._write(self._separators.pop())
-
-    def _seperator_with_newline(self, base=None):
-        pretty_ext = ('\n%s' % self._indent) if self._pretty else ''
-        if base is None:
-            return pretty_ext
-        else:
-            return '%s%s' % (base, pretty_ext)
-
-    def _open(self, open_char):
-        self._write_seperator()
-        self._write(open_char)
-        self._indent = '%s  ' % self._indent
-        self._separators.append(self._seperator_with_newline())
-
-    def _close(self, close_char):
-        self._separators.pop()
-        self._indent = self._indent[:-2]
-        self._write(self._seperator_with_newline())
-        self._write(close_char)
-        self._separators.append(self._seperator_with_newline(','))
-
-    def open_object(self):
-        assert self._states[-1] != JSONStreamWriter.OBJECT, "Cannot open object in object."
-        if self._states[-1] == JSONStreamWriter.KEY_VALUE:
-            self._states.pop()
-        self._open('{')
-        self._states.append(JSONStreamWriter.OBJECT)
-
-    def close_object(self):
-        assert self._states.pop() == JSONStreamWriter.OBJECT, "Can only close object in object."
-        self._close('}')
-
-    def open_array(self):
-        assert self._states[-1] != JSONStreamWriter.OBJECT, "Cannot open array in object."
-        if self._states[-1] == JSONStreamWriter.KEY_VALUE:
-            self._states.pop()
-        self._open('[')
-        self._states.append(JSONStreamWriter.ARRAY)
-
-    def close_array(self):
-        assert self._states.pop() == JSONStreamWriter.ARRAY, "Can only close array in array."
-        self._close(']')
-
-    def key_value(self, key, value):
-        self.key(key)
-        self.value(value)
-
-    def key(self, key: str):
-        assert self._states[-1] == JSONStreamWriter.OBJECT, "Key can only be in objects."
-        self._write_seperator()
-        json.dump(key, self._fp)
-        self._separators.append(': ' if self._pretty else ':')
-        self._states.append(JSONStreamWriter.KEY_VALUE)
-
-    @staticmethod
-    def _json_serializable_value(value):
-        if hasattr(value, 'tolist'):
-            # run tolist of pentential numpy array types
-            return value.tolist()
-
-        else:
-            return value
-
-    def write(self, str):
-        if self._pretty:
-            str = str.replace('\n', '\n%s' % self._indent)
-        self._fp.write(str)
-
-    def value(self, value):
-        assert self._states[-1] != JSONStreamWriter.OBJECT, "Values can not be in objects."
-        if self._states[-1] == JSONStreamWriter.KEY_VALUE:
-            self._states.pop()
-
-        self._write_seperator()
-        json.dump(
-            JSONStreamWriter._json_serializable_value(value), self,
-            indent=2 if self._pretty else 1,
-            separators=(', ', ': ') if self._pretty else (',', ':'))
-        self._separators.append(self._seperator_with_newline(','))
-
-    def close(self):
-        assert self._states[-1] == JSONStreamWriter.START, "Something was not closed."
-
-
-class LegacyParserBackend(AbstractParserBackend):
-    '''
-    Partial implementation of :class:`AbstractParserBackend` that implements some
-    methods that are independent from the core backend implementation.
-    '''
-    def __init__(self, logger):
-        self.logger = logger if logger is not None else get_logger(__name__)
-
-        self.reset_status()
-
-        # things that have no real purpos, but are required by some legacy code
-        self._unknown_attributes = {}
-        self._known_attributes = ['results']
-        self.fileOut = io.StringIO()
-
-    def startedParsingSession(
-            self, mainFileUri, parserInfo, parserStatus=None, parserErrors=None):
-        self.reset_status()
-
-    def finishedParsingSession(self, parserStatus, parserErrors, *args, **kwargs):
-        self._status = parserStatus
-        self._errors = parserErrors
-
-    def pwarn(self, msg):
-        self.logger.warn(msg)
-        if len(self._warnings) < 10:
-            self._warnings.append(msg)
-        elif len(self._warnings) == 10:
-            self._warnings.append('There are more warnings, check the processing logs.')
-
-    def _parse_context_uri(self, context_uri: str) -> Tuple[str, int]:
-        '''
-        Returns the last segment of the given context uri, i.e. the section that
-        constitutes the context.
-        '''
-        path_str = re.sub(r'^(nmd://[^/]+/[^/]+)?/', '', context_uri, count=1)
-        path = path_str.split('/')[::-1]  # reversed path via extended slice syntax
-
-        if len(path) == 0:
-            raise BadContextURI('Uri %s has not path.' % context_uri)
-
-        while len(path) > 0:
-            meta_name = path.pop()
-            potential_index = path[-1] if len(path) > 0 else 'none'
-            try:
-                index = int(potential_index)
-                path.pop()
-            except ValueError:
-                index = 0
-
-        return meta_name, index
-
-    @property
-    def status(self) -> ParserStatus:
-        ''' Returns status and potential errors. '''
-        return (self._status, self._errors)
-
-    def reset_status(self) -> None:
-        self._status = 'ParseSuccess'
-        self._errors = None
-        self._warnings: List[str] = []
-
-
-class LocalBackend(LegacyParserBackend, metaclass=DelegatingMeta):
-    '''
-    This implementation of :class:`AbstractParserBackend` is a extended version of
-    NOMAD-coe's ``LocalBackend`` that allows to write the results in an *archive*-style .json.
-    It can be used like the original thing, but also allows to output archive JSON
-    after parsing via :func:`write_json`.
-    '''
-    def __init__(self, *args, **kwargs):
-        logger = kwargs.pop('logger', None)
-        super().__init__(logger=logger)
-
-        self.domain = kwargs.pop('domain', None)
-        self._delegate = LegacyLocalBackend(*args, **kwargs)
-        self.mi2_data: Dict[str, MSection] = {}
-        self._open_context: Tuple[str, int] = None
-        self._context_section = None
-
-    def __getitem__(self, metaname):
-        return self.data[metaname]
-
-    def __getattr__(self, name):
-        ''' Support for unimplemented and unexpected methods. '''
-        if name not in self._known_attributes and self._unknown_attributes.get(name) is None:
-            self.logger.debug('Access of unexpected backend attribute/method', attribute=name)
-            self._unknown_attributes[name] = name
-
-        return getattr(self._delegate, name)
-
-    def add_mi2_section(self, section: MSection):
-        ''' Allows to mix a metainfo2 style section into backend. '''
-        self.mi2_data[section.m_def.name] = section
-
-    def get_mi2_section(self, section_def: MI2Section):
-        ''' Allows to mix a metainfo2 style section into backend. '''
-        return self.mi2_data.get(section_def.name, None)
-
-    def finishedParsingSession(self, *args, **kwargs):
-        super().finishedParsingSession(*args, **kwargs)
-        self._delegate.finishedParsingSession(*args, **kwargs)
-
-    def openSection(self, metaName: str, parent_index: int = -1) -> int:
-        if self._open_context is None:
-            return self._delegate.openSection(metaName, parent_index=parent_index)
-        else:
-            assert self._context_section is not None
-
-            child_sections = list()
-
-            def find_child_sections(section):
-                for subsections in section.subsections.values():
-                    for subsection in subsections:
-                        if subsection.name == metaName:
-                            child_sections.append(subsection)
-                        find_child_sections(subsection)
-
-            find_child_sections(self._context_section)
-
-            if len(child_sections) == 0:
-                return self._delegate.openSection(metaName)
-            elif len(child_sections) == 1:
-                index = child_sections[0].gIndex  # TODO  this also needs to be reversed, on closing sections
-                self._delegate.sectionManagers[metaName].lastSectionGIndex = index
-                return index
-            else:
-                raise WrongContextState(
-                    'You cannot re-open %s with multiple instances in the context.' % metaName)
-
-    def openContext(self, contextUri: str):
-        if self._open_context is not None:
-            raise WrongContextState('There is already an open context on this backend.')
-
-        meta_name, index = self._parse_context_uri(contextUri)
-        try:
-            section_manager = self._delegate.sectionManagers[meta_name]
-        except KeyError:
-            raise BadContextURI('The section %s does not exist.' % meta_name)
-
-        if section_manager.lastSectionGIndex < index:
-            raise BadContextURI(
-                'Last index of section %s is %d, cannot open %d.' %
-                (meta_name, section_manager.lastSectionGIndex, index))
-
-        self._context_section = section_manager.openSections[index]
-        self._open_context = meta_name, section_manager.lastSectionGIndex
-        section_manager.lastSectionGIndex = index
-
-    def closeContext(self, contextUri):
-        if self._open_context is None:
-            raise WrongContextState('There is no context to close on this backend.')
-
-        meta_name, old_index = self._open_context
-        context_meta_name, _ = self._parse_context_uri(contextUri)
-        if context_meta_name != meta_name:
-            raise BadContextURI(
-                '%d is not the URI that his context was opened with.' % contextUri)
-
-        self._delegate.sectionManagers[context_meta_name].lastSectionGIndex = old_index
-        self._open_context = None
-        self._context_section = None
-
-    @property
-    def data(self) -> Results:
-        return self._delegate.results
-
-    def _write(
-            self, json_writer: JSONStreamWriter, value: Any,
-            filter: Callable[[str, Any], Any] = None):
-
-        if isinstance(value, list):
-            if len(value) == 1 and isinstance(value[0], Section) and \
-                    not self._delegate.metaInfoEnv().infoKindEl(value[0].name).repeats:
-                self._write(json_writer, value[0], filter=filter)
-            else:
-                json_writer.open_array()
-                for item in value:
-                    self._write(json_writer, item, filter=filter)
-                json_writer.close_array()
-
-        elif isinstance(value, Section):
-            section = value
-            json_writer.open_object()
-            json_writer.key_value('_name', section.name)
-            json_writer.key_value('_gIndex', section.gIndex)
-
-            for name, value in section.items():
-                if filter is not None:
-                    value = filter(name, value)
-
-                if value is not None:
-                    json_writer.key(name)
-                    self._write(json_writer, value, filter=filter)
-
-            json_writer.close_object()
-
-        else:
-            json_writer.value(value)
-
-    def _obj(self, value: Any, filter: Callable[[str, Any], Any] = None) -> Any:
-        if isinstance(value, list):
-            if len(value) == 1 and isinstance(value[0], Section) and \
-                    not self._delegate.metaInfoEnv().infoKindEl(value[0].name).repeats:
-                return self._obj(value[0], filter=filter)
-            else:
-                return [self._obj(item, filter=filter) for item in value]
-
-        elif isinstance(value, Section):
-            section = value
-            obj = dict(_name=section.name, _gIndex=section.gIndex)
-            for name, value in section.items():
-                if filter is not None:
-                    value = filter(name, value)
-
-                if value is not None:
-                    obj[name] = self._obj(value, filter=filter)
-            return obj
-
-        else:
-            return JSONStreamWriter._json_serializable_value(value)
-
-    def write_json(
-            self, out: TextIO, pretty=True, filter: Callable[[str, Any], Any] = None,
-            root_sections: List[str] = ['section_run', 'section_entry_info']):
-        '''
-        Writes the results stored in the backend after parsing in an 'archive'.json
-        style format.
-
-        Arguments:
-            out: The file-like that is used to write the json to.
-            pretty: Format the json or not.
-            filter: Optional filter that takes metaname, value pairs and returns a new value.
-        '''
-        json_writer = JSONStreamWriter(out, pretty=pretty)
-        json_writer.open_object()
-
-        # TODO the root sections should be determined programatically
-        for root_section in root_sections:
-            json_writer.key(root_section)
-            try:
-                self._write(json_writer, self._delegate.results[root_section], filter=filter)
-            except LookupError:
-                # not all root_sections might be part of the backend
-                self._write(json_writer, {})
-                pass
-
-        for name, section in self.mi2_data.items():
-            json_writer.key_value(name, section.m_to_dict())
-
-        json_writer.close_object()
-        json_writer.close()
-
-    def traverse(self, *args, **kwargs):
-        return self._delegate.results.traverse(*args, **kwargs)
-
-    def __repr__(self):
-        def filter(name, value):
-            if name.startswith('section_'):
-                return value
-
-            if name.startswith('x_'):
-                return None
-
-            if getattr(value, 'tolist', None) or isinstance(value, list):
-                return '<some array>'
-            else:
-                return value
-
-        out = StringIO()
-        self.write_json(JSONStreamWriter(out), filter=filter)
-        return out.getvalue()
diff --git a/nomad/parsing/legacy.py b/nomad/parsing/legacy.py
new file mode 100644
index 0000000000..344e7678a4
--- /dev/null
+++ b/nomad/parsing/legacy.py
@@ -0,0 +1,592 @@
+# Copyright 2018 Markus Scheidgen
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an"AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+'''
+This module contains functionality to use old 'legacy' NOMAD CoE parsers with the
+new nomad@fairdi infrastructure. This covers aspects like the new metainfo, a unifying
+wrapper for parsers, parser logging, and a parser backend.
+'''
+
+from typing import Dict, List, Union, Any, Tuple, Type
+from abc import ABCMeta, abstractmethod
+import importlib
+import os.path
+import inspect
+from unittest.mock import patch
+import logging
+import glob
+import sys
+
+from nomadcore.local_meta_info import InfoKindEnv
+
+from nomad import utils, datamodel, config
+from nomad.metainfo import (
+    SubSection, Quantity, Section, Reference, MResource, MSection, MSectionBound, Property)
+from nomad.metainfo.legacy import (
+    LegacyMetainfoEnvironment, python_package_mapping, normalize_name)
+
+from .parser import MatchingParser
+
+logger = utils.get_logger(__name__)
+
+
+class BackendError(Exception):
+    pass
+
+
+class BadContextUri(Exception):
+    pass
+
+
+class AbstractParserBackend(metaclass=ABCMeta):
+    '''
+    This ABS provides the parser backend interface used by the NOMAD-coe parsers.
+    '''
+
+    @abstractmethod
+    def metaInfoEnv(self):
+        ''' Returns the meta info used by this backend. '''
+        pass
+
+    @abstractmethod
+    def startedParsingSession(
+            self, mainFileUri, parserInfo, parserStatus=None, parserErrors=None):
+        '''
+        Should be called when the parsing starts.
+        ParserInfo should be a valid json dictionary.
+        '''
+        pass
+
+    @abstractmethod
+    def finishedParsingSession(
+            self, parserStatus, parserErrors, mainFileUri=None, parserInfo=None,
+            parsingStats=None):
+        ''' Called when the parsing finishes. '''
+        pass
+
+    @abstractmethod
+    def openContext(self, contextUri: str):
+        ''' Open existing archive data to introduce new data into an existing section. '''
+        pass
+
+    @abstractmethod
+    def closeContext(self, contextUri: str):
+        ''' Close priorly opened existing archive data again. '''
+        pass
+
+    @abstractmethod
+    def openSection(self, metaName, parent_index=-1):
+        ''' Opens a new section and returns its new unique gIndex. '''
+        pass
+
+    @abstractmethod
+    def closeSection(self, metaName, gIndex):
+        '''
+        Closes the section with the given meta name and index. After this, no more
+        value can be added to this section.
+        '''
+        pass
+
+    @abstractmethod
+    def openNonOverlappingSection(self, metaName):
+        ''' Opens a new non overlapping section. '''
+        pass
+
+    @abstractmethod
+    def setSectionInfo(self, metaName, gIndex, references):
+        '''
+        Sets info values of an open section references should be a dictionary with the
+        gIndexes of the root sections this section refers to.
+        '''
+        pass
+
+    @abstractmethod
+    def closeNonOverlappingSection(self, metaName):
+        '''
+        Closes the current non overlapping section for the given meta name. After
+        this, no more value can be added to this section.
+        '''
+        pass
+
+    @abstractmethod
+    def openSections(self):
+        ''' Returns the sections that are still open as metaName, gIndex tuples. '''
+        pass
+
+    @abstractmethod
+    def addValue(self, metaName, value, gIndex=-1):
+        '''
+        Adds a json value for the given metaName. The gIndex is used to identify
+        the right parent section.
+        '''
+        pass
+
+    @abstractmethod
+    def addRealValue(self, metaName, value, gIndex=-1):
+        '''
+        Adds a float value for the given metaName. The gIndex is used to identify
+        the right parent section.
+        '''
+        pass
+
+    @abstractmethod
+    def addArray(self, metaName, shape, gIndex=-1):
+        '''
+        Adds an unannitialized array of the given shape for the given metaName.
+        The gIndex is used to identify the right parent section.
+        This is neccessary before array values can be set with :func:`setArrayValues`.
+        '''
+
+    @abstractmethod
+    def setArrayValues(self, metaName, values, offset=None, gIndex=-1):
+        '''
+        Adds values of the given numpy array to the last array added for the given
+        metaName and parent gIndex.
+        '''
+        pass
+
+    @abstractmethod
+    def addArrayValues(self, metaName, values, gIndex=-1, override: bool = False):
+        '''
+        Adds an array with the given numpy array values for the given metaName and
+        parent section gIndex. Override determines whether to rewrite exisiting values
+        in the backend.
+        '''
+        pass
+
+    @abstractmethod
+    def pwarn(self, msg):
+        ''' Used to catch parser warnings. '''
+        pass
+
+    # The following are extensions to the origin NOMAD-coe parser backend. And allow
+    # access to existing data
+
+    # @property
+    # @abstractmethod
+    # def data(self) -> Results:
+    #     pass
+
+    @abstractmethod
+    def get_sections(self, meta_name: str, g_index: int = -1) -> List[int]:
+        ''' Return all gIndices for existing sections of the given meta_name and parent section index. '''
+        pass
+
+    @abstractmethod
+    def get_value(self, metaName: str, g_index=-1) -> Any:
+        '''
+        Return the value set to the given meta_name in its parent section of the given index.
+        An index of -1 (default) is only allowed if there is exactly one parent section.
+        '''
+        pass
+
+    # def add_mi2_section(self, section: MSection):
+    #     ''' Allows to mix a metainfo2 style section into backend. '''
+    #     pass
+
+    # def get_mi2_section(self, section_def: MI2Section):
+    #     ''' Allows to mix a metainfo2 style section into backend. '''
+    #     pass
+
+    # def traverse(self, *args, **kwargs) -> Iterable[Tuple[str, str, Any]]:
+    #     ''' Traverses the backend data and yiels tuples with metainfo name, event type,
+    #     and value '''
+    #     pass
+
+    @abstractmethod
+    def __getitem__(self, key):
+        pass
+
+
+class Backend(AbstractParserBackend):
+    '''
+    A backend that uses the new metainfo to store all data.
+
+    Arguments:
+        metainfo: The main legacy metainfo package name or a legacy metainfo environment
+            instance.
+        logger: An optional logger.
+        domain: An optional domain name.
+
+    Attributes:
+        domain: The domain that this backend contains data for.
+        env: The metainfo environment (all available definitions).
+        resource: The metainfo resource that contains all data.
+        logger: A logger that can be used to log metainfo and backend operation related
+            warnings and errors.
+    '''
+
+    def __init__(self, metainfo: Union[str, InfoKindEnv], domain: str = None, logger=None):
+
+        if logger is None:
+            logger = utils.get_logger(__name__)
+        self.logger = logger
+        self.domain = domain if domain is not None else 'dft'  # TODO
+
+        if isinstance(metainfo, InfoKindEnv):
+            metainfo = metainfo.name
+
+        python_package_name, _ = python_package_mapping(metainfo)
+        python_package_name = '.'.join(python_package_name.split('.')[:-1])
+        python_module = importlib.import_module(python_package_name)
+        self.env: LegacyMetainfoEnvironment = getattr(python_module, 'm_env')
+        self.__legacy_env = None
+        self.resource = MResource()
+
+        self.__open_sections: Dict[Tuple[Section, int], MSection] = {}
+        self.strict = False  # TODO
+
+        self.reset_status()
+        # things that have no real purpose, but are required by some legacy code
+        # self._unknown_attributes = {}
+        # self._known_attributes = ['results']
+        # self.fileOut = io.StringIO()
+
+    def __getitem__(self, key):
+        property_def = self.resolve_definition(key, Property)
+        section_def = property_def.m_parent
+        if section_def.extends_base_section:
+            section_def = section_def.base_sections[0]
+
+        if isinstance(property_def, Quantity):
+            return self.__open_sections[(section_def, -1)].m_get(property_def)
+
+        elif isinstance(property_def, SubSection):
+            return self.__open_sections[(section_def, -1)].m_get_sub_sections(property_def)
+
+    def metaInfoEnv(self):
+        if self.__legacy_env is None:
+            self.__legacy_env = self.env.legacy_info_env()
+        return self.__legacy_env
+
+    def resolve_definition(self, name, section_cls: Type[MSectionBound]) -> MSectionBound:
+        return self.env.resolve_definition(normalize_name(name), section_cls)
+
+    def resolve_context(self, context_uri: str):
+        path = context_uri.strip('/').split('/')
+        path.reverse()
+        current = None
+        while len(path) > 0:
+            section = path.pop()
+            if len(path) == 0:
+                raise BadContextUri(context_uri)
+            index = int(path.pop())
+            if current is None:
+                section_def = self.resolve_definition(section, Section)
+                if section_def is None:
+                    raise BadContextUri(context_uri)
+                i = 0
+                for content in self.resource.contents:
+                    if content.m_follows(section_def):
+                        if i == index:
+                            current = content
+                            break
+
+                        i += 1
+
+            else:
+                sub_section_def = self.resolve_definition(section, SubSection)
+                if sub_section_def is None:
+                    raise BadContextUri(context_uri)
+                current = current.m_get_sub_section(sub_section_def, index)
+
+        if current is None:
+            raise BadContextUri(context_uri)
+
+        return current
+
+    def openContext(self, context_uri: str):
+        ''' Open existing archive data to introduce new data into an existing section. '''
+        section = self.resolve_context(context_uri)
+        self.__open(section)
+
+    def closeContext(self, context_uri: str):
+        ''' Close priorly opened existing archive data again. '''
+        section = self.resolve_context(context_uri)
+        self.__close(section)
+
+    def __open(self, section):
+        if section.m_parent_index != -1:
+            self.__open_sections[(section.m_def, section.m_parent_index)] = section
+
+        # here -1 meaning the last opened section
+        self.__open_sections[(section.m_def, -1)] = section
+
+    def __close(self, section):
+        # TODO
+        pass
+        # if section.m_parent_index != -1 and self.__open_sections.get((section.m_def, -1)) == section:
+        #     del(self.__open_sections[(section.m_def, -1)])
+        # del(self.__open_sections[(section.m_def, section.m_parent_index)])
+
+    def openSection(self, name, parent_index: int = -1):
+        '''
+        It will assume that there is a sub-section def with the given name.
+        It will use the latest opened section of the sub-sections parent as the parent
+        for the new section.
+        An Exception will be known root sections, e.g. 'section_run'.
+        '''
+        section_def = self.resolve_definition(name, Section)
+
+        if name in datamodel.root_sections:
+            section = self.resource.create(section_def.section_cls)
+
+        else:
+            sub_section_def = self.resolve_definition(name, SubSection)
+            parent_section_def = sub_section_def.m_parent_as(Section)
+            if parent_section_def.extends_base_section:
+                parent_section_def = parent_section_def.base_sections[0]
+
+            parent = self.__open_sections[(parent_section_def, parent_index)]
+            section = parent.m_create(section_def.section_cls, sub_section_def)
+
+        self.__open(section)
+        return section.m_parent_index
+
+    def get_open_section_for_quantity(self, name, g_index):
+        ''' Returns the open section that contains the quantity of the given name. '''
+
+        quantity_def = self.resolve_definition(name, Quantity)
+        section_def = quantity_def.m_parent_as(Section)
+        if section_def.extends_base_section:
+            section_def = section_def.base_sections[0]
+
+        section = self.__open_sections[(section_def, g_index)]
+
+        return section, quantity_def
+
+    def closeSection(self, name, g_index):
+        # TODO
+        if self.strict:
+            section_def = self.resolve_definition(name, Section)
+            section = self.__open_sections[(section_def, g_index)]
+            self.__close(section)
+
+    def openNonOverlappingSection(self, metaName):
+        return self.openSection(metaName)
+
+    def setSectionInfo(self, metaName, gIndex, references):
+        '''
+        Sets info values of an open section references should be a dictionary with the
+        gIndexes of the root sections this section refers to.
+        '''
+        # TODO might be necessary to make references work?
+        pass
+
+    def closeNonOverlappingSection(self, name):
+        return self.closeSection(name, -1)
+
+    def openSections(self):
+        ''' Returns the sections that are still open as metaName, gIndex tuples. '''
+        raise NotImplementedError()
+        # for section_def, sub_sections in self.open_sections_by_def:
+        #     for sub_section in sub_sections:
+        #         yield section_def.name, sub_section.m_parent_index
+
+    def addValue(self, name, value, g_index=-1):
+        section, quantity_def = self.get_open_section_for_quantity(name, g_index)
+        if isinstance(quantity_def.type, Reference):
+            # quantity is a reference
+            possible_targets = self.resource.all(quantity_def.type.target_section_def.section_cls)
+            referenced_target = None
+            for target in possible_targets:
+                if target.m_parent_index == value:
+                    referenced_target = target
+
+            if referenced_target is None:
+                raise BackendError('There is not section for the given reference index')
+
+            value = referenced_target
+
+        setattr(section, name, value)
+
+    def addRealValue(self, name, value, g_index=-1):
+        self.addValue(name, value, g_index)
+
+    def addArray(self, name, shape, g_index=-1):
+        '''
+        Adds an uninitialized array of the given shape for the given metaName.
+        The gIndex is used to identify the right parent section.
+        This is neccessary before array values can be set with :func:`setArrayValues`.
+        '''
+        raise NotImplementedError()
+
+    def setArrayValues(self, metaName, values, offset=None, gIndex=-1):
+        '''
+        Adds values of the given numpy array to the last array added for the given
+        metaName and parent gIndex.
+        '''
+        raise NotImplementedError()
+
+    def addArrayValues(self, name, values, gIndex=-1, override: bool = False):
+        '''
+        Adds an array with the given numpy array values for the given metaName and
+        parent section gIndex. Override determines whether to rewrite exisiting values
+        in the backend.
+        '''
+        section, quantity_def = self.get_open_section_for_quantity(name, gIndex)
+        if isinstance(quantity_def.type, Reference):
+            # quantity is a reference
+            possible_targets = self.resource.all(quantity_def.type.target_section_def.section_cls)
+            resolved_values = []
+            for value in values:
+                referenced_target = None
+                for target in possible_targets:
+                    if target.m_parent_index == value:
+                        referenced_target = target
+
+                if referenced_target is None:
+                    raise BackendError('There is not section for the given reference index')
+
+                resolved_values.append(referenced_target)
+            values = resolved_values
+
+        if self.strict and not override:
+            quantity_def = section.m_def.all_quantities[name]
+            assert not section.m_is_set(quantity_def)
+
+        setattr(section, name, values)
+
+    # The following are extensions to the origin NOMAD-coe parser backend. And allow
+    # access to existing data
+
+    def get_sections(self, meta_name: str, g_index: int = -1) -> List[int]:
+        ''' Return all gIndices for existing sections of the given meta_name and parent index. '''
+        section_def = self.resolve_definition(meta_name, Section)
+        return [
+            section.m_parent_index for section in self.resource.all(section_def.section_cls)
+            if g_index == -1 or section.m_parent.m_parent_index == g_index]
+
+    def get_value(self, meta_name: str, g_index=-1) -> Any:
+        '''
+        Return the value set to the given meta_name in its parent section of the given index.
+        An index of -1 (default) is only allowed if there is exactly one parent section.
+        '''
+        section, quantity_def = self.get_open_section_for_quantity(meta_name, g_index)
+        value = section.m_get(quantity_def)
+
+        if value is None:
+            raise KeyError()
+
+        if isinstance(quantity_def.type, Reference):
+            return value.m_parent_index
+
+        return value
+
+    def add_mi2_section(self, section: MSection):
+        self.resource.add(section)
+
+    def get_mi2_section(self, section_def: Section):
+        for content in self.resource.contents:
+            if content.m_def == section_def:
+                return content
+
+    def startedParsingSession(
+            self, mainFileUri, parserInfo, parserStatus=None, parserErrors=None):
+        self.reset_status()
+
+    def finishedParsingSession(
+            self, parserStatus, parserErrors, mainFileUri=None, parserInfo=None,
+            parsingStats=None):
+        self._status = parserStatus
+        self._errors = parserErrors
+
+    def addMatchTelemetry(self, match_telemetry, gIndex=-1):
+        # TODO
+        pass
+
+    def pwarn(self, msg):
+        self.logger.warn(msg)
+        if len(self._warnings) < 10:
+            self._warnings.append(msg)
+        elif len(self._warnings) == 10:
+            self._warnings.append('There are more warnings, check the processing logs.')
+
+    @property
+    def status(self) -> Tuple[str, List[str]]:
+        ''' Returns status and potential errors. '''
+        return (self._status, self._errors)
+
+    def reset_status(self) -> None:
+        self._status = 'ParseSuccess'
+        self._errors = None
+        self._warnings: List[str] = []
+
+
+class LegacyParser(MatchingParser):
+    '''
+    A parser implementation for legacy NOMAD-coe parsers. It assumes that parsers
+    are installed to the python environment.
+
+    Arguments:
+        parser_class_name: the main parser class that implements NOMAD-coe's
+        backend_factory: a callable that returns a backend, takes meta_info and logger as argument
+    '''
+    def __init__(self, parser_class_name: str, *args, backend_factory=None, **kwargs) -> None:
+        super().__init__(*args, **kwargs)
+
+        self.parser_class_name = parser_class_name
+        self.backend_factory = backend_factory
+
+    def run(self, mainfile: str, logger=None) -> Backend:
+        # TODO we need a homogeneous interface to parsers, but we dont have it right now.
+        # There are some hacks to distinguish between ParserInterface parser and simple_parser
+        # using hasattr, kwargs, etc.
+        def create_backend(meta_info):
+            if self.backend_factory is not None:
+                return self.backend_factory(meta_info, logger=logger)
+
+            return Backend(meta_info, logger=logger, domain=self.domain)
+
+        module_name = self.parser_class_name.split('.')[:-1]
+        parser_class = self.parser_class_name.split('.')[-1]
+        module = importlib.import_module('.'.join(module_name))
+        Parser = getattr(module, parser_class)
+
+        init_signature = inspect.getargspec(Parser.__init__)
+        kwargs = dict(backend=create_backend, log_level=logging.DEBUG, debug=True)
+        kwargs = {key: value for key, value in kwargs.items() if key in init_signature.args}
+
+        with utils.legacy_logger(logger):
+            self.parser = Parser(**kwargs)
+
+            with patch.object(sys, 'argv', []):
+                backend = self.parser.parse(mainfile)
+                os.chdir(config.fs.working_directory)
+
+            if backend is None or not hasattr(backend, 'status'):
+                backend = self.parser.parser_context.super_backend
+
+        return backend
+
+
+class VaspOutcarParser(LegacyParser):
+    '''
+    LegacyParser that only matches mailfiles, if there is no .xml in the
+    same directory, i.e. to use the VASP OUTCAR parser in absence of .xml
+    output file.
+    '''
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.name = 'parsers/vaspoutcar'
+
+    def is_mainfile(self, filename: str, *args, **kwargs) -> bool:
+        is_mainfile = super().is_mainfile(filename, *args, **kwargs)
+
+        if is_mainfile:
+            directory = os.path.dirname(filename)
+            if len(glob.glob('%s/*.xml*' % directory)) > 0:
+                return False
+
+        return is_mainfile
diff --git a/nomad/parsing/metainfo.py b/nomad/parsing/metainfo.py
deleted file mode 100644
index 5884345955..0000000000
--- a/nomad/parsing/metainfo.py
+++ /dev/null
@@ -1,321 +0,0 @@
-# Copyright 2018 Markus Scheidgen
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an"AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-from typing import List, Dict, Any, Tuple
-import json
-
-from nomadcore.local_backend import ParserEvent
-
-from nomad import utils, datamodel
-from nomad.metainfo import SubSection, Section, MSection, Quantity, MResource, Reference
-from nomad.metainfo.legacy import LegacyMetainfoEnvironment
-
-from .backend import LegacyParserBackend
-
-# TODO nonOverlappingSection should reopen (?)
-# TODO non repeat section should reopen existing (?)
-# TODO references are set by index in old metainfo
-
-
-class BackendError(Exception):
-    pass
-
-
-class MetainfoBackend(LegacyParserBackend):
-    ''' A backend that uses the new metainfo to store all data. '''
-
-    def __init__(self, env: LegacyMetainfoEnvironment, logger=None, domain: str = None, strict: bool = False):
-        super().__init__(logger=logger)
-        self.domain = domain if domain is not None else 'dft'  # TODO
-        self.env = env
-        self.legacy_env = env.legacy_info_env()
-        self.resource = MResource()
-
-        if logger is None:
-            logger = utils.get_logger(__name__)
-        self.logger = logger
-
-        self.strict = strict
-        self.__open_sections: Dict[Tuple[Section, int], MSection] = {}
-
-    def metaInfoEnv(self):
-        return self.legacy_env
-
-    def resolve_context(self, context_uri: str):
-        path = context_uri.strip('/').split('/')
-        path.reverse()
-        current = None
-        while len(path) > 0:
-            section = path.pop()
-            index = int(path.pop())
-            if current is None:
-                section_def = self.env.resolve_definition(section, Section)
-                if section_def is None:
-                    raise KeyError
-                current = self.resource.contents[index]
-                if current.m_def != section_def:
-                    raise KeyError
-            else:
-                sub_section_def = self.env.resolve_definition(section, SubSection)
-                if sub_section_def is None:
-                    raise KeyError
-                current = current.m_get_sub_section(sub_section_def, index)
-
-        return current
-
-    def openContext(self, context_uri: str):
-        ''' Open existing archive data to introduce new data into an existing section. '''
-        section = self.resolve_context(context_uri)
-        self.__open(section)
-
-    def closeContext(self, context_uri: str):
-        ''' Close priorly opened existing archive data again. '''
-        section = self.resolve_context(context_uri)
-        self.__close(section)
-
-    def __open(self, section):
-        if section.m_parent_index != -1:
-            self.__open_sections[(section.m_def, section.m_parent_index)] = section
-        self.__open_sections[(section.m_def, -1)] = section
-
-    def __close(self, section):
-        if section.m_parent_index != -1 and self.__open_sections.get((section.m_def, -1)) == section:
-            del(self.__open_sections[(section.m_def, -1)])
-        del(self.__open_sections[(section.m_def, section.m_parent_index)])
-
-    def openSection(self, name, parent_index: int = -1):
-        '''
-        It will assume that there is a sub-section def with the given name.
-        It will use the latest opened section of the sub-sections parent as the parent
-        for the new section.
-        An Exception will be known root sections, e.g. 'section_run'.
-        '''
-        section_def = self.env.resolve_definition(name, Section)
-
-        if name in datamodel.root_sections:
-            section = self.resource.create(section_def.section_cls)
-            section.m_parent_index = 0  # Some parsers and the caching backend requires that root sections have a gIndex of 0.
-        else:
-            sub_section_def = self.env.resolve_definition(name, SubSection)
-            parent_section_def = sub_section_def.m_parent_as(Section)
-            if parent_section_def.extends_base_section:
-                parent_section_def = parent_section_def.base_sections[0]
-            try:
-                parent = self.__open_sections[(parent_section_def, parent_index)]
-            except KeyError:
-                raise BackendError('No open parent section %s while opening %s' % (
-                    parent_section_def.name, name))
-            section = parent.m_create(section_def.section_cls, sub_section_def)
-
-        self.__open(section)
-        return section.m_parent_index
-
-    def get_open_section_for_quantity(self, name, g_index):
-        ''' Returns the open section that contains the quantity of the given name. '''
-
-        quantity_def = self.env.resolve_definition(name, Quantity)
-        section_def = quantity_def.m_parent_as(Section)
-        if section_def.extends_base_section:
-            section_def = section_def.base_sections[0]
-        try:
-            section = self.__open_sections[(section_def, g_index)]
-        except KeyError:
-            raise BackendError(
-                'Cannot access/modify %s. Parent section %s with g_index %d not open' % (
-                    name, section_def.name, g_index))
-
-        return section, quantity_def
-
-    def closeSection(self, name, g_index):
-        if self.strict:
-            section_def = self.env.resolve_definition(name, Section)
-            try:
-                section = self.__open_sections[(section_def, g_index)]
-                self.__close(section)
-            except KeyError:
-                raise BackendError(
-                    'Cannot close %s with g_index %d, it is not open' % (section_def.name, g_index))
-
-    def openNonOverlappingSection(self, metaName):
-        return self.openSection(metaName)
-
-    def setSectionInfo(self, metaName, gIndex, references):
-        '''
-        Sets info values of an open section references should be a dictionary with the
-        gIndexes of the root sections this section refers to.
-        '''
-        # TODO might be necessary to make references work?
-        pass
-
-    def closeNonOverlappingSection(self, name):
-        return self.closeSection(name, -1)
-
-    def openSections(self):
-        ''' Returns the sections that are still open as metaName, gIndex tuples. '''
-        raise NotImplementedError()
-        # for section_def, sub_sections in self.open_sections_by_def:
-        #     for sub_section in sub_sections:
-        #         yield section_def.name, sub_section.m_parent_index
-
-    def addValue(self, name, value, g_index=-1):
-        section, quantity_def = self.get_open_section_for_quantity(name, g_index)
-        if isinstance(quantity_def.type, Reference):
-            # quantity is a reference
-            possible_targets = self.resource.all(quantity_def.type.target_section_def.section_cls)
-            referenced_target = None
-            for target in possible_targets:
-                if target.m_parent_index == value:
-                    referenced_target = target
-
-            if referenced_target is None:
-                raise BackendError('There is not section for the given reference index')
-
-            value = referenced_target
-
-        setattr(section, name, value)
-
-    def addRealValue(self, name, value, g_index=-1):
-        self.addValue(name, value, g_index)
-
-    def addArray(self, name, shape, g_index=-1):
-        '''
-        Adds an unannitialized array of the given shape for the given metaName.
-        The gIndex is used to identify the right parent section.
-        This is neccessary before array values can be set with :func:`setArrayValues`.
-        '''
-        raise NotImplementedError()
-
-    def setArrayValues(self, metaName, values, offset=None, gIndex=-1):
-        '''
-        Adds values of the given numpy array to the last array added for the given
-        metaName and parent gIndex.
-        '''
-        raise NotImplementedError()
-
-    def addArrayValues(self, name, values, gIndex=-1, override: bool = False):
-        '''
-        Adds an array with the given numpy array values for the given metaName and
-        parent section gIndex. Override determines whether to rewrite exisiting values
-        in the backend.
-        '''
-        section, quantity_def = self.get_open_section_for_quantity(name, gIndex)
-        if isinstance(quantity_def.type, Reference):
-            # quantity is a reference
-            possible_targets = self.resource.all(quantity_def.type.target_section_def.section_cls)
-            resolved_values = []
-            for value in values:
-                referenced_target = None
-                for target in possible_targets:
-                    if target.m_parent_index == value:
-                        referenced_target = target
-
-                if referenced_target is None:
-                    raise BackendError('There is not section for the given reference index')
-
-                resolved_values.append(referenced_target)
-            values = resolved_values
-
-        if self.strict and not override:
-            quantity_def = section.m_def.all_quantities[name]
-            assert not section.m_is_set(quantity_def)
-
-        setattr(section, name, values)
-
-    # The following are extensions to the origin NOMAD-coe parser backend. And allow
-    # access to existing data
-
-    @property
-    def data(self):
-        raise NotImplementedError(
-            'This method does not make sense in the context of the new metainfo.')
-
-    def get_sections(self, meta_name: str, g_index: int = -1) -> List[int]:
-        ''' Return all gIndices for existing sections of the given meta_name and parent index. '''
-        section_def = self.env.resolve_definition(meta_name, Section)
-        return [
-            section.m_parent_index for section in self.resource.all(section_def.section_cls)
-            if g_index == -1 or section.m_parent.m_parent_index == g_index]
-
-    def get_value(self, meta_name: str, g_index=-1) -> Any:
-        '''
-        Return the value set to the given meta_name in its parent section of the given index.
-        An index of -1 (default) is only allowed if there is exactly one parent section.
-        '''
-        try:
-            quantity = self.env.resolve_definition(meta_name, Quantity)
-        except KeyError:
-            return None
-
-        section_def = quantity.m_parent_as(Section)
-        if section_def.extends_base_section:
-            section_def = section_def.base_sections[0]
-        value = None
-
-        for section in self.resource.all(section_def.section_cls):
-            if section.m_parent_index == g_index:
-                value = section.m_get(quantity)
-
-            if section_def.name in ['section_run', 'section_entry_info']:
-                value = section.m_get(quantity)
-
-        if value is None:
-            raise KeyError()
-
-        if isinstance(quantity.type, Reference):
-            return value.m_parent_index
-
-        return value
-
-    def add_mi2_section(self, section: MSection):
-        self.resource.add(section)
-
-    def get_mi2_section(self, section_def: Section):
-        for content in self.resource.contents:
-            if content.m_def == section_def:
-                return content
-
-    def write_json(self, out, pretty: bool = True, *args, **kwargs):
-        if pretty:
-            kwargs = dict(indent=2)
-        else:
-            kwargs = dict()
-        json.dump([section.m_to_dict(with_meta=True) for section in self.resource.contents], out, **kwargs)
-
-    def traverse(self, *args, **kwargs):
-        for content in self.resource.contents:
-            for section in content.m_all_contents():
-                yield section.m_def.name, ParserEvent.open_section, None
-                for quantity_def in section.m_def.all_quantities.values():
-                    if section.m_is_set(quantity_def):
-                        if len(quantity_def.shape) == 0:
-                            event = ParserEvent.add_value
-                        else:
-                            event = ParserEvent.add_array_value
-                        yield quantity_def.name, event, section.m_get(quantity_def)
-                yield section.m_def.name, ParserEvent.close_section, None
-
-    def startedParsingSession(
-            self, mainFileUri, parserInfo, parserStatus=None, parserErrors=None):
-        pass
-
-    def finishedParsingSession(
-            self, parserStatus, parserErrors, mainFileUri=None, parserInfo=None,
-            parsingStats=None):
-        pass
-
-    def addMatchTelemetry(self, match_telemetry, gIndex=-1):
-        pass
-
-    def pwarn(self, msg):
-        self.logger.warning(msg)
diff --git a/nomad/parsing/parser.py b/nomad/parsing/parser.py
index a05511960d..4abfbb33b5 100644
--- a/nomad/parsing/parser.py
+++ b/nomad/parsing/parser.py
@@ -14,18 +14,7 @@
 
 from typing import List
 from abc import ABCMeta, abstractmethod
-import sys
 import re
-import importlib
-import inspect
-from unittest.mock import patch
-import logging
-import os.path
-import os
-import glob
-
-from nomad import utils, config
-from nomad.parsing.backend import LocalBackend
 
 
 class Parser(metaclass=ABCMeta):
@@ -53,9 +42,9 @@ class Parser(metaclass=ABCMeta):
         pass
 
     @abstractmethod
-    def run(self, mainfile: str, logger=None) -> LocalBackend:
+    def run(self, mainfile: str, logger=None):
         '''
-        Runs the parser on the given mainfile. It uses :class:`LocalBackend` as
+        Runs the parser on the given mainfile. It uses :class:`Backend` as
         a backend. The meta-info access is handled by the underlying NOMAD-coe parser.
 
         Args:
@@ -63,7 +52,7 @@ class Parser(metaclass=ABCMeta):
             logger: A optional logger
 
         Returns:
-            The used :class:`LocalBackend` with status information and result data.
+            The used :class:`Backend` with status information and result data.
         '''
 
 
@@ -92,7 +81,7 @@ class BrokenParser(Parser):
 
         return False
 
-    def run(self, mainfile: str, logger=None) -> LocalBackend:
+    def run(self, mainfile: str, logger=None):
         raise Exception('Failed on purpose.')
 
 
@@ -160,73 +149,5 @@ class MissingParser(MatchingParser):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
 
-    def run(self, mainfile: str, logger=None) -> LocalBackend:
+    def run(self, mainfile: str, logger=None):
         raise Exception('The code %s is not yet supported.' % self.code_name)
-
-
-class LegacyParser(MatchingParser):
-    '''
-    A parser implementation for legacy NOMAD-coe parsers. It assumes that parsers
-    are installed to the python environment.
-
-    Arguments:
-        parser_class_name: the main parser class that implements NOMAD-coe's
-        backend_factory: a callable that returns a backend, takes meta_info and logger as argument
-    '''
-    def __init__(self, parser_class_name: str, *args, backend_factory=None, **kwargs) -> None:
-        super().__init__(*args, **kwargs)
-
-        self.parser_class_name = parser_class_name
-        self.backend_factory = backend_factory
-
-    def run(self, mainfile: str, logger=None) -> LocalBackend:
-        # TODO we need a homogeneous interface to parsers, but we dont have it right now.
-        # There are some hacks to distringuish between ParserInterface parser and simple_parser
-        # using hasattr, kwargs, etc.
-        def create_backend(meta_info):
-            if self.backend_factory is not None:
-                return self.backend_factory(meta_info, logger=logger)
-
-            return LocalBackend(meta_info, debug=False, logger=logger, domain=self.domain)
-
-        module_name = self.parser_class_name.split('.')[:-1]
-        parser_class = self.parser_class_name.split('.')[-1]
-        module = importlib.import_module('.'.join(module_name))
-        Parser = getattr(module, parser_class)
-
-        init_signature = inspect.getargspec(Parser.__init__)
-        kwargs = dict(backend=create_backend, log_level=logging.DEBUG, debug=True)
-        kwargs = {key: value for key, value in kwargs.items() if key in init_signature.args}
-
-        with utils.legacy_logger(logger):
-            self.parser = Parser(**kwargs)
-
-            with patch.object(sys, 'argv', []):
-                backend = self.parser.parse(mainfile)
-                os.chdir(config.fs.working_directory)
-
-            if backend is None or not hasattr(backend, 'status'):
-                backend = self.parser.parser_context.super_backend
-
-        return backend
-
-
-class VaspOutcarParser(LegacyParser):
-    '''
-    LegacyParser that only matches mailfiles, if there is no .xml in the
-    same directory, i.e. to use the VASP OUTCAR parser in absence of .xml
-    output file.
-    '''
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.name = 'parsers/vaspoutcar'
-
-    def is_mainfile(self, filename: str, *args, **kwargs) -> bool:
-        is_mainfile = super().is_mainfile(filename, *args, **kwargs)
-
-        if is_mainfile:
-            directory = os.path.dirname(filename)
-            if len(glob.glob('%s/*.xml*' % directory)) > 0:
-                return False
-
-        return is_mainfile
diff --git a/nomad/processing/data.py b/nomad/processing/data.py
index b5441025fa..54e2f7a273 100644
--- a/nomad/processing/data.py
+++ b/nomad/processing/data.py
@@ -39,7 +39,7 @@ import json
 from nomad import utils, config, infrastructure, search, datamodel
 from nomad.files import PathObject, UploadFiles, ExtractError, ArchiveBasedStagingUploadFiles, PublicUploadFiles, StagingUploadFiles
 from nomad.processing.base import Proc, process, task, PENDING, SUCCESS, FAILURE
-from nomad.parsing import parser_dict, match_parser, LocalBackend
+from nomad.parsing import parser_dict, match_parser, Backend
 from nomad.normalizing import normalizers
 
 
@@ -106,7 +106,7 @@ class Calc(Proc):
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
-        self._parser_backend: LocalBackend = None
+        self._parser_backend: Backend = None
         self._upload: Upload = None
         self._upload_files: ArchiveBasedStagingUploadFiles = None
         self._calc_proc_logwriter = None
@@ -187,7 +187,7 @@ class Calc(Proc):
         instead of creating it initially, we are just updating the existing
         records.
         '''
-        parser = match_parser(self.mainfile, self.upload_files, strict=False)
+        parser = match_parser(self.upload_files.raw_file_object(self.mainfile).os_path, strict=False)
 
         if parser is None and not config.reprocess_unmatched:
             # Remove the logsfile and set a fake logwriter to avoid creating a log file,
@@ -437,8 +437,10 @@ class Calc(Proc):
         with utils.timer(
                 logger, 'archived', step='archive',
                 input_size=self.mainfile_file.size) as log_data:
+
             with self.upload_files.archive_file(self.calc_id, 'wt') as out:
-                self._parser_backend.write_json(out, pretty=True, root_sections=datamodel.root_sections)
+                json.dump(self._parser_backend.resource.m_to_dict(
+                    lambda section: section.m_def.name in datamodel.root_sections), out, indent=2)
 
             log_data.update(archive_size=self.upload_files.archive_file_object(self.calc_id).size)
 
@@ -823,7 +825,7 @@ class Upload(Proc):
         for filename in upload_files.raw_file_manifest():
             self._preprocess_files(filename)
             try:
-                parser = match_parser(filename, upload_files)
+                parser = match_parser(upload_files.raw_file_object(filename).os_path)
                 if parser is not None:
                     directory = os.path.dirname(filename)
                     if directory in directories_with_match:
diff --git a/requirements.txt b/requirements.txt
index 80661f4a9d..62ad5f6d9a 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -39,7 +39,6 @@ zipstream-new==1.1.5
 bagit
 bcrypt
 filelock
-ujson==1.35
 bravado
 pyjwt[crypto]
 jsonschema[format]
diff --git a/tests/app/test_api.py b/tests/app/test_api.py
index df93878101..b00c82167d 100644
--- a/tests/app/test_api.py
+++ b/tests/app/test_api.py
@@ -38,7 +38,6 @@ from tests.test_files import example_file, example_file_mainfile, example_file_c
 from tests.test_files import create_staging_upload, create_public_upload, assert_upload_files
 from tests.test_search import assert_search_upload
 from tests.processing import test_data as test_processing
-from tests.utils import assert_exception
 
 from tests.app.test_app import BlueprintClient
 
@@ -700,7 +699,7 @@ class TestArchive(UploadFilesBasedTests):
 class TestRepo():
     @pytest.fixture(scope='class')
     def example_elastic_calcs(
-            self, elastic_infra, normalized: parsing.LocalBackend,
+            self, elastic_infra, normalized: parsing.Backend,
             test_user: User, other_test_user: User):
         clear_elastic(elastic_infra)
 
@@ -1174,10 +1173,10 @@ class TestEditRepo():
         Dataset.m_def.a_mongo.objects(name='new_ds').delete()
 
     @pytest.fixture(autouse=True)
-    def example_data(self, meta_info, class_api, test_user, other_test_user):
+    def example_data(self, class_api, test_user, other_test_user):
         def create_entry(id, user, **kwargs):
             metadata = dict(uploader=user.user_id, **kwargs)
-            create_test_structure(meta_info, id, 2, 1, [], 0, metadata=metadata)
+            create_test_structure(id, 2, 1, [], 0, metadata=metadata)
 
         entries = [
             dict(calc_id='1', upload_id='upload_1', user=test_user, published=True, with_embargo=False),
@@ -1354,7 +1353,7 @@ class TestEditRepo():
         assert rv.status_code == 200
         rv = self.perform_edit(datasets=[], query=dict(upload_id='upload_1'))
         assert rv.status_code == 200
-        with assert_exception(KeyError):
+        with pytest.raises(KeyError):
             assert Dataset.m_def.a_mongo.get(dataset_id=self.example_dataset.dataset_id) is None
 
     def test_edit_ds_user_namespace(self, test_user):
diff --git a/tests/app/test_optimade.py b/tests/app/test_optimade.py
index c531bbf350..9eaa4300aa 100644
--- a/tests/app/test_optimade.py
+++ b/tests/app/test_optimade.py
@@ -22,7 +22,6 @@ from nomad.app.optimade import parse_filter, url
 
 from tests.app.test_app import BlueprintClient
 from tests.conftest import clear_elastic, create_test_structure
-from tests.utils import assert_exception
 
 
 @pytest.fixture(scope='session')
@@ -34,14 +33,14 @@ def test_get_entry(published: Upload):
     calc_id = list(published.calcs)[0].calc_id
     with published.upload_files.archive_file(calc_id) as f:
         data = json.load(f)
-    assert 'OptimadeEntry' in data
+    assert 'OptimadeEntry' in data, data.keys()
     search_result = search.SearchRequest().search_parameter('calc_id', calc_id).execute_paginated()['results'][0]
     assert 'dft.optimade.chemical_formula_hill' in search.flat(search_result)
 
 
-def test_no_optimade(meta_info, mongo, elastic, api):
-    create_test_structure(meta_info, 1, 2, 1, [], 0)
-    create_test_structure(meta_info, 2, 2, 1, [], 0, optimade=False)
+def test_no_optimade(mongo, elastic, api):
+    create_test_structure(1, 2, 1, [], 0)
+    create_test_structure(2, 2, 1, [], 0, optimade=False)
     search.refresh()
 
     rv = api.get('/calculations')
@@ -52,14 +51,14 @@ def test_no_optimade(meta_info, mongo, elastic, api):
 
 
 @pytest.fixture(scope='module')
-def example_structures(meta_info, elastic_infra, mongo_infra):
+def example_structures(elastic_infra, mongo_infra):
     clear_elastic(elastic_infra)
     mongo_infra.drop_database('test_db')
 
-    create_test_structure(meta_info, 1, 2, 1, [], 0)
-    create_test_structure(meta_info, 2, 2, 1, ['C'], 0)
-    create_test_structure(meta_info, 3, 2, 1, [], 1)
-    create_test_structure(meta_info, 4, 1, 1, [], 0)
+    create_test_structure(1, 2, 1, [], 0)
+    create_test_structure(2, 2, 1, ['C'], 0)
+    create_test_structure(3, 2, 1, [], 1)
+    create_test_structure(4, 1, 1, [], 0)
     search.refresh()
 
     yield
@@ -127,7 +126,7 @@ def test_optimade_parser(example_structures, query, results):
         result = search.SearchRequest(query=query).execute_paginated()
         assert result['pagination']['total'] == results
     else:
-        with assert_exception():
+        with pytest.raises(Exception):
             query = parse_filter(query)
 
 
diff --git a/tests/conftest.py b/tests/conftest.py
index b5bbfe51e6..4b7731e150 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -31,12 +31,9 @@ import numpy as np
 import json
 import logging
 
-from nomadcore.local_meta_info import loadJsonFile
-import nomad_meta_info
-
 from nomad import config, infrastructure, parsing, processing, app, utils
 from nomad.datamodel import User, EntryMetadata
-from nomad.parsing import LocalBackend
+from nomad.parsing import Backend
 
 from tests import test_parsing, test_normalizing
 from tests.processing import test_data as test_processing
@@ -284,14 +281,6 @@ def proc_infra(worker, elastic, mongo, raw_files):
     return dict(elastic=elastic)
 
 
-@pytest.fixture(scope='session')
-def meta_info():
-    file_dir = os.path.dirname(os.path.abspath(nomad_meta_info.__file__))
-    path = os.path.join(file_dir, 'all.nomadmetainfo.json')
-    meta_info, _ = loadJsonFile(path)
-    return meta_info
-
-
 @pytest.fixture(scope='module')
 def test_user():
     return User(**test_users[test_user_uuid(1)])
@@ -535,21 +524,21 @@ def internal_example_user_metadata(example_user_metadata) -> dict:
 
 
 @pytest.fixture(scope='session')
-def parsed(example_mainfile: Tuple[str, str]) -> parsing.LocalBackend:
-    ''' Provides a parsed calculation in the form of a LocalBackend. '''
+def parsed(example_mainfile: Tuple[str, str]) -> parsing.Backend:
+    ''' Provides a parsed calculation in the form of a Backend. '''
     parser, mainfile = example_mainfile
     return test_parsing.run_parser(parser, mainfile)
 
 
 @pytest.fixture(scope='session')
-def parsed_ems() -> parsing.LocalBackend:
-    ''' Provides a parsed experiment in the form of a LocalBackend. '''
+def parsed_ems() -> parsing.Backend:
+    ''' Provides a parsed experiment in the form of a Backend. '''
     return test_parsing.run_parser('parsers/skeleton', 'tests/data/parsers/skeleton/example.metadata.json')
 
 
 @pytest.fixture(scope='session')
-def normalized(parsed: parsing.LocalBackend) -> parsing.LocalBackend:
-    ''' Provides a normalized calculation in the form of a LocalBackend. '''
+def normalized(parsed: parsing.Backend) -> parsing.Backend:
+    ''' Provides a normalized calculation in the form of a Backend. '''
     return test_normalizing.run_normalize(parsed)
 
 
@@ -648,7 +637,7 @@ def reset_infra(mongo, elastic):
 
 
 def create_test_structure(
-        meta_info, id: int, h: int, o: int, extra: List[str], periodicity: int,
+        id: int, h: int, o: int, extra: List[str], periodicity: int,
         optimade: bool = True, metadata: dict = None):
     ''' Creates a calculation in Elastic and Mongodb with the given properties.
 
@@ -668,7 +657,7 @@ def create_test_structure(
     atom_labels = ['H' for i in range(0, h)] + ['O' for i in range(0, o)] + extra
     test_vector = np.array([0, 0, 0])
 
-    backend = LocalBackend(meta_info, False, True)  # type: ignore
+    backend = Backend('public', False, True)  # type: ignore
     backend.openSection('section_run')
     backend.addValue('program_name', 'test_code')
     backend.openSection('section_system')
diff --git a/tests/data/parsers/template_no_system.json b/tests/data/parsers/template_no_system.json
index 05014c80b9..a4e8dca423 100644
--- a/tests/data/parsers/template_no_system.json
+++ b/tests/data/parsers/template_no_system.json
@@ -25,7 +25,6 @@
           {
             "_name": "section_single_configuration_calculation",
             "_gIndex": 0,
-            "single_configuration_calculation_to_system_ref": 0,
             "single_configuration_to_calculation_method_ref": 0,
             "energy_free": -1.5936767191492225e-18,
             "energy_total": -1.5935696296699573e-18,
diff --git a/tests/data/proc/examples_with_warning_template.zip b/tests/data/proc/examples_with_warning_template.zip
index 1de924997633e4afea4602609207322a03fc5145..2b01c74cd444803fbe60604aa7ea6e917bdd2301 100644
GIT binary patch
delta 1307
zcmZY9eLNF*9Ki8yX7d!Q#d?)&oKY!p(>!dVxk}Szip_GZ^AsyXYoQ0mouv@Ad6=Ch
zYIS8=4X<uu%+i&IbmXaBAtVpES`CMC+x5D??)TsK{r$dve}1Yh?pT<S0t~<=0R3y0
zb64!SE+!BGt}sl1<8n8ElzQSHfIy9n0R}=H3w3M_)GG|*9DX__Bv`j7(=E#Wy;tcr
z&JdAq7U^b7i?zCMjR4O%CrKnZRb#}b0P*bM_ldMynnc>^6jJ~YtOWu9VEtKZs5*WW
z3rii6!j{X7o?qrITHSn*BMC!QBN*9ssMs?z=*qCoZPP3+dpo)v5mdWPPLmw93&Lk%
zP91w3u4u%JB?SB0hZe7)-MChs+cdpPwa~X*1otPx3(5~;63i9bk=>q>akd%DMffr9
z30-Eea?(B3ny!$hBY3sK*TMl7UX?h@%maPX#=~Ez3m+@&@whOsz!8rxj;I>*V)mGl
z3qau2(ld<_Ha%-|r7S~^Iq8oYL7z?MEr9a4-@Q@K0sN<^>A5tH(Q846Ep#$@i+N>V
zUfIsGd+G6OuR2S#CEkAQcM;>Zmx$bLR!mt8q<Gq6r^YY$Zi1?M9N9dS)YY{f0f!xx
z{q38z{@Lb_>T*=Ezev2*jx!u>Pc&Z=@AY9XNO+8rv-OTS-&U8?f7q0i#OPI575o{C
z`kio;%@|3ZLHfMnI%+)9d=A1AwzSqUY9WIu(z<)vFX!zSH(X-R8J`bd#<~4$=^rbq
zVeQLvjo*@EwcE;-Iv7H(SQ&M-q!MVMx5<xu^XJ`E-sE-IKzeCMdceg|t@0rYax%JK
zFunC{M_?3qoaN)@H#P@s_R6O|1P_u^R=J<^EJTo=*5KhxrzoiB3H+<iRI$YM4W#AJ
zV@75Hk>X0b#-6!gEOu(Z5U3-l3I{(HlK|%^TfI1xZaN{m*I1mEeqhefOWQVo<-j5A
zcbjl7LC>lp>Iibmn&WL|W2u$53ZERDG`mcCx3MNUFsQ)_#LMvBZQ%9d&?d2awv44L
zMi14VDoaBLklo>}{3TrIf;$se`gE3J!S=p0&>q3w)6dsRuWI_0PRxtz-U@SOoz>eW
z;$Mf(KDp+w2r|yOzB9x}Xu035^SvPOhJ;UfF`21q$eoIeH>f#RaV&b7X;U8*(I1?T
z{uRSPNB8(spi&3s)B{^}FcPP@{O<Oy-Z4x!T5cWuNYuOUWl`;Z@8YIz;)`9>7RAJf
zixIn}vrF1RqTsK%SLb$R)WkV&n36ZNUhm})OPXbakX}J#q$5IV8vToZeNnygUMK1<
zXeP7|pk%;370BNzrm-2_t&@c4r_@hJ5KXkS^5oIDVJMnbotmnd%<R_|3$c5WBgl~@
zB3BI-)*g^p<uI0p*s;|8tY^ad$X`|LMNbDi*&7KT_n~ro26!XWZEuqZaB#StA{!>j
zQ%;o9-u{SOBFD-r7-~^Rwr~FG(yJfL?e9CqWv$Dqn83yOj$v*m=F!8jk1`$}w&k5G
zW6YNnI>_d^B@H=W94ji9O#7%wwVC@B?<u_TpU^Wy-<y0&ic*Rh8uDVGF?|Qv;4`VY
z@n!7j)K<0EjX<~|EGFbW$--(Cp_=vlCV6OMUT{Lf3Xl{41lbt;S0;XwAs(b}5}Xf%
zm;&Xx*_!VGL4ou^(whmW<trBHP#>eOsQQW;9qNmuNAUlu<OL;y^;P0ugd!m_LwyVX
E0S}{CcK`qY

delta 1307
zcmZ3-zm}gTz?+$civa`<Y@GOCWugHWd%NzG=zq3%COS$pf`lgfv$1n>GB9@ng*$a8
zPLu(Q3K;7pmR5v@042JC65T)vX{N(K^?Gc5Kz<*PFUl_hG?s&5!a5D#7dPI2WS<<)
zXj9*yF(rB#P(^74Hv=QfS4IW~7Lc-|5x4Umn+epO59g@!W4Wte+kN?+QYrV6uZw&G
zSy*)Y_qwPAs%oykeDq(nW@MR8*EW^wu78udpIFYBY3$th=j*Wv^EumH1ZF9RJ)8W#
z$NshB;UBkZPP1wpmprlZ+Ns-%e|}Bg*RnPyv0k=UtY@9%Ilc$?-#zyiKKqAFV)~M+
zLg#sWuAB3G-<J@UqGF;QbVJImQPMBiqj$bXT%NqW&5H`L8Nz)Q94hy^s*WoiwUmhe
zz_x=g;NoPF>vFmq862~mnXi{Kf4(t!?`_GB^Cguci_7MG*_h?9{nVz%6Sgi_nCjtH
zJV`+>VrEDEq=Ub&O@41*6Lj)hw5|Pu(3#iw7oHNe-o5SB+fa`@Q-Qg6+HZ>eJMi!0
zW7{e>|I6}fT#sgZ73NC64K%aM$j!0cKd0lL-=gm(dkp@`&br8zvO~jTpWAYYK&H$t
zgXboSMsHWI+4QgXc*F&sy^~_r_Dq!9f4S#-MB<IVr%vZE`Z(3c)N`mE<@V6tz04=w
zF}+qzSz~(pM#<=V0t`9bQ&e0Q)V5wPD4yWV+Fs<zt)(FTL?gX-`S1Iyr<g7~v!TgS
zq%Sp6EB0tb?<Q&WDeFE|wQPDE=ydkjizmmHiMorw7K!&<F8OG-vDaUID@*YgCK~to
zt<Ij5SUBgzmPL-Dt3^-kuAdZ8oD}h|-(tGaO|7{L1y|K3-FuN1XJXr0q@}-*VWs!F
zdvdk0$2?~h*Scpvo4YV?_NsN9s!JEFo*MIJ_Qbb4^D<fs6Id5AmzP=GaQ%0THAPuA
z%R&8YxZiY7r_Z91({rw$GyKE4*7L6Z$MpB%8=B)U+|Ainal_`{$1RHMSF_%$Kex@k
z`BeOKc6|lK1+VAt68HRm<khvdw{!RUPCh?jqRX;`tNlTKE|+=yZ|3+}EnOVjC!uqC
z$-a~22I&G>fy>tay)aj(eOZ;3<6Ko0?b&X-yzG6STuFCc79z1@p|C}$QKr|mOIJ6_
zgdB^z;(B-P79Zwq`!D(3a;)@f-6ww}P~?5RU1Dn6uE#(3WTw_I_FPz6lOAzu`;0wR
z3oof|sF}}jbw+S<y7_wU)cGE}=I%OJct&H>;saaX3N~3Ud)k)x<mkNXEMDTvxu?F|
z{KEe3pQ@jC-@D~Ma9536TU)#Hb<6dw=V$r(UKa^T7LQvTv+u)_PlvLuw%EL%^ejfI
z`uCTMy!*oHf6th(;B2hA|D&q`Oq^EFGImMZGCnzQEkEPvf})S-%>LfsJ*2QD`F6ML
z@sFutE>%4Xn3l6ouvy2X&evq|&3QX}i(RDXIaAr&oJ}4{Z*NRWpYxb!x=8w_y_4T>
z6#x5n(V}+lYd6a_v1!TQkY3cPAo;U;I#aW3q+#alH*5ZBDf*ivERpA`*dU!7GdH#R
z_?OH@3_($)++P*)1+tb#J7;};R<We&*EjwEZ$>6LW>~>A`2ed8Q#-Io5uTjK#>I4S
zBTztQvL%}W6R1D}334++#HInoKxGj`;bDm2XP_XcKoS-P8H!#gS+jdFHE4je%wp$b
K+sFzmj2HkTBvbSN

diff --git a/tests/metainfo/test_legacy.py b/tests/metainfo/test_legacy.py
index b0e7de7c1b..076641a347 100644
--- a/tests/metainfo/test_legacy.py
+++ b/tests/metainfo/test_legacy.py
@@ -17,12 +17,8 @@ import numpy as np
 
 from nomadcore.local_meta_info import InfoKindEl, InfoKindEnv
 
-from nomad.metainfo.metainfo import (
-    MSection, MCategory, Section, Quantity, SubSection, Definition, Package, DeriveError,
-    MetainfoError, Environment, MResource, Datetime, units, Annotation, SectionAnnotation,
-    DefinitionAnnotation, Reference, MProxy, derived)
+from nomad.metainfo.metainfo import Section, Quantity, SubSection
 from nomad.metainfo.legacy import LegacyMetainfoEnvironment, convert, python_package_mapping
-from nomad.parsing.metainfo import MetainfoBackend
 
 
 @pytest.fixture(scope='session')
@@ -82,9 +78,9 @@ def env(legacy_env):
         'nomad/datamodel/metainfo/common.py',
         'nomad.datamodel.metainfo.common'),
     (
-        'vasp_incars',
-        'dependencies/parsers/vasp/vaspparser/metainfo/vasp_incars.py',
-        'vaspparser.metainfo.vasp_incars')
+        'fhi_aims',
+        'dependencies/parsers/fhi-aims/fhiaimsparser/metainfo/fhi_aims.py',
+        'fhiaimsparser.metainfo.fhi_aims')
 ])
 def test_package_mapping(package, path, name):
     assert python_package_mapping(package) == (name, path)
@@ -106,37 +102,3 @@ def test_environment(env: LegacyMetainfoEnvironment, no_warn):
     assert env.resolve_definition('atom_positions', Quantity).type == np.dtype('float64')
     assert env.resolve_definition('bool_test', Quantity).type == bool
     assert env.resolve_definition('program_name', Quantity).m_parent.name == 'section_run'
-
-
-def test_backend(env, no_warn):
-    backend = MetainfoBackend(env)
-    run = backend.openSection('section_run')
-    backend.addValue('program_name', 'vasp')
-
-    system_0 = backend.openSection('section_system')
-    assert system_0 == 0
-
-    backend.addValue('number_of_atoms', 3)
-    backend.addArrayValues('atom_labels', np.array(['H', 'H', 'O']))
-    backend.addArrayValues('atom_positions', [[0, 0, 0], [0, 0, 0], [0, 0, 0]])
-    backend.closeSection('section_system', system_0)
-
-    system_1 = backend.openSection('section_system')
-    assert system_1 == 1
-    backend.closeSection('section_system', system_1)
-
-    method = backend.openSection('section_method')
-    backend.addValue('method_system_ref', system_0)
-    backend.closeSection('section_method', method)
-
-    backend.closeSection('section_run', run)
-
-    assert backend.get_sections('section_system') == [0, 1]
-    assert len(backend.get_value('atom_labels', 0)) == 3
-    assert backend.get_value('method_system_ref', 0) == 0
-    assert backend.get_value('program_name', 0) == 'vasp'
-
-    backend.openContext('section_run/0/section_system/1')
-    backend.addValue('number_of_atoms', 10)
-    backend.closeContext('section_run/0/section_system/1')
-    assert backend.get_value('number_of_atoms', 1) == 10
diff --git a/tests/metainfo/test_metainfo.py b/tests/metainfo/test_metainfo.py
index 8e957bd19d..78e1f68ff8 100644
--- a/tests/metainfo/test_metainfo.py
+++ b/tests/metainfo/test_metainfo.py
@@ -17,17 +17,11 @@ import numpy as np
 import pint.quantity
 import datetime
 
-from nomadcore.local_meta_info import InfoKindEl, InfoKindEnv
-
 from nomad.metainfo.metainfo import (
     MSection, MCategory, Section, Quantity, SubSection, Definition, Package, DeriveError,
     MetainfoError, Environment, MResource, Datetime, units, Annotation, SectionAnnotation,
     DefinitionAnnotation, Reference, MProxy, derived)
 from nomad.metainfo.example import Run, VaspRun, System, SystemHash, Parsing, SCC, m_package as example_package
-from nomad.metainfo.legacy import LegacyMetainfoEnvironment, convert
-from nomad.parsing.metainfo import MetainfoBackend
-
-from tests.utils import assert_exception
 
 
 def assert_section_def(section_def: Section):
@@ -182,7 +176,7 @@ class TestM2:
         class TestBase(MSection):
             name = Quantity(type=str)
 
-        with assert_exception(MetainfoError):
+        with pytest.raises(MetainfoError):
             class TestSection(TestBase):  # pylint: disable=unused-variable
                 name = Quantity(type=int)
 
@@ -190,7 +184,7 @@ class TestM2:
         class TestBase(MSection):
             name = Quantity(type=str)
 
-        with assert_exception(MetainfoError):
+        with pytest.raises(MetainfoError):
             class TestSection(TestBase):  # pylint: disable=unused-variable
                 m_def = Section(extends_base_section=True)
                 name = Quantity(type=int)
@@ -223,12 +217,12 @@ class TestM2:
         assert len(TestSection.m_def.warnings) > 0
 
     def test_higher_shapes_require_dtype(self):
-        with assert_exception(MetainfoError):
+        with pytest.raises(MetainfoError):
             class TestSection(MSection):  # pylint: disable=unused-variable
                 test = Quantity(type=int, shape=[3, 3])
 
     def test_only_extends_one_base(self):
-        with assert_exception(MetainfoError):
+        with pytest.raises(MetainfoError):
             class TestSection(Run, System):  # pylint: disable=unused-variable
                 m_def = Section(extends_base_section=True)
 
@@ -330,7 +324,7 @@ class TestM1:
         assert len(System().periodic_dimensions) == 3
         assert System().atom_labels is None
 
-        with assert_exception(AttributeError):
+        with pytest.raises(AttributeError):
             getattr(System(), 'does_not_exist')
 
     def test_m_section(self):
@@ -360,15 +354,15 @@ class TestM1:
         assert parsing.m_parent_index == -1
 
     def test_wrong_type(self):
-        with assert_exception(TypeError):
+        with pytest.raises(TypeError):
             Run().code_name = 1
 
     def test_wrong_shape_1(self):
-        with assert_exception(TypeError):
+        with pytest.raises(TypeError):
             Run().code_name = ['name']
 
     def test_wrong_shape_2(self):
-        with assert_exception(TypeError):
+        with pytest.raises(TypeError):
             System().atom_labels = 'label'
 
     def test_np_array(self):
@@ -396,7 +390,7 @@ class TestM1:
         system.lattice_vectors = [[1.2e-10, 0, 0], [0, 1.2e-10, 0], [0, 0, 1.2e-10]]
         assert isinstance(system.lattice_vectors, pint.quantity._Quantity)
         assert isinstance(system.unit_cell, pint.quantity._Quantity)
-        assert np.array_equal(system.unit_cell, system.lattice_vectors)
+        assert np.array_equal(system.unit_cell.magnitude, system.lattice_vectors.magnitude)
 
     @pytest.fixture(scope='function')
     def example_data(self):
@@ -438,7 +432,7 @@ class TestM1:
     def test_derived(self):
         system = System()
 
-        with assert_exception(DeriveError):
+        with pytest.raises(DeriveError):
             assert system.n_atoms == 3
 
         system.atom_labels = ['H', 'H', 'O']
@@ -493,7 +487,7 @@ class TestM1:
             two = SubSection(sub_section=System)
 
         test_section = TestSection()
-        with assert_exception():
+        with pytest.raises(Exception):
             test_section.m_create(System)
 
         test_section.m_create(System, TestSection.one)
@@ -524,7 +518,7 @@ class TestM1:
         scc.energy_total_0 = 1.0
         scc.an_int = 1
         assert scc.energy_total_0.m == 1.0  # pylint: disable=no-member
-        assert scc.energy_total_0.item() == 1.0  # pylint: disable=no-member
+        assert scc.energy_total_0 == 1.0 * units.J
         assert scc.m_to_dict()['energy_total_0'] == 1.0
         assert scc.an_int == 1
         assert scc.an_int.__class__ == np.int32
@@ -549,7 +543,7 @@ class TestM1:
         assert obj.m_resolve('/sub') == referenced
 
         obj.proxy = MProxy('doesnotexist', m_proxy_section=obj, m_proxy_quantity=ReferencingSection.proxy)
-        with assert_exception(ReferenceError):
+        with pytest.raises(ReferenceError):
             obj.proxy.name
 
         obj.proxy = MProxy('sub', m_proxy_section=obj, m_proxy_quantity=ReferencingSection.proxy)
diff --git a/tests/parser_measurement.py b/tests/parser_measurement.py
index 9cdefe1d24..fd613bd5f1 100644
--- a/tests/parser_measurement.py
+++ b/tests/parser_measurement.py
@@ -6,14 +6,14 @@ if __name__ == '__main__':
     from nomad.parsing import parser_dict
     from nomad.cli.parse import normalize_all
     from nomad.metainfo.legacy import LegacyMetainfoEnvironment
-    from nomad.parsing.metainfo import MetainfoBackend
+    from nomad.parsing.legacy import Backend
 
     mainfile_path = sys.argv[1]
     config.console_log_level = logging.CRITICAL
     utils.configure_logging()
 
     def backend_factory(env, logger):
-        return MetainfoBackend(LegacyMetainfoEnvironment(env), logger=logger)
+        return Backend(LegacyMetainfoEnvironment(env), logger=logger)
 
     logger = utils.get_logger(__name__)
     parser = parser_dict['parsers/vasp']
diff --git a/tests/processing/test_data.py b/tests/processing/test_data.py
index 2a2f401d14..0b666854f4 100644
--- a/tests/processing/test_data.py
+++ b/tests/processing/test_data.py
@@ -25,7 +25,6 @@ from nomad.files import UploadFiles, StagingUploadFiles, PublicUploadFiles
 from nomad.processing import Upload, Calc
 from nomad.processing.base import task as task_decorator, FAILURE, SUCCESS
 
-from tests import utils as test_utils
 from tests.test_search import assert_search_upload
 from tests.test_files import assert_upload_files
 
@@ -276,7 +275,7 @@ def test_re_processing(published: Upload, internal_example_user_metadata, monkey
 
     # assert changed archive files
     if with_failure in ['after', 'not-matched']:
-        with test_utils.assert_exception():
+        with pytest.raises(Exception):
             published.upload_files.archive_file(first_calc.calc_id)
     else:
         with published.upload_files.archive_file(first_calc.calc_id) as f:
@@ -284,7 +283,7 @@ def test_re_processing(published: Upload, internal_example_user_metadata, monkey
 
     # assert changed archive log files
     if with_failure in ['not-matched']:
-        with test_utils.assert_exception():
+        with pytest.raises(Exception):
             published.upload_files.archive_log_file(first_calc.calc_id)
     else:
         with published.upload_files.archive_log_file(first_calc.calc_id) as f:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index e55d309950..e36211ac1e 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -23,7 +23,6 @@ from nomad.cli import cli
 from nomad.processing import Upload, Calc
 
 from tests.app.test_app import BlueprintClient
-from tests.utils import assert_exception
 
 # TODO there is much more to test
 
@@ -79,7 +78,7 @@ class TestAdmin:
         assert published.upload_files.exists()
         assert calc.metadata['with_embargo']
         assert search.SearchRequest().owner('public').search_parameter('upload_id', upload_id).execute()['total'] == 0
-        with assert_exception():
+        with pytest.raises(Exception):
             files.UploadFiles.get(upload_id=upload_id).archive_file(calc_id=calc.calc_id)
 
         result = click.testing.CliRunner().invoke(
diff --git a/tests/test_datamodel.py b/tests/test_datamodel.py
index 2c7b581945..9605254fcd 100644
--- a/tests/test_datamodel.py
+++ b/tests/test_datamodel.py
@@ -123,11 +123,9 @@ def test_common_metainfo():
 
 def test_vasp_metainfo():
     from nomad.datamodel.metainfo import public
-
-    run = public.section_run()
-
-    assert 'vasp_src_date' not in run.m_def.all_quantities
     from vaspparser.metainfo import m_env  # pylint: disable=unused-import
+    run = public.section_run()
+    assert 'vasp_src_date' in run.m_def.all_quantities
 
 
 if __name__ == '__main__':
diff --git a/tests/test_files.py b/tests/test_files.py
index ce9d0cffa8..cb9a0a67ed 100644
--- a/tests/test_files.py
+++ b/tests/test_files.py
@@ -27,8 +27,6 @@ from nomad.files import DirectoryObject, PathObject
 from nomad.files import StagingUploadFiles, PublicUploadFiles, UploadFiles, Restricted, \
     ArchiveBasedStagingUploadFiles
 
-from tests.utils import assert_exception
-
 
 CalcWithFiles = Tuple[datamodel.EntryMetadata, str]
 UploadWithFiles = Tuple[str, Iterable[datamodel.EntryMetadata], UploadFiles]
@@ -456,7 +454,7 @@ class TestPublicUploadFiles(UploadFilesContract):
         upload_files.re_pack(entries)
         assert_upload_files(upload_id, entries, PublicUploadFiles, with_embargo=False)
         assert len(os.listdir(upload_files.os_path)) == 8
-        with assert_exception(KeyError):
+        with pytest.raises(KeyError):
             StagingUploadFiles(upload_files.upload_id)
 
 
diff --git a/tests/test_normalizing.py b/tests/test_normalizing.py
index 7393eff584..0c14eb61e1 100644
--- a/tests/test_normalizing.py
+++ b/tests/test_normalizing.py
@@ -18,13 +18,12 @@ from ase import Atoms
 import ase.build
 
 from nomad import datamodel, config
-from nomad.parsing import LocalBackend
+from nomad.parsing import Backend
 from nomad.normalizing import normalizers
 
 from tests.test_parsing import parsed_vasp_example  # pylint: disable=unused-import
 from tests.test_parsing import parsed_template_example  # pylint: disable=unused-import
 from tests.test_parsing import parsed_example  # pylint: disable=unused-import
-from tests.test_parsing import parsed_example_metainfo  # pylint: disable=unused-import
 from tests.test_parsing import parsed_template_no_system  # pylint: disable=unused-import
 from tests.test_parsing import parse_file
 from tests.utils import assert_log
@@ -83,7 +82,7 @@ map would be empty.
 '''
 
 
-def run_normalize(backend: LocalBackend) -> LocalBackend:
+def run_normalize(backend: Backend) -> Backend:
     status, _ = backend.status
 
     assert status == 'ParseSuccess'
@@ -95,12 +94,12 @@ def run_normalize(backend: LocalBackend) -> LocalBackend:
 
 
 @pytest.fixture
-def normalized_vasp_example(parsed_vasp_example: LocalBackend) -> LocalBackend:
+def normalized_vasp_example(parsed_vasp_example: Backend) -> Backend:
     return run_normalize(parsed_vasp_example)
 
 
 @pytest.fixture
-def normalized_example(parsed_example: LocalBackend) -> LocalBackend:
+def normalized_example(parsed_example: Backend) -> Backend:
     if parsed_example.domain != 'ems':
         return run_normalize(parsed_example)
 
@@ -108,11 +107,11 @@ def normalized_example(parsed_example: LocalBackend) -> LocalBackend:
 
 
 @pytest.fixture
-def normalized_template_example(parsed_template_example) -> LocalBackend:
+def normalized_template_example(parsed_template_example) -> Backend:
     return run_normalize(parsed_template_example)
 
 
-def run_normalize_for_structure(atoms: Atoms) -> LocalBackend:
+def run_normalize_for_structure(atoms: Atoms) -> Backend:
     template = parsed_template_no_system()
 
     # Fill structural information
@@ -127,12 +126,12 @@ def run_normalize_for_structure(atoms: Atoms) -> LocalBackend:
 
 
 @pytest.fixture(scope='session')
-def single_point(two_d) -> LocalBackend:
+def single_point(two_d) -> Backend:
     return two_d
 
 
 @pytest.fixture(scope='session')
-def geometry_optimization() -> LocalBackend:
+def geometry_optimization() -> Backend:
     parser_name = "parsers/template"
     filepath = "tests/data/normalizers/fcc_crystal_structure.json"
     backend = parse_file((parser_name, filepath))
@@ -141,12 +140,12 @@ def geometry_optimization() -> LocalBackend:
 
 
 @pytest.fixture(scope='session')
-def molecular_dynamics(bulk) -> LocalBackend:
+def molecular_dynamics(bulk) -> Backend:
     return bulk
 
 
 @pytest.fixture(scope='session')
-def phonon() -> LocalBackend:
+def phonon() -> Backend:
     parser_name = "parsers/phonopy"
     filepath = "tests/data/parsers/phonopy/phonopy-FHI-aims-displacement-01/control.in"
     backend = parse_file((parser_name, filepath))
@@ -155,7 +154,7 @@ def phonon() -> LocalBackend:
 
 
 @pytest.fixture(scope='session')
-def bulk() -> LocalBackend:
+def bulk() -> Backend:
     parser_name = "parsers/cp2k"
     filepath = "tests/data/normalizers/cp2k_bulk_md/si_md.out"
     backend = parse_file((parser_name, filepath))
@@ -164,7 +163,7 @@ def bulk() -> LocalBackend:
 
 
 @pytest.fixture(scope='session')
-def two_d() -> LocalBackend:
+def two_d() -> Backend:
     parser_name = "parsers/fhi-aims"
     filepath = "tests/data/normalizers/fhiaims_2d_singlepoint/aims.out"
     backend = parse_file((parser_name, filepath))
@@ -173,7 +172,7 @@ def two_d() -> LocalBackend:
 
 
 @pytest.fixture(scope='session')
-def surface() -> LocalBackend:
+def surface() -> Backend:
     parser_name = "parsers/fhi-aims"
     filepath = "tests/data/normalizers/fhiaims_surface_singlepoint/PBE-light+tight-rho2.out"
     backend = parse_file((parser_name, filepath))
@@ -182,7 +181,7 @@ def surface() -> LocalBackend:
 
 
 @pytest.fixture(scope='session')
-def molecule() -> LocalBackend:
+def molecule() -> Backend:
     parser_name = "parsers/fhi-aims"
     filepath = "tests/data/normalizers/fhiaims_molecule_singlepoint/aims.out"
     backend = parse_file((parser_name, filepath))
@@ -191,7 +190,7 @@ def molecule() -> LocalBackend:
 
 
 @pytest.fixture(scope='session')
-def atom() -> LocalBackend:
+def atom() -> Backend:
     parser_name = "parsers/gaussian"
     filepath = "tests/data/normalizers/gaussian_atom_singlepoint/m9b7.out"
     backend = parse_file((parser_name, filepath))
@@ -200,7 +199,7 @@ def atom() -> LocalBackend:
 
 
 @pytest.fixture(scope='session')
-def one_d() -> LocalBackend:
+def one_d() -> Backend:
     parser_name = "parsers/exciting"
     filepath = "tests/data/normalizers/exciting_1d_singlepoint/INFO.OUT"
     backend = parse_file((parser_name, filepath))
@@ -212,7 +211,7 @@ def test_template_example_normalizer(parsed_template_example, no_warn, caplog):
     run_normalize(parsed_template_example)
 
 
-def assert_normalized(backend: LocalBackend):
+def assert_normalized(backend: Backend):
     metadata = datamodel.EntryMetadata(domain=backend.domain)
     metadata.apply_domain_metadata(backend)
     assert metadata.formula is not None
@@ -242,15 +241,10 @@ def assert_normalized(backend: LocalBackend):
         assert metadata[key] != config.services.unavailable_value, '%s must not be unavailable' % key
 
 
-def test_normalizer(normalized_example: LocalBackend):
+def test_normalizer(normalized_example: Backend):
     assert_normalized(normalized_example)
 
 
-def test_normalizer_metainfo(parsed_example_metainfo):
-    if parsed_example_metainfo.domain != 'ems':
-        assert_normalized(run_normalize(parsed_example_metainfo))
-
-
 def test_normalizer_faulty_matid(caplog):
     ''' Runs normalizer on an example w/ bools for atom pos. Should force matid error.'''
     backend = parse_file(boolean_positions)
@@ -322,21 +316,20 @@ def test_representative_systems(single_point, molecular_dynamics, geometry_optim
         except KeyError:
             sccs = backend["section_single_configuration_calculation"]
             scc = sccs[-1]
-            repr_system_idx = scc["single_configuration_calculation_to_system_ref"]
+            repr_system = scc["single_configuration_calculation_to_system_ref"]
         else:
             sampling_method = backend["sampling_method"]
             if sampling_method == "molecular_dynamics":
-                idx = 0
+                scc = frames[0]
             else:
-                idx = -1
-            scc_idx = frames[idx]
-            scc = backend["section_single_configuration_calculation"][scc_idx]
-            repr_system_idx = scc["single_configuration_calculation_to_system_ref"]
+                scc = frames[-1]
+
+            repr_system = scc["single_configuration_calculation_to_system_ref"]
 
         # Check that only the representative system has been labels with
         # "is_representative"
-        for i, system in enumerate(backend["section_system"]):
-            if i == repr_system_idx:
+        for system in backend["section_system"]:
+            if system == repr_system:
                 assert system["is_representative"] is True
             else:
                 with pytest.raises(KeyError):
diff --git a/tests/test_parsing.py b/tests/test_parsing.py
index 2e0025ed10..adce1e2da6 100644
--- a/tests/test_parsing.py
+++ b/tests/test_parsing.py
@@ -20,9 +20,7 @@ import os
 from shutil import copyfile
 
 from nomad import utils, files
-from nomad.metainfo.legacy import convert
-from nomad.parsing import JSONStreamWriter, parser_dict, match_parser, BrokenParser
-from nomad.parsing import LocalBackend, BadContextURI, MetainfoBackend
+from nomad.parsing import parser_dict, match_parser, BrokenParser, BadContextUri, Backend
 
 
 parser_examples = [
@@ -83,14 +81,15 @@ parser_examples = fixed_parser_examples
 correct_num_output_files = 50
 
 
-class TestLocalBackend(object):
+class TestBackend(object):
 
     @pytest.fixture(scope='function')
-    def backend(self, meta_info):
-        return LocalBackend(meta_info, debug=True)
+    def backend(self):
+        return Backend('common')
 
-    def test_meta_info(self, meta_info, no_warn):
-        assert 'section_topology' in meta_info
+    def test_meta_info(self, no_warn):
+        from nomad.datamodel.metainfo import m_env
+        assert 'section_topology' in m_env.all_definitions_by_name
 
     def test_section(self, backend, no_warn):
         g_index = backend.openSection('section_run')
@@ -126,15 +125,15 @@ class TestLocalBackend(object):
         backend.closeNonOverlappingSection('section_system')
 
         backend.openNonOverlappingSection('section_system')
-        assert backend.openSection('section_symmetry') == 1
-        backend.closeSection('section_symmetry', 1)
+        assert backend.openSection('section_symmetry') == 0
+        backend.closeSection('section_symmetry', 0)
         backend.closeNonOverlappingSection('section_system')
 
         assert backend.get_sections('section_system') == [0, 1, 2]
-        assert backend.get_sections('section_symmetry') == [0, 1]
+        assert backend.get_sections('section_symmetry') == [0, 0]
         assert backend.get_sections('section_symmetry', 0) == [0]
         assert backend.get_sections('section_symmetry', 1) == []
-        assert backend.get_sections('section_symmetry', 2) == [1]
+        assert backend.get_sections('section_symmetry', 2) == [0]
 
     def test_section_override(self, backend, no_warn):
         ''' Test whether we can overwrite values already in the backend.'''
@@ -146,9 +145,7 @@ class TestLocalBackend(object):
         backend.closeSection('section_system', 0)
 
         backend.closeSection('section_run', 0)
-        output = StringIO()
-        backend.write_json(output)
-        assert backend.get_value('atom_labels').tolist() == expected_value
+        assert backend.get_value('atom_labels') == expected_value
 
     def test_two_sections(self, backend, no_warn):
         g_index = backend.openSection('section_run')
@@ -165,12 +162,12 @@ class TestLocalBackend(object):
         assert backend.get_sections('section_entry_info') == [0]
 
         output = StringIO()
-        backend.write_json(output)
+        json.dump(backend.resource.m_to_dict(), output)
         archive = json.loads(output.getvalue())
         assert 'section_run' in archive
         assert 'section_entry_info' in archive
 
-    def test_subsection(self, backend: LocalBackend, no_warn):
+    def test_subsection(self, backend: Backend, no_warn):
         backend.openSection('section_run')
         backend.openSection('section_method')
         backend.closeSection('section_method', -1)
@@ -185,12 +182,13 @@ class TestLocalBackend(object):
         backend.openSection('section_method')
         backend.closeSection('section_method', -1)
 
-        runs = backend.data['section_run']
+        from nomad.datamodel.metainfo.public import section_run
+        runs = backend.resource.all(section_run)
         assert len(runs) == 2
         assert len(runs[0]['section_method']) == 2
         assert len(runs[1]['section_method']) == 1
 
-    def test_open_section_of_specific_parent(self, backend: LocalBackend, no_warn):
+    def test_open_section_of_specific_parent(self, backend: Backend, no_warn):
         run_index = backend.openSection('section_run')
         scc_index = backend.openSection('section_single_configuration_calculation')
         backend.closeSection('section_single_configuration_calculation', scc_index)
@@ -198,14 +196,15 @@ class TestLocalBackend(object):
         backend.closeSection('section_dos', dos_index)
         backend.closeSection('section_run', run_index)
 
-        runs = backend.data['section_run']
+        from nomad.datamodel.metainfo.public import section_run
+        runs = backend.resource.all(section_run)
         assert len(runs) == 1
         run = runs[0]
         assert len(run['section_single_configuration_calculation']) == 1
         assert 'section_dos' in run['section_single_configuration_calculation'][0]
         assert len(run['section_single_configuration_calculation'][0]['section_dos']) == 1
 
-    def test_open_section_of_specific_parent2(self, backend: LocalBackend, no_warn):
+    def test_open_section_of_specific_parent2(self, backend: Backend, no_warn):
         run_index = backend.openSection('section_run')
         scc_index = backend.openSection('section_single_configuration_calculation')
         backend.closeSection('section_single_configuration_calculation', scc_index)
@@ -218,15 +217,15 @@ class TestLocalBackend(object):
         backend.closeSection('section_dos', dos_index)
         backend.closeSection('section_run', run_index)
 
-        runs = backend.data['section_run']
+        from nomad.datamodel.metainfo.public import section_run
+        runs = backend.resource.all(section_run)
         assert len(runs) == 1
         run = runs[0]
         assert len(run['section_single_configuration_calculation']) == 2
-        assert 'section_dos' in run['section_single_configuration_calculation'][0]
-        assert len(run['section_single_configuration_calculation'][0]['section_dos']) == 1
-        assert 'section_dos' not in run['section_single_configuration_calculation'][1]
+        assert len(run['section_single_configuration_calculation'][0].section_dos) == 1
+        assert len(run['section_single_configuration_calculation'][1].section_dos) == 0
 
-    def test_context(self, backend: LocalBackend, no_warn):
+    def test_context(self, backend: Backend, no_warn):
         backend.openSection('section_run')
         backend.openSection('section_method')
         backend.closeSection('section_method', -1)
@@ -246,11 +245,12 @@ class TestLocalBackend(object):
         backend.openContext('/section_run/0/section_method/0')
         backend.closeContext('/section_run/0/section_method/0')
 
-        runs = backend.data['section_run']
+        from nomad.datamodel.metainfo.public import section_run
+        runs = backend.resource.all(section_run)
         assert runs[0]['program_name'] == 't1'
         assert runs[1]['program_name'] == 't2'
 
-    def test_multi_context(self, backend: LocalBackend, no_warn):
+    def test_multi_context(self, backend: Backend, no_warn):
         backend.openSection('section_run')
         backend.closeSection('section_run', -1)
 
@@ -264,19 +264,21 @@ class TestLocalBackend(object):
         backend.closeSection('section_method', -1)
         backend.closeContext('/section_run/0')
 
-        assert len(backend.data['section_method']) == 1
+        from nomad.datamodel.metainfo.public import section_run
+        runs = backend.resource.all(section_run)
+        assert len(runs[0].section_method) == 2
 
-    def test_bad_context(self, backend: LocalBackend, no_warn):
+    def test_bad_context(self, backend: Backend, no_warn):
         try:
             backend.openContext('section_run/0')
             assert False
-        except BadContextURI:
+        except BadContextUri:
             pass
 
         try:
             backend.openContext('dsfds')
             assert False
-        except BadContextURI:
+        except BadContextUri:
             pass
 
 
@@ -287,42 +289,6 @@ def create_reference(data, pretty):
         return json.dumps(data, separators=(',', ':'))
 
 
-@pytest.mark.parametrize("pretty", [False, True])
-def test_stream_generator(pretty, no_warn):
-    example_data = [
-        {
-            'key1': 'value',
-            'key2': 1
-        },
-        {
-            'key': {
-                'key': 'value'
-            }
-        }
-    ]
-
-    out = StringIO()
-    writer = JSONStreamWriter(out, pretty=pretty)
-    writer.open_array()
-    writer.open_object()
-    writer.key('key1')
-    writer.value('value')
-    writer.key('key2')
-    writer.value(1)
-    writer.close_object()
-    writer.open_object()
-    writer.key('key')
-    writer.open_object()
-    writer.key('key')
-    writer.value('value')
-    writer.close_object()
-    writer.close_object()
-    writer.close_array()
-    writer.close()
-
-    assert create_reference(example_data, pretty) == out.getvalue()
-
-
 def assert_parser_result(backend, error=False):
     status, errors = backend.status
     assert status == 'ParseSuccess'
@@ -337,60 +303,44 @@ def assert_parser_dir_unchanged(previous_wd, current_wd):
     assert previous_wd == current_wd
 
 
-def run_parser(parser_name, mainfile, backend_factory=None):
+def run_parser(parser_name, mainfile):
     parser = parser_dict[parser_name]
-    if backend_factory is not None and hasattr(parser, 'backend_factory'):
-        original_backend_factory = parser.backend_factory
-        parser.backend_factory = backend_factory
     result = parser.run(mainfile, logger=utils.get_logger(__name__))
     result.domain = parser.domain
-    if backend_factory is not None and hasattr(parser, 'backend_factory'):
-        parser.backend_factory = original_backend_factory
     return add_calculation_info(result, parser_name=parser_name)
 
 
 @pytest.fixture
-def parsed_vasp_example() -> LocalBackend:
+def parsed_vasp_example() -> Backend:
     return run_parser(
         'parsers/vasp', 'dependencies/parsers/vasp/test/examples/xml/perovskite.xml')
 
 
 @pytest.fixture
-def parsed_template_example() -> LocalBackend:
+def parsed_template_example() -> Backend:
     return run_parser(
         'parsers/template', 'tests/data/parsers/template.json')
 
 
 @pytest.fixture(scope="session")
-def parsed_template_no_system() -> LocalBackend:
+def parsed_template_no_system() -> Backend:
     return run_parser(
         'parsers/template', 'tests/data/parsers/template_no_system.json')
 
 
-def parse_file(parser_name_and_mainfile) -> LocalBackend:
+def parse_file(parser_name_and_mainfile) -> Backend:
     parser_name, mainfile = parser_name_and_mainfile
     return run_parser(parser_name, mainfile)
 
 
 @pytest.fixture(params=parser_examples, ids=lambda spec: '%s-%s' % spec)
-def parsed_example(request) -> LocalBackend:
+def parsed_example(request) -> Backend:
     parser_name, mainfile = request.param
     result = run_parser(parser_name, mainfile)
     return result
 
 
-@pytest.fixture(params=parser_examples, ids=lambda spec: '%s-%s' % spec)
-def parsed_example_metainfo(request) -> LocalBackend:
-    parser_name, mainfile = request.param
-
-    def backend_factory(env, logger):
-        return MetainfoBackend(convert(env), logger=logger)
-
-    result = run_parser(parser_name, mainfile, backend_factory=backend_factory)
-    return result
-
-
-def add_calculation_info(backend: LocalBackend, **kwargs) -> LocalBackend:
+def add_calculation_info(backend: Backend, **kwargs) -> Backend:
     backend.openNonOverlappingSection('section_entry_info')
     backend.addValue('upload_id', 'test_upload_id')
     backend.addValue('calc_id', 'test_calc_id')
@@ -411,10 +361,6 @@ def test_parser(parser_name, mainfile):
     assert_parser_dir_unchanged(previous_wd, current_wd=os.getcwd())
 
 
-def test_parser_metainfo(parsed_example_metainfo):
-    pass
-
-
 def test_broken_xml_vasp():
     parser_name, mainfile = 'parsers/vasp', 'tests/data/parsers/vasp/broken.xml'
     previous_wd = os.getcwd()  # Get Working directory before parsing.
@@ -438,7 +384,7 @@ def test_match(raw_files, with_latin_1_file, no_warn):
 
     matched_mainfiles = {}
     for mainfile in upload_files.raw_file_manifest():
-        parser = match_parser(mainfile, upload_files)
+        parser = match_parser(upload_files.raw_file_object(mainfile).os_path)
         if parser is not None and not isinstance(parser, BrokenParser):
             matched_mainfiles[mainfile] = parser
 
diff --git a/tests/test_search.py b/tests/test_search.py
index 1e987c4150..6678017ccf 100644
--- a/tests/test_search.py
+++ b/tests/test_search.py
@@ -33,7 +33,7 @@ def test_index_skeleton_calc(elastic):
     create_entry(entry_metadata)
 
 
-def test_index_normalized_calc(elastic, normalized: parsing.LocalBackend):
+def test_index_normalized_calc(elastic, normalized: parsing.Backend):
     entry_metadata = datamodel.EntryMetadata(
         domain='dft', upload_id='test upload id', calc_id='test id')
     entry_metadata.apply_domain_metadata(normalized)
@@ -48,7 +48,7 @@ def test_index_normalized_calc(elastic, normalized: parsing.LocalBackend):
 
 
 def test_index_normalized_calc_with_metadata(
-        elastic, normalized: parsing.LocalBackend, internal_example_user_metadata: dict):
+        elastic, normalized: parsing.Backend, internal_example_user_metadata: dict):
     entry_metadata = datamodel.EntryMetadata(
         domain='dft', upload_id='test upload id', calc_id='test id')
     entry_metadata.apply_domain_metadata(normalized)
@@ -66,7 +66,7 @@ def test_index_upload(elastic, processed: processing.Upload):
 
 
 @pytest.fixture()
-def example_search_data(elastic, normalized: parsing.LocalBackend):
+def example_search_data(elastic, normalized: parsing.Backend):
     entry_metadata = datamodel.EntryMetadata(
         domain='dft', upload_id='test upload id', calc_id='test id')
     entry_metadata.apply_domain_metadata(normalized)
@@ -77,7 +77,7 @@ def example_search_data(elastic, normalized: parsing.LocalBackend):
 
 
 @pytest.fixture()
-def example_ems_search_data(elastic, parsed_ems: parsing.LocalBackend):
+def example_ems_search_data(elastic, parsed_ems: parsing.Backend):
     entry_metadata = datamodel.EntryMetadata(
         domain='ems', upload_id='test upload id', calc_id='test id')
     entry_metadata.apply_domain_metadata(parsed_ems)
@@ -201,7 +201,7 @@ def test_search_include(elastic, example_search_data):
 
 @pytest.mark.parametrize("order_by", [None, 'upload_id'])
 def test_search_quantity(
-        elastic, normalized: parsing.LocalBackend, test_user: datamodel.User,
+        elastic, normalized: parsing.Backend, test_user: datamodel.User,
         other_test_user: datamodel.User, order_by: str):
 
     entry_metadata = datamodel.EntryMetadata(
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 17b38d962c..9eb9b56992 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -14,16 +14,15 @@
 
 import time
 import json
+import pytest
 
 from nomad import utils
 
-from tests import utils as test_utils
-
 
 def test_decode_handle_id():
     assert utils.decode_handle_id('a1') == 321
     assert utils.decode_handle_id('6i370') == 6884576
-    with test_utils.assert_exception(ValueError):
+    with pytest.raises(ValueError):
         utils.decode_handle_id('zz')
 
 
diff --git a/tests/utils.py b/tests/utils.py
index 194da6e4e0..eb52be09fc 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -14,9 +14,7 @@
 
 ''' Methods to help with testing of nomad@FAIRDI.'''
 
-from typing import Type
 import json
-from contextlib import contextmanager
 from logging import LogRecord
 
 
@@ -46,18 +44,3 @@ def assert_log(caplog, level: str, event_part: str) -> LogRecord:
     assert record is not None
 
     return record
-
-
-@contextmanager
-def assert_exception(exception_cls: Type = Exception):
-    '''
-    A context manager that can be used to assert that the given exception is thrown
-    within the respective ``with``clause.
-    '''
-    has_exception = False
-    try:
-        yield
-    except exception_cls:
-        has_exception = True
-
-    assert has_exception
-- 
GitLab