diff --git a/nomad/metainfo/encyclopedia.py b/nomad/metainfo/encyclopedia.py
index 0a1de6e35fe1edde20bdb77bf21d205015e73e9c..fa6fc375601e772a184e61c9facac3d6b7869082 100644
--- a/nomad/metainfo/encyclopedia.py
+++ b/nomad/metainfo/encyclopedia.py
@@ -61,34 +61,90 @@ class WyckoffSet(MSection):
     variables = SubSection(sub_section=WyckoffVariables.m_def, repeats=False)
 
 
-class Material(MSection):
+class IdealizedStructure(MSection):
     m_def = Section(
         a_flask=dict(skip_none=True),
         a_elastic=dict(type=InnerDoc),
         description="""
-        Section for storing the data that links an Encyclopedia entry into a
-        specific material.
+        Contains structural information for an idealized representation of the
+        material used in the calculation. This idealization is used for
+        visualizing the material and for calculating the structural properties.
+        The properties of the idealized structure may slightly vary from the
+        original structure used in the calculation.
         """
     )
-
-    # Material-specific
-    material_type = Quantity(
-        type=MEnum(bulk="bulk", two_d="2D", one_d="1D", unavailable="unavailable"),
+    atom_labels = Quantity(
+        type=str,
+        shape=['1..*'],
         description="""
-        "Character of physical system's geometry, e.g. bulk, 2D, 1D... ",
+        Type (element, species) of each atom.
         """
     )
-    material_hash = Quantity(
-        type=str,
+    atom_positions = Quantity(
+        type=np.dtype('f8'),
+        shape=['number_of_atoms', 3],
         description="""
-        A fixed length, unique material identifier in the form of a hash
-        digest.
+        Atom positions given in coordinates that are relative to the idealized
+        cell.
+        """
+    )
+    lattice_vectors = Quantity(
+        type=np.dtype('f8'),
+        shape=[3, 3],
+        description="""
+        Lattice vectors of the idealized structure. For bulk materials it is
+        the Bravais cell. This cell is representative and is idealized to match
+        the detected symmetry properties.
+        """
+    )
+    lattice_vectors_primitive = Quantity(
+        type=np.dtype('f8'),
+        shape=[3, 3],
+        description="""
+        Lattice vectors of the the primitive unit cell in a form to be visualized
+        within the idealized cell. This cell is representative and is
+        idealized to match the detected symmemtry properties.
+        """
+    )
+    lattice_parameters = Quantity(
+        type=np.dtype('f8'),
+        shape=[6],
+        description="""
+        Lattice parameters of the idealized cell. The lattice parameters can
+        only be reported consistently after idealization and may not perfectly
+        correspond to the original simulation cell.
+        """
+    )
+    periodicity = Quantity(
+        type=np.bool,
+        shape=[3],
+        description="""
+        Automatically detected true periodicity of each lattice direction. May
+        not correspond to the periodicity used in the calculation.
         """
     )
     number_of_atoms = Quantity(
         type=int,
         description="""
-        Number of atoms in the bravais cell."
+        Number of atoms in the idealized structure."
+        """
+    )
+    cell_volume = Quantity(
+        type=float,
+        description="""
+        Volume of the idealized cell. The cell volume can only be reported
+        consistently after idealization and may not perfectly correspond to the
+        original simulation cell.
+        """
+    )
+
+
+class Bulk(MSection):
+    m_def = Section(
+        a_flask=dict(skip_none=True),
+        a_elastic=dict(type=InnerDoc),
+        description="""
+        Contains information that is specific to bulk crystalline materials.
         """
     )
     bravais_lattice = Quantity(
@@ -123,21 +179,6 @@ class Material(MSection):
         The detected crystal system. One of seven possibilities in three dimensions.
         """
     )
-    formula = Quantity(
-        type=str,
-        description="""
-        Formula giving the composition and occurrences of the elements in the
-        Hill notation for the irreducible unit cell.
-        """
-    )
-    formula_reduced = Quantity(
-        type=str,
-        description="""
-        Formula giving the composition and occurrences of the elements in the
-        Hill notation for the irreducible unit cell. In this reduced form the
-        number of occurences have been divided by the greatest common divisor.
-        """
-    )
     has_free_wyckoff_parameters = Quantity(
         type=bool,
         description="""
@@ -147,26 +188,6 @@ class Material(MSection):
         move with possible restrictions set by the symmetry.
         """
     )
-    material_classification = Quantity(
-        type=str,
-        description="""
-        Contains the compound class and classification of the material
-        according to springer materials in JSON format.
-        """
-    )
-    material_name = Quantity(
-        type=str,
-        description="""
-        Most meaningful name for a material.
-        """
-    )
-    periodicity = Quantity(
-        type=np.bool,
-        shape=[3],
-        description="""
-        Periodicity of each lattice direction.
-        """
-    )
     point_group = Quantity(
         type=MEnum("1", "-1", "2", "m", "2/m", "222", "mm2", "mmm", "4", "-4", "4/m", "422", "4mm", "-42m", "4/mmm", "3", "-3", "32", "3m", "-3m", "6", "-6", "6/m", "622", "6mm", "-6m2", "6/mmm", "23", "m-3", "432", "-43m", "m-3m"),
         description="""
@@ -206,70 +227,67 @@ class Material(MSection):
         Classification of the material according to the historically grown "strukturbericht".
         """
     )
+    wyckoff_sets = SubSection(sub_section=WyckoffSet.m_def, repeats=True)
 
-    # Calculation-specific
-    atom_labels = Quantity(
-        type=str,
-        shape=['1..*'],
+
+class Material(MSection):
+    m_def = Section(
+        a_flask=dict(skip_none=True),
+        a_elastic=dict(type=InnerDoc),
         description="""
-        Type (element, species) of each atom,
+        Section for storing the data that links an Encyclopedia entry into a
+        specific material.
         """
     )
-    atom_positions = Quantity(
-        type=np.dtype('f8'),
-        shape=['number_of_atoms', 3],
+    material_type = Quantity(
+        type=MEnum(bulk="bulk", two_d="2D", one_d="1D", unavailable="unavailable"),
         description="""
-        Position of each atom, given in relative coordinates.
+        "Broad structural classification for the material, e.g. bulk, 2D, 1D... ",
         """
     )
-    cell_normalized = Quantity(
-        type=np.dtype('f8'),
-        shape=[3, 3],
+    material_hash = Quantity(
+        type=str,
         description="""
-        Unit cell in normalized form, meaning the bravais cell. This cell is
-        representative and is idealized to match the detected symmetry
-        properties.
+        A fixed length, unique material identifier in the form of a hash
+        digest.
         """
     )
-    cell_primitive = Quantity(
-        type=np.dtype('f8'),
-        shape=[3, 3],
+    material_name = Quantity(
+        type=str,
         description="""
-        Definition of the primitive unit cell in a form to be visualized well
-        within the normalized cell. This cell is representative and is
-        idealized to match the detected symmemtry properties.
+        Most meaningful name for a material.
         """
     )
-
-    wyckoff_sets = SubSection(sub_section=WyckoffSet.m_def, repeats=True)
-
-    cell_angles_string = Quantity(
+    material_classification = Quantity(
         type=str,
         description="""
-        A summary of the cell angles, part of material definition.
+        Contains the compound class and classification of the material
+        according to springer materials in JSON format.
         """
     )
-    cell_volume = Quantity(
-        type=float,
+    formula = Quantity(
+        type=str,
         description="""
-        Cell volume for a specific calculation. The cell volume can only be
-        reported consistently after normalization. Thus it corresponds to the
-        normalized cell that is idealized to fit the detected symmetry and may
-        not perfectly correspond to the original simulation cell.
+        Formula giving the composition and occurrences of the elements in the
+        Hill notation. For periodic materials the formula is calculated fom the
+        primitive unit cell.
         """
     )
-    lattice_parameters = Quantity(
-        type=np.dtype('f8'),
-        shape=[6],
+    formula_reduced = Quantity(
+        type=str,
         description="""
-        Lattice parameters of a specific calculation. The lattice parameters
-        can only be reported consistently after normalization. Thus they
-        correspond to the normalized cell that is idealized to fit the detected
-        symmetry and may not perfectly correspond to the original simulation
-        cell.
+        Formula giving the composition and occurrences of the elements in the
+        Hill notation whre the number of occurences have been divided by the
+        greatest common divisor.
         """
     )
 
+    # The idealized structure for this material
+    idealized_structure = SubSection(sub_section=IdealizedStructure.m_def, repeats=False)
+
+    # Bulk-specific properties
+    bulk = SubSection(sub_section=Bulk.m_def, repeats=False)
+
 
 class Method(MSection):
     m_def = Section(
@@ -498,6 +516,13 @@ class ElectronicBandStructure(MSection):
         Stores information related to an electronic band structure.
         """
     )
+    scc_index = Quantity(
+        type=int,
+        description="""
+        Index of the single configuration calculation that contains the band
+        structure.
+        """
+    )
     fermi_level = Quantity(
         type=float,
         unit=units.J,
@@ -551,6 +576,13 @@ class ElectronicDOS(MSection):
         Stores the electronic density of states (DOS).
         """
     )
+    scc_index = Quantity(
+        type=int,
+        description="""
+        Index of the single configuration calculation that contains the density
+        of states.
+        """
+    )
     fermi_level = Quantity(
         type=float,
         unit=units.J,
@@ -588,12 +620,6 @@ class Properties(MSection):
         are used by the NOMAD Encyclopedia.
         """
     )
-    scc_index = Quantity(
-        type=int,
-        description="""
-        Index of a representative single configuration calculation."
-        """
-    )
     atomic_density = Quantity(
         type=float,
         unit=units.m**(-3),
@@ -628,12 +654,6 @@ class Encyclopedia(MSection):
         Section which stores information for the NOMAD Encyclopedia.
         """
     )
-    mainfile_uri = Quantity(
-        type=str,
-        description="""
-        Path of the main file.
-        """
-    )
     material = SubSection(sub_section=Material.m_def, repeats=False)
     method = SubSection(sub_section=Method.m_def, repeats=False)
     properties = SubSection(sub_section=Properties.m_def, repeats=False)
diff --git a/nomad/normalizing/encyclopedia.py b/nomad/normalizing/encyclopedia.py
index d6cfd71760244493d231c3069284c41060ef64ae..7307f58e765aa4a3ab59cbf37db2b0820256f279 100644
--- a/nomad/normalizing/encyclopedia.py
+++ b/nomad/normalizing/encyclopedia.py
@@ -44,7 +44,9 @@ from nomad.metainfo.encyclopedia import (
     Properties,
     RunType,
     WyckoffSet,
+    Bulk,
     WyckoffVariables,
+    IdealizedStructure,
     ElectronicBandStructure,
     BandGap,
 )
@@ -233,13 +235,6 @@ class EncyclopediaNormalizer(Normalizer):
         method.method_type = method_id
         return repr_method, method_id
 
-    def mainfile_uri(self, encyclopedia: Encyclopedia):
-        entry_info = self._backend["section_entry_info"][0]
-        upload_id = entry_info["upload_id"]
-        mainfile_path = entry_info["mainfile"]
-        uri = f"nmd://R{upload_id}/data/{mainfile_path}"
-        encyclopedia.mainfile_uri = uri
-
     # def similar_materials(self) -> None:
         # pass
 
@@ -264,30 +259,30 @@ class EncyclopediaNormalizer(Normalizer):
     # def number_of_calculations(self) -> None:
         # pass
 
-    def fill(self, ctx: Context):
+    def fill(self, context: Context):
         # Fill structure related metainfo
         struct: Any = None
-        if ctx.material_type == Material.material_type.type.bulk:
+        if context.material_type == Material.material_type.type.bulk:
             struct = MaterialBulkNormalizer(self.backend, self.logger)
-        elif ctx.material_type == Material.material_type.type.two_d:
+        elif context.material_type == Material.material_type.type.two_d:
             struct = Material2DNormalizer(self.backend, self.logger)
-        elif ctx.material_type == Material.material_type.type.one_d:
+        elif context.material_type == Material.material_type.type.one_d:
             struct = Material1DNormalizer(self.backend, self.logger)
         if struct is not None:
-            struct.normalize(ctx)
+            struct.normalize(context)
 
         # Fill method related metainfo
         method = None
-        if ctx.method_type == Method.method_type.type.DFT or ctx.method_type == Method.method_type.type.DFTU:
+        if context.method_type == Method.method_type.type.DFT or context.method_type == Method.method_type.type.DFTU:
             method = MethodDFTNormalizer(self._backend, self.logger)
-        elif ctx.method_type == Method.method_type.type.GW:
+        elif context.method_type == Method.method_type.type.GW:
             method = MethodGWNormalizer(self._backend, self.logger)
         if method is not None:
-            method.normalize(ctx)
+            method.normalize(context)
 
         # Fill properties related metainfo
         properties = PropertiesNormalizer(self.backend, self.logger)
-        properties.normalize(ctx)
+        properties.normalize(context)
 
     def normalize(self, logger=None) -> None:
         """The caller will automatically log if the normalizer succeeds or ends
@@ -303,9 +298,6 @@ class EncyclopediaNormalizer(Normalizer):
             sec_enc.m_create(Properties)
             run_type = sec_enc.m_create(RunType)
 
-            # Get generic data
-            self.mainfile_uri(sec_enc)
-
             # Determine run type, stop if unknown
             run_type_name = self.run_type(run_type)
             if run_type_name == config.services.unavailable_value:
@@ -377,18 +369,18 @@ class MaterialNormalizer():
         self.backend = backend
         self.logger = logger
 
-    def atom_labels(self, material: Material, std_atoms: Atoms) -> None:
-        material.atom_labels = std_atoms.get_chemical_symbols()
+    def atom_labels(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
+        ideal.atom_labels = std_atoms.get_chemical_symbols()
 
-    def atom_positions(self, material: Material, std_atoms: Atoms) -> None:
-        material.atom_positions = std_atoms.get_scaled_positions(wrap=False)
+    def atom_positions(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
+        ideal.atom_positions = std_atoms.get_scaled_positions(wrap=False)
 
     @abstractmethod
-    def cell_normalized(self, material: Material, std_atoms: Atoms) -> None:
+    def lattice_vectors(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
         pass
 
-    def cell_volume(self, material: Material, std_atoms: Atoms) -> None:
-        material.cell_volume = float(std_atoms.get_volume() * 1e-10**3)
+    def cell_volume(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
+        ideal.cell_volume = float(std_atoms.get_volume() * 1e-10**3)
 
     def formula(self, material: Material, names: List[str], counts: List[int]) -> None:
         formula = structure.get_formula_string(names, counts)
@@ -403,11 +395,11 @@ class MaterialNormalizer():
         norm_hash_string = structure.get_symmetry_string(spg_number, wyckoff_sets)
         material.material_hash = hash(norm_hash_string)
 
-    def number_of_atoms(self, material: Material, std_atoms: Atoms) -> None:
-        material.number_of_atoms = len(std_atoms)
+    def number_of_atoms(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
+        ideal.number_of_atoms = len(std_atoms)
 
     @abstractmethod
-    def normalize(self, ctx: Context) -> None:
+    def normalize(self, context: Context) -> None:
         pass
 
 
@@ -419,30 +411,30 @@ class MaterialBulkNormalizer(MaterialNormalizer):
         orig_volume = repr_system.get_volume() * (1e-10)**3
         properties.atomic_density = float(orig_n_atoms / orig_volume)
 
-    def bravais_lattice(self, material: Material, section_symmetry: Section) -> None:
+    def bravais_lattice(self, bulk: Bulk, section_symmetry: Section) -> None:
         bravais_lattice = section_symmetry["bravais_lattice"]
-        material.bravais_lattice = bravais_lattice
+        bulk.bravais_lattice = bravais_lattice
 
-    def cell_normalized(self, material: Material, std_atoms: Atoms) -> None:
+    def lattice_vectors(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
         cell_normalized = std_atoms.get_cell()
         cell_normalized *= 1e-10
-        material.cell_normalized = cell_normalized
+        ideal.lattice_vectors = cell_normalized
 
-    def cell_primitive(self, material: Material, prim_atoms: Atoms) -> None:
+    def lattice_vectors_primitive(self, ideal: IdealizedStructure, prim_atoms: Atoms) -> None:
         cell_prim = prim_atoms.get_cell()
         cell_prim *= 1e-10
-        material.cell_primitive = cell_prim
+        ideal.lattice_vectors_primitive = cell_prim
 
-    def crystal_system(self, material: Material, section_symmetry: Section) -> None:
-        material.crystal_system = section_symmetry["crystal_system"]
+    def crystal_system(self, bulk: Bulk, section_symmetry: Section) -> None:
+        bulk.crystal_system = section_symmetry["crystal_system"]
 
-    def has_free_wyckoff_parameters(self, material: Material, symmetry_analyzer: SymmetryAnalyzer) -> None:
+    def has_free_wyckoff_parameters(self, bulk: Bulk, symmetry_analyzer: SymmetryAnalyzer) -> None:
         has_free_param = symmetry_analyzer.get_has_free_wyckoff_parameters()
-        material.has_free_wyckoff_parameters = has_free_param
+        bulk.has_free_wyckoff_parameters = has_free_param
 
-    def lattice_parameters(self, material: Material, std_atoms: Atoms) -> None:
+    def lattice_parameters(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
         cell_normalized = std_atoms.get_cell() * 1E-10
-        material.lattice_parameters = structure.get_lattice_parameters(cell_normalized)
+        ideal.lattice_parameters = structure.get_lattice_parameters(cell_normalized)
 
     def mass_density(self, properties: Properties, repr_system: Atoms) -> None:
         mass = structure.get_summed_atomic_mass(repr_system.get_atomic_numbers())
@@ -570,19 +562,19 @@ class MaterialBulkNormalizer(MaterialNormalizer):
 
             material.material_name = name
 
-    def periodicity(self, material: Material) -> None:
-        material.periodicity = np.array([True, True, True], dtype=np.bool)
+    def periodicity(self, ideal: IdealizedStructure) -> None:
+        ideal.periodicity = np.array([True, True, True], dtype=np.bool)
 
-    def point_group(self, material: Material, section_symmetry: Section) -> None:
+    def point_group(self, bulk: Bulk, section_symmetry: Section) -> None:
         point_group = section_symmetry["point_group"]
-        material.point_group = point_group
+        bulk.point_group = point_group
 
-    def space_group_number(self, material: Material, spg_number: int) -> None:
-        material.space_group_number = spg_number
+    def space_group_number(self, bulk: Bulk, spg_number: int) -> None:
+        bulk.space_group_number = spg_number
 
-    def space_group_international_short_symbol(self, material: Material, symmetry_analyzer: SymmetryAnalyzer) -> None:
+    def space_group_international_short_symbol(self, bulk: Bulk, symmetry_analyzer: SymmetryAnalyzer) -> None:
         spg_int_symb = symmetry_analyzer.get_space_group_international_short()
-        material.space_group_international_short_symbol = spg_int_symb
+        bulk.space_group_international_short_symbol = spg_int_symb
 
     def material_classification(self, material: Material, section_system: Section) -> None:
         try:
@@ -606,7 +598,7 @@ class MaterialBulkNormalizer(MaterialNormalizer):
         if classes:
             material.material_classification = json.dumps(classes)
 
-    def structure_type(self, material: Material, section_system: Section) -> None:
+    def structure_type(self, bulk: Bulk, section_system: Section) -> None:
         try:
             sec_prototype = section_system["section_prototype"][0]
             notes = sec_prototype.tmp['prototype_notes']
@@ -638,18 +630,18 @@ class MaterialBulkNormalizer(MaterialNormalizer):
         }
         enc_note = note_map.get(notes, None)
         if enc_note is not None:
-            material.structure_type = enc_note
+            bulk.structure_type = enc_note
 
-    def structure_prototype(self, material: Material, section_system: Section) -> None:
+    def structure_prototype(self, bulk: Bulk, section_system: Section) -> None:
         try:
             sec_prototype = section_system["section_prototype"][0]
             name = sec_prototype.tmp['prototype_name']
         except Exception:
             return
 
-        material.structure_prototype = name
+        bulk.structure_prototype = name
 
-    def strukturbericht_designation(self, material: Material, section_system: Section) -> None:
+    def strukturbericht_designation(self, bulk: Bulk, section_system: Section) -> None:
         try:
             sec_prototype = section_system["section_prototype"][0]
             strukturbericht = sec_prototype.tmp["strukturbericht_designation"]
@@ -658,11 +650,11 @@ class MaterialBulkNormalizer(MaterialNormalizer):
 
         # In the current GUI we replace LaTeX with plain text
         strukturbericht = re.sub('[$_{}]', '', strukturbericht)
-        material.strukturbericht_designation = strukturbericht
+        bulk.strukturbericht_designation = strukturbericht
 
-    def wyckoff_sets(self, material: Material, wyckoff_sets: Dict) -> None:
+    def wyckoff_sets(self, bulk: Bulk, wyckoff_sets: Dict) -> None:
         for group in wyckoff_sets:
-            wset = material.m_create(WyckoffSet)
+            wset = bulk.m_create(WyckoffSet)
             if group.x is not None or group.y is not None or group.z is not None:
                 variables = wset.m_create(WyckoffVariables)
                 if group.x is not None:
@@ -675,9 +667,9 @@ class MaterialBulkNormalizer(MaterialNormalizer):
             wset.element = group.element
             wset.wyckoff_letter = group.wyckoff_letter
 
-    def normalize(self, ctx: Context) -> None:
+    def normalize(self, context: Context) -> None:
         # Fetch resources
-        sec_system = ctx.representative_system
+        sec_system = context.representative_system
         sec_enc = self.backend.get_mi2_section(Encyclopedia.m_def)
         material = sec_enc.material
         properties = sec_enc.properties
@@ -690,51 +682,53 @@ class MaterialBulkNormalizer(MaterialNormalizer):
         wyckoff_sets = symmetry_analyzer.get_wyckoff_sets_conventional(return_parameters=True)
         names, counts = structure.get_hill_decomposition(prim_atoms.get_chemical_symbols(), reduced=False)
         greatest_common_divisor = reduce(gcd, counts)
-        ctx.greatest_common_divisor = greatest_common_divisor
+        context.greatest_common_divisor = greatest_common_divisor
         reduced_counts = np.array(counts) / greatest_common_divisor
 
         # Fill structural information
+        bulk = material.m_create(Bulk)
+        ideal = material.m_create(IdealizedStructure)
         self.mass_density(properties, repr_atoms)
         self.material_hash(material, spg_number, wyckoff_sets)
-        self.number_of_atoms(material, std_atoms)
-        self.atom_labels(material, std_atoms)
-        self.atom_positions(material, std_atoms)
+        self.number_of_atoms(ideal, std_atoms)
+        self.atom_labels(ideal, std_atoms)
+        self.atom_positions(ideal, std_atoms)
         self.atomic_density(properties, repr_atoms)
-        self.bravais_lattice(material, sec_symmetry)
-        self.cell_normalized(material, std_atoms)
-        self.cell_volume(material, std_atoms)
-        self.crystal_system(material, sec_symmetry)
-        self.cell_primitive(material, prim_atoms)
+        self.bravais_lattice(bulk, sec_symmetry)
+        self.lattice_vectors(ideal, std_atoms)
+        self.cell_volume(ideal, std_atoms)
+        self.crystal_system(bulk, sec_symmetry)
+        self.lattice_vectors_primitive(ideal, prim_atoms)
         self.formula(material, names, counts)
         self.formula_reduced(material, names, reduced_counts)
-        self.has_free_wyckoff_parameters(material, symmetry_analyzer)
-        self.lattice_parameters(material, std_atoms)
+        self.has_free_wyckoff_parameters(bulk, symmetry_analyzer)
+        self.lattice_parameters(ideal, std_atoms)
         self.material_name(material, names, reduced_counts)
         self.material_classification(material, sec_system)
-        self.periodicity(material)
-        self.point_group(material, sec_symmetry)
-        self.space_group_number(material, spg_number)
-        self.space_group_international_short_symbol(material, symmetry_analyzer)
-        self.structure_type(material, sec_system)
-        self.structure_prototype(material, sec_system)
-        self.strukturbericht_designation(material, sec_system)
-        self.wyckoff_sets(material, wyckoff_sets)
+        self.periodicity(ideal)
+        self.point_group(bulk, sec_symmetry)
+        self.space_group_number(bulk, spg_number)
+        self.space_group_international_short_symbol(bulk, symmetry_analyzer)
+        self.structure_type(bulk, sec_system)
+        self.structure_prototype(bulk, sec_system)
+        self.strukturbericht_designation(bulk, sec_system)
+        self.wyckoff_sets(bulk, wyckoff_sets)
 
 
 class Material2DNormalizer(MaterialNormalizer):
     """Processes structure related metainfo for Encyclopedia 2D structures.
     """
-    def cell_normalized(self, material: Material, std_atoms: Atoms) -> None:
+    def lattice_vectors(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
         cell_normalized = std_atoms.get_cell()
         cell_normalized *= 1e-10
-        material.cell_normalized = cell_normalized
+        ideal.lattice_vectors = cell_normalized
 
-    def cell_primitive(self, material: Material, prim_atoms: Atoms) -> None:
+    def lattice_vectors_primitive(self, ideal: IdealizedStructure, prim_atoms: Atoms) -> None:
         cell_prim = prim_atoms.get_cell()
         cell_prim *= 1e-10
-        material.cell_primitive = cell_prim
+        ideal.lattice_vectors_primitive = cell_prim
 
-    def lattice_parameters(self, material: Material, std_atoms: Atoms, periodicity: np.array) -> None:
+    def lattice_parameters(self, ideal: IdealizedStructure, std_atoms: Atoms, periodicity: np.array) -> None:
         # 2D systems only have three lattice parameter: two length and angle between them
         periodic_indices = np.where(np.array(periodicity) == True)[0]  # noqa: E712
         cell = std_atoms.get_cell()
@@ -744,11 +738,11 @@ class Material2DNormalizer(MaterialNormalizer):
         b = np.linalg.norm(b_vec)
         alpha = np.clip(np.dot(a_vec, b_vec) / (a * b), -1.0, 1.0)
         alpha = np.arccos(alpha)
-        material.lattice_parameters = np.array([a, b, 0.0, alpha, 0.0, 0.0])
+        ideal.lattice_parameters = np.array([a, b, 0.0, alpha, 0.0, 0.0])
 
-    def periodicity(self, material: Material, std_atoms: Atoms) -> None:
+    def periodicity(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
         # MatID already provides the correct periodicity
-        material.periodicity = std_atoms.get_pbc()
+        ideal.periodicity = std_atoms.get_pbc()
 
     def get_symmetry_analyzer(self, original_system: Atoms) -> SymmetryAnalyzer:
         # Get dimension of system by also taking into account the covalent radii
@@ -787,11 +781,11 @@ class Material2DNormalizer(MaterialNormalizer):
         )
         return symmetry_analyzer
 
-    def normalize(self, ctx: Context) -> None:
+    def normalize(self, context: Context) -> None:
         # Fetch resources
         sec_enc = self.backend.get_mi2_section(Encyclopedia.m_def)
         material = sec_enc.material
-        repr_atoms = ctx.representative_system.tmp["representative_atoms"]  # Temporary value stored by SystemNormalizer
+        repr_atoms = context.representative_system.tmp["representative_atoms"]  # Temporary value stored by SystemNormalizer
         symmetry_analyzer = self.get_symmetry_analyzer(repr_atoms)
         spg_number = symmetry_analyzer.get_space_group_number()
         wyckoff_sets = symmetry_analyzer.get_wyckoff_sets_conventional(return_parameters=False)
@@ -799,20 +793,21 @@ class Material2DNormalizer(MaterialNormalizer):
         prim_atoms = symmetry_analyzer.get_primitive_system()
         names, counts = structure.get_hill_decomposition(prim_atoms.get_chemical_symbols(), reduced=False)
         greatest_common_divisor = reduce(gcd, counts)
-        ctx.greatest_common_divisor = greatest_common_divisor
+        context.greatest_common_divisor = greatest_common_divisor
         reduced_counts = np.array(counts) / greatest_common_divisor
 
         # Fill metainfo
-        self.periodicity(material, std_atoms)
+        ideal = material.m_create(IdealizedStructure)
+        self.periodicity(ideal, std_atoms)
         self.material_hash(material, spg_number, wyckoff_sets)
-        self.number_of_atoms(material, std_atoms)
-        self.atom_labels(material, std_atoms)
-        self.atom_positions(material, std_atoms)
-        self.cell_normalized(material, std_atoms)
-        self.cell_primitive(material, prim_atoms)
+        self.number_of_atoms(ideal, std_atoms)
+        self.atom_labels(ideal, std_atoms)
+        self.atom_positions(ideal, std_atoms)
+        self.lattice_vectors(ideal, std_atoms)
+        self.lattice_vectors_primitive(ideal, prim_atoms)
         self.formula(material, names, counts)
         self.formula_reduced(material, names, reduced_counts)
-        self.lattice_parameters(material, std_atoms, material.periodicity)
+        self.lattice_parameters(ideal, std_atoms, ideal.periodicity)
 
 
 class Material1DNormalizer(MaterialNormalizer):
@@ -832,19 +827,19 @@ class Material1DNormalizer(MaterialNormalizer):
         hash_val = hash(hash_seed)
         material.material_hash = hash_val
 
-    def cell_normalized(self, material: Material, std_atoms: Atoms) -> None:
+    def lattice_vectors(self, ideal: IdealizedStructure, std_atoms: Atoms) -> None:
         cell_normalized = std_atoms.get_cell()
         cell_normalized *= 1e-10
-        material.cell_normalized = cell_normalized
+        ideal.lattice_vectors = cell_normalized
 
-    def lattice_parameters(self, material: Material, std_atoms: Atoms, periodicity: np.array) -> None:
+    def lattice_parameters(self, ideal: IdealizedStructure, std_atoms: Atoms, periodicity: np.array) -> None:
         # 1D systems only have one lattice parameter: length in periodic dimension
         periodic_indices = np.where(np.array(periodicity) == True)[0]  # noqa: E712
         cell = std_atoms.get_cell()
         a = np.linalg.norm(cell[periodic_indices[0], :]) * 1e-10
-        material.lattice_parameters = np.array([a, 0.0, 0.0, 0.0, 0.0, 0.0])
+        ideal.lattice_parameters = np.array([a, 0.0, 0.0, 0.0, 0.0, 0.0])
 
-    def periodicity(self, material: Material, prim_atoms: Atoms) -> None:
+    def periodicity(self, ideal: IdealizedStructure, prim_atoms: Atoms) -> None:
         # Get dimension of system by also taking into account the covalent radii
         dimensions = matid.geometry.get_dimensions(prim_atoms, [True, True, True])
         basis_dimensions = np.linalg.norm(prim_atoms.get_cell(), axis=1)
@@ -856,7 +851,7 @@ class Material1DNormalizer(MaterialNormalizer):
         if sum(periodicity) != 1:
             raise ValueError("Could not detect the periodic dimensions in a 1D system.")
 
-        material.periodicity = periodicity
+        ideal.periodicity = periodicity
 
     def get_structure_fingerprint(self, prim_atoms: Atoms) -> str:
         """Calculates a numeric fingerprint that coarsely encodes the atomic
@@ -1000,9 +995,9 @@ class Material1DNormalizer(MaterialNormalizer):
 
         return std_atoms
 
-    def normalize(self, ctx: Context) -> None:
+    def normalize(self, context: Context) -> None:
         # Fetch resources
-        sec_system = ctx.representative_system
+        sec_system = context.representative_system
         sec_enc = self.backend.get_mi2_section(Encyclopedia.m_def)
         material = sec_enc.material
         repr_atoms = sec_system.tmp["representative_atoms"]  # Temporary value stored by SystemNormalizer
@@ -1011,20 +1006,21 @@ class Material1DNormalizer(MaterialNormalizer):
         prim_atoms.set_pbc(True)
         names, counts = structure.get_hill_decomposition(prim_atoms.get_chemical_symbols(), reduced=False)
         greatest_common_divisor = reduce(gcd, counts)
-        ctx.greatest_common_divisor = greatest_common_divisor
+        context.greatest_common_divisor = greatest_common_divisor
         reduced_counts = np.array(counts) / greatest_common_divisor
 
         # Fill metainfo
-        self.periodicity(material, prim_atoms)
-        std_atoms = self.get_std_atoms(material.periodicity, prim_atoms)
-        self.number_of_atoms(material, std_atoms)
-        self.atom_labels(material, std_atoms)
-        self.atom_positions(material, std_atoms)
-        self.cell_normalized(material, std_atoms)
+        ideal = material.m_create(IdealizedStructure)
+        self.periodicity(ideal, prim_atoms)
+        std_atoms = self.get_std_atoms(ideal.periodicity, prim_atoms)
+        self.number_of_atoms(ideal, std_atoms)
+        self.atom_labels(ideal, std_atoms)
+        self.atom_positions(ideal, std_atoms)
+        self.lattice_vectors(ideal, std_atoms)
         self.formula(material, names, counts)
         self.formula_reduced(material, names, reduced_counts)
         self.material_hash_1d(material, std_atoms)
-        self.lattice_parameters(material, std_atoms, material.periodicity)
+        self.lattice_parameters(ideal, std_atoms, ideal.periodicity)
 
 
 class MethodNormalizer():
@@ -1159,7 +1155,7 @@ class MethodNormalizer():
         pass
 
     @abstractmethod
-    def normalize(self, ctx: Context) -> None:
+    def normalize(self, context: Context) -> None:
         pass
 
 
@@ -1421,14 +1417,14 @@ class MethodDFTNormalizer(MethodNormalizer):
 
         return shortname
 
-    def normalize(self, ctx: Context) -> None:
+    def normalize(self, context: Context) -> None:
         # Fetch resources
-        repr_method = ctx.representative_method
-        repr_system = ctx.representative_system
+        repr_method = context.representative_method
+        repr_system = context.representative_system
         sec_enc = self.backend.get_mi2_section(Encyclopedia.m_def)
         method = sec_enc.method
         material = sec_enc.material
-        settings_basis_set = get_basis_set_settings(ctx, self.backend, self.logger)
+        settings_basis_set = get_basis_set_settings(context, self.backend, self.logger)
 
         # Fill metainfo
         self.basis_set_type(method)
@@ -1467,9 +1463,9 @@ class MethodGWNormalizer(MethodDFTNormalizer):
     def gw_type(self, method: Method, repr_method: Section) -> None:
         method.gw_type = repr_method["electronic_structure_method"]
 
-    def normalize(self, ctx: Context) -> None:
+    def normalize(self, context: Context) -> None:
         # Fetch resources
-        repr_method = ctx.representative_method
+        repr_method = context.representative_method
         sec_enc = self.backend.get_mi2_section(Encyclopedia.m_def)
         method = sec_enc.method
 
@@ -1477,7 +1473,7 @@ class MethodGWNormalizer(MethodDFTNormalizer):
         self.code_name(method)
         self.code_version(method)
         self.functional_type(method)
-        self.gw_type(method, ctx.representative_method)
+        self.gw_type(method, context.representative_method)
         self.gw_starting_point(method, repr_method)
 
 
@@ -1647,7 +1643,7 @@ class PropertiesNormalizer():
         bz_json = json.dumps(brillouin_zone)
         band_structure.brillouin_zone = bz_json
 
-    def band_structure(self, properties: Properties, run_type: str, material_type: str, representative_scc: Section, sec_system: Section) -> None:
+    def band_structure(self, properties: Properties, run_type: str, material_type: str, context: Context, sec_system: Section) -> None:
         """Band structure data following arbitrary path.
 
         Currently this function is only taking into account the normalized band
@@ -1662,6 +1658,7 @@ class PropertiesNormalizer():
         if run_type != RunType.run_type.type.single_point or material_type != Material.material_type.type.bulk:
             return
 
+        representative_scc = context.representative_scc
         orig_atoms = sec_system.tmp["representative_atoms"]
         symmetry_analyzer = sec_system["section_symmetry"][0].tmp["symmetry_analyzer"]
         prim_atoms = symmetry_analyzer.get_primitive_system()
@@ -1677,6 +1674,7 @@ class PropertiesNormalizer():
             # Loop over bands
             for band_data in bands:
                 band_structure = ElectronicBandStructure()
+                band_structure.scc_index = int(context.representative_scc_idx)
                 kpoints = []
                 energies = []
                 try:
@@ -1770,21 +1768,20 @@ class PropertiesNormalizer():
         energies = json.dumps(energy_dict)
         properties.energies = energies
 
-    def normalize(self, ctx: Context) -> None:
+    def normalize(self, context: Context) -> None:
         # There needs to be a valid SCC in order to extract any properties
-        representative_scc = ctx.representative_scc
+        representative_scc = context.representative_scc
         if representative_scc is None:
             return
 
         # Fetch resources
         sec_enc = self.backend.get_mi2_section(Encyclopedia.m_def)
         properties = sec_enc.properties
-        properties.scc_index = int(ctx.representative_scc_idx)
-        run_type = ctx.run_type
-        material_type = ctx.material_type
-        sec_system = ctx.representative_system
-        gcd = ctx.greatest_common_divisor
+        run_type = context.run_type
+        material_type = context.material_type
+        sec_system = context.representative_system
+        gcd = context.greatest_common_divisor
 
         # Save metainfo
-        self.band_structure(properties, run_type, material_type, representative_scc, sec_system)
+        self.band_structure(properties, run_type, material_type, context, sec_system)
         self.energies(properties, gcd, representative_scc)
diff --git a/tests/normalizing/test_encyclopedia.py b/tests/normalizing/test_encyclopedia.py
index 0bb4d6bd295318e32e1800bbdc8b367f974b9381..3f99590058f55b5152cf9e832ad626601f101927 100644
--- a/tests/normalizing/test_encyclopedia.py
+++ b/tests/normalizing/test_encyclopedia.py
@@ -73,17 +73,19 @@ def test_1d_metainfo(one_d: LocalBackend):
     """
     enc = one_d.get_mi2_section(Encyclopedia.m_def)
     # Material
-    assert enc.material.material_type == "1D"
-    assert enc.material.formula == "C6H4"
-    assert enc.material.formula_reduced == "C3H2"
-    assert np.array_equal(enc.material.periodicity, [True, False, False])
+    material = enc.material
+    assert material.material_type == "1D"
+    assert material.formula == "C6H4"
+    assert material.formula_reduced == "C3H2"
 
-    # Representative system
-    assert enc.material.number_of_atoms == 10
-    assert enc.material.atom_labels == ["C", "C", "C", "C", "C", "C", "H", "H", "H", "H"]
-    assert enc.material.atom_positions is not None
-    assert enc.material.cell_normalized is not None
-    assert np.allclose(enc.material.lattice_parameters, [4.33793652e-10, 0, 0, 0, 0, 0], atol=0)
+    # Idealized structure
+    ideal = enc.material.idealized_structure
+    assert ideal.number_of_atoms == 10
+    assert ideal.atom_labels == ["C", "C", "C", "C", "C", "C", "H", "H", "H", "H"]
+    assert ideal.atom_positions is not None
+    assert ideal.lattice_vectors is not None
+    assert np.array_equal(ideal.periodicity, [True, False, False])
+    assert np.allclose(ideal.lattice_parameters, [4.33793652e-10, 0, 0, 0, 0, 0], atol=0)
 
 
 def test_2d_metainfo(two_d: LocalBackend):
@@ -91,18 +93,20 @@ def test_2d_metainfo(two_d: LocalBackend):
     """
     enc = two_d.get_mi2_section(Encyclopedia.m_def)
     # Material
-    assert enc.material.material_type == "2D"
-    assert enc.material.formula == "C2"
-    assert enc.material.formula_reduced == "C"
-    assert np.array_equal(enc.material.periodicity, [True, True, False])
-
-    # Representative system
-    assert enc.material.number_of_atoms == 2
-    assert enc.material.atom_labels == ["C", "C"]
-    assert enc.material.atom_positions is not None
-    assert enc.material.cell_normalized is not None
-    assert enc.material.cell_primitive is not None
-    assert np.allclose(enc.material.lattice_parameters, [2.46559821e-10, 2.46559821e-10, 0, 120 / 180 * np.pi, 0, 0], atol=0)
+    material = enc.material
+    assert material.material_type == "2D"
+    assert material.formula == "C2"
+    assert material.formula_reduced == "C"
+
+    # Idealized structure
+    ideal = enc.material.idealized_structure
+    assert ideal.number_of_atoms == 2
+    assert ideal.atom_labels == ["C", "C"]
+    assert ideal.atom_positions is not None
+    assert ideal.lattice_vectors is not None
+    assert ideal.lattice_vectors_primitive is not None
+    assert np.array_equal(ideal.periodicity, [True, True, False])
+    assert np.allclose(ideal.lattice_parameters, [2.46559821e-10, 2.46559821e-10, 0, 120 / 180 * np.pi, 0, 0], atol=0)
 
 
 def test_bulk_metainfo(bulk: LocalBackend):
@@ -110,36 +114,40 @@ def test_bulk_metainfo(bulk: LocalBackend):
     """
     enc = bulk.get_mi2_section(Encyclopedia.m_def)
     # Material
-    assert enc.material.material_type == "bulk"
-    assert enc.material.formula == "Si2"
-    assert enc.material.formula_reduced == "Si"
-    assert enc.material.material_name == "Silicon"
-    assert enc.material.structure_type == "diamond"
-    assert enc.material.structure_prototype == "C"
-    assert enc.material.strukturbericht_designation == "A4"
-
-    # Symmetry
-    assert enc.material.crystal_system == "cubic"
-    assert enc.material.bravais_lattice == "cF"
-    assert enc.material.has_free_wyckoff_parameters is False
-    assert enc.material.point_group == "m-3m"
-    assert enc.material.wyckoff_sets is not None
-    assert enc.material.space_group_number == 227
-    assert enc.material.space_group_international_short_symbol == "Fd-3m"
-
-    # Representative system
-    assert enc.material.number_of_atoms == 8
-    assert enc.material.atom_labels == ["Si", "Si", "Si", "Si", "Si", "Si", "Si", "Si"]
-    assert enc.material.atom_positions is not None
-    assert enc.material.cell_normalized is not None
-    assert enc.material.cell_primitive is not None
-    assert np.array_equal(enc.material.periodicity, [True, True, True])
-    assert enc.material.lattice_parameters is not None
-    assert enc.material.cell_volume == pytest.approx(5.431**3 * 1e-30)
-
-    # Calculation
-    assert enc.properties.atomic_density == pytest.approx(4.99402346512432e+28)
-    assert enc.properties.mass_density == pytest.approx(8 * 28.0855 * 1.6605389e-27 / (5.431**3 * 1e-30))  # Atomic mass in kg/m^3
+    material = enc.material
+    assert material.material_type == "bulk"
+    assert material.formula == "Si2"
+    assert material.formula_reduced == "Si"
+    assert material.material_name == "Silicon"
+
+    # Bulk
+    bulk = enc.material.bulk
+    assert bulk.crystal_system == "cubic"
+    assert bulk.bravais_lattice == "cF"
+    assert bulk.has_free_wyckoff_parameters is False
+    assert bulk.point_group == "m-3m"
+    assert bulk.wyckoff_sets is not None
+    assert bulk.space_group_number == 227
+    assert bulk.structure_type == "diamond"
+    assert bulk.structure_prototype == "C"
+    assert bulk.strukturbericht_designation == "A4"
+    assert bulk.space_group_international_short_symbol == "Fd-3m"
+
+    # Idealized structure
+    ideal = enc.material.idealized_structure
+    assert ideal.number_of_atoms == 8
+    assert ideal.atom_labels == ["Si", "Si", "Si", "Si", "Si", "Si", "Si", "Si"]
+    assert ideal.atom_positions is not None
+    assert ideal.lattice_vectors is not None
+    assert ideal.lattice_vectors_primitive is not None
+    assert np.array_equal(ideal.periodicity, [True, True, True])
+    assert ideal.lattice_parameters is not None
+    assert ideal.cell_volume == pytest.approx(5.431**3 * 1e-30)
+
+    # Properties
+    prop = enc.properties
+    assert prop.atomic_density == pytest.approx(4.99402346512432e+28)
+    assert prop.mass_density == pytest.approx(8 * 28.0855 * 1.6605389e-27 / (5.431**3 * 1e-30))  # Atomic mass in kg/m^3
 
 
 def test_1d_material_identification():
@@ -404,9 +412,10 @@ def test_1d_structure_structure_at_cell_boundary():
         "C",
     ]
 
-    assert np.allclose(enc.material.atom_positions, expected_pos)
-    assert np.array_equal(enc.material.atom_labels, expected_labels)
-    assert np.allclose(enc.material.cell_normalized, expected_cell)
+    ideal = enc.material.idealized_structure
+    assert np.allclose(ideal.atom_positions, expected_pos)
+    assert np.array_equal(ideal.atom_labels, expected_labels)
+    assert np.allclose(ideal.lattice_vectors, expected_cell)
 
 
 def test_2d_structure_structure_at_cell_boundary():
@@ -444,9 +453,10 @@ def test_2d_structure_structure_at_cell_boundary():
         "C",
     ]
 
-    assert np.allclose(enc.material.atom_positions, expected_pos)
-    assert np.array_equal(enc.material.atom_labels, expected_labels)
-    assert np.allclose(enc.material.cell_normalized, expected_cell)
+    ideal = enc.material.idealized_structure
+    assert np.allclose(ideal.atom_positions, expected_pos)
+    assert np.array_equal(ideal.atom_labels, expected_labels)
+    assert np.allclose(ideal.lattice_vectors, expected_cell)
 
 
 def test_method_dft_metainfo(single_point):