diff --git a/dependencies/parsers/electronic b/dependencies/parsers/electronic
index 5c077f48adcda8e6ec2f5cfb2220adc04100c3e6..62a093b8d34752675e4203b53629a201caf57391 160000
--- a/dependencies/parsers/electronic
+++ b/dependencies/parsers/electronic
@@ -1 +1 @@
-Subproject commit 5c077f48adcda8e6ec2f5cfb2220adc04100c3e6
+Subproject commit 62a093b8d34752675e4203b53629a201caf57391
diff --git a/gui/src/components/entry/properties/ElectronicPropertiesCard.js b/gui/src/components/entry/properties/ElectronicPropertiesCard.js
index ca81caf2cb0d98bbd76061ab1984c2597203bc6f..5a3b94587064ee05f81e7d6eb5170ae4cf73f384 100644
--- a/gui/src/components/entry/properties/ElectronicPropertiesCard.js
+++ b/gui/src/components/entry/properties/ElectronicPropertiesCard.js
@@ -15,20 +15,33 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react'
+import React, { useMemo } from 'react'
 import PropTypes from 'prop-types'
 import { PropertyCard } from './PropertyCard'
-import { getLocation, resolveInternalRef } from '../../../utils'
+import { getLocation, resolveInternalRef, parseNomadUrl } from '../../../utils'
 import ElectronicProperties from '../../visualization/ElectronicProperties'
 import { refPath } from '../../archive/metainfo'
+import { useEntryStoreObj } from '../../DataStore'
+// import { useEntryPageContext } from '../EntryPageContext'
+// import { useApi } from '../../api'
 
 const ElectronicPropertiesCard = React.memo(({index, properties, archive}) => {
   const urlPrefix = `${getLocation()}/data`
+  // const {installationUrl} = useEntryPageContext()
+  // const api = useApi()
 
   // Find out which properties are present
   const hasDos = properties.has('dos_electronic')
   const hasBs = properties.has('band_structure_electronic')
 
+  // const loadArchive = useMemo((url) => {
+  //   const parsedUrl = parseNomadUrl(url)
+  //   const entryStoreObj = useEntryStoreObj(parsedUrl.installationUrl, parsedUrl.entryId, false, '*')
+  //   return entryStoreObj.archive
+  // })
+  console.log(useEntryStoreObj, useMemo, parseNomadUrl)
+  console.log(typeof archive)
+
   // Do not show the card if none of the properties are available
   if (!hasDos && !hasBs) {
     return null
@@ -36,17 +49,38 @@ const ElectronicPropertiesCard = React.memo(({index, properties, archive}) => {
 
   // Resolve DOS data
   let dos = hasDos ? undefined : false
+  // const dos = []
   const dosData = archive?.results?.properties?.electronic?.dos_electronic
   if (dosData) {
-    dos = {}
-    dos.energies = resolveInternalRef(dosData.energies, archive)
-    dos.densities = resolveInternalRef(dosData.total, archive).map(dos => dos.value)
-    if (dosData.band_gap) {
-      dos.energy_highest_occupied = Math.max(...dosData.band_gap.map(x => x.energy_highest_occupied))
-    }
-    dos.m_path = `${urlPrefix}/${refPath(dosData.energies.split('/').slice(0, -1).join('/'))}`
+    dos = []
+    const dosArchive = archive
+    dosData.forEach(source => {
+      const d = {}
+      if (!source.energies.startsWith('/')) {
+        console.log(source)
+        // dosArchive = loadArchive(source.energies)
+      } else {
+        d.energies = resolveInternalRef(source.energies, dosArchive)
+        d.densities = resolveInternalRef(source.total, dosArchive).map(dos => dos.value)
+      }
+      // if (source.energies.startswith('../entries')) {
+      //   // resolve first external archive
+      //   const uploadId = archive?.metadata?.upload_id
+      //   const entryId = archive?.metadata?.entry_id
+      //   const baseUrl = `${installationUrl}/uploads/${uploadId}/archive/${entryId}`
+      //   const path = source.energies
+      //   const url = resolveNomadUrl(source.energies, baseUrl)
+      //   api.post(`/entries/${url.entryId}/archive/query`, {required: '*'})
+      // }
+      d.name = source.name
+      if (source.band_gap) {
+        d.energy_highest_occupied = Math.max(...source.band_gap.map(x => x.energy_highest_occupied))
+      }
+      d.m_path = `${urlPrefix}/${refPath(source.energies.split('/').slice(0, -1).join('/'))}`
+      if (d.energies && d.densities) dos.push(d)
+  })
+    dos = dos.length === 0 ? false : dos
   }
-
   // Resolve data for band structure, brillouin zone and band gaps.
   let bs = hasBs ? undefined : false
   let band_gap = hasBs ? undefined : false
diff --git a/gui/src/components/visualization/DOS.js b/gui/src/components/visualization/DOS.js
index 4a1e5235b1d356aaa341ea4b6f56376e4900807a..4ae3775a55dac2d321306d33715fd63332e7acc5 100644
--- a/gui/src/components/visualization/DOS.js
+++ b/gui/src/components/visualization/DOS.js
@@ -77,72 +77,80 @@ const DOS = React.memo(({
       return
     }
 
-    // Determine the energy reference.
-    let energyHighestOccupied
+    // Create the final data that will be plotted.
+    const plotData = []
     let normalized
-    if (type === 'vibrational') {
-      energyHighestOccupied = 0
-      normalized = true
-    } else {
-      if (data.energy_highest_occupied === undefined) {
+    const mins = []
+    const maxes = []
+    data.forEach((d, n) => {
+      console.log(d)
+          // Determine the energy reference.
+      let energyHighestOccupied
+      if (type === 'vibrational') {
         energyHighestOccupied = 0
-        normalized = false
-      } else {
-        energyHighestOccupied = new Quantity(data.energy_highest_occupied, energyUnit).toSystem(units).value()
         normalized = true
+      } else {
+        if (d.energy_highest_occupied === undefined) {
+          energyHighestOccupied = 0
+          normalized = false
+        } else {
+          energyHighestOccupied = new Quantity(d.energy_highest_occupied, energyUnit).toSystem(units).value()
+          normalized = true
+        }
       }
-    }
 
-    // Convert units and determine range
-    const mins = []
-    const maxes = []
-    const nChannels = data.densities.length
-    let energies = new Quantity(data.energies, energyUnit).toSystem(units).value()
-    const values1 = new Quantity(data.densities[0], valueUnit).toSystem(units).value()
-    let values2
-    mins.push(Math.min(...values1))
-    maxes.push(Math.max(...values1))
-    if (nChannels === 2) {
-      values2 = new Quantity(data.densities[1], valueUnit).toSystem(units).value()
-      mins.push(Math.min(...values2))
-      maxes.push(Math.max(...values2))
-    }
-    const range = [Math.min(...mins), Math.max(...maxes)]
-    if (energyHighestOccupied !== 0) {
-      energies = add(energies, -energyHighestOccupied)
-    }
+      // Convert units and determine range
+      const nChannels = d.densities.length
+      let energies = new Quantity(d.energies, energyUnit).toSystem(units).value()
+      const values1 = new Quantity(d.densities[0], valueUnit).toSystem(units).value()
+      let values2
+      mins.push(Math.min(...values1))
+      maxes.push(Math.max(...values1))
+      if (nChannels === 2) {
+        values2 = new Quantity(d.densities[1], valueUnit).toSystem(units).value()
+        mins.push(Math.min(...values2))
+        maxes.push(Math.max(...values2))
+      }
+      if (energyHighestOccupied !== 0) {
+        energies = add(energies, -energyHighestOccupied)
+      }
 
-    // Create the final data that will be plotted.
-    const plotData = []
-    if (nChannels === 2) {
+      const dash = (d.name !== undefined && n === 1) ? 'dot' : undefined
+      if (nChannels === 2) {
+        plotData.push(
+          {
+            x: values2,
+            y: energies,
+            type: 'scatter',
+            mode: 'lines',
+            showlegend: false,
+            line: {
+              color: theme.palette.secondary.main,
+              width: 2,
+              dash: dash
+            }
+          }
+        )
+      }
       plotData.push(
         {
-          x: values2,
+          x: values1,
           y: energies,
+          name: d.name,
           type: 'scatter',
           mode: 'lines',
-          showlegend: false,
+          showlegend: d.name !== undefined,
           line: {
-            color: theme.palette.secondary.main,
-            width: 2
+            color: theme.palette.primary.main,
+            width: 2,
+            dash: dash
           }
         }
       )
-    }
-    plotData.push(
-      {
-        x: values1,
-        y: energies,
-        type: 'scatter',
-        mode: 'lines',
-        showlegend: false,
-        line: {
-          color: theme.palette.primary.main,
-          width: 2
-        }
-      }
-    )
+    })
 
+    const range = [Math.min(...mins), Math.max(...maxes)]
+    console.log(range)
     // Normalization line
     if (type !== 'vibrational' && normalizedToHOE) {
       plotData.push({
@@ -197,12 +205,13 @@ const DOS = React.memo(({
 DOS.propTypes = {
   data: PropTypes.oneOfType([
     PropTypes.bool, // Set to False to show NoData component
-    PropTypes.shape({
+    PropTypes.arrayOf(PropTypes.shape({
       energies: PropTypes.array.isRequired, // DOS energies array
       densities: PropTypes.array.isRequired, // DOS values array
       energy_highest_occupied: PropTypes.number, // Highest occupied energy.
-      m_path: PropTypes.string // Path of the section containing the data in the Archive
-    })
+      m_path: PropTypes.string, // Path of the section containing the data in the Archive
+      name: PropTypes.string
+    }))
   ]),
   layout: PropTypes.object,
   className: PropTypes.string,
diff --git a/nomad/datamodel/metainfo/workflow.py b/nomad/datamodel/metainfo/workflow.py
index 907e4b87e7fa46773fd68c4c041e573b06e35c7e..e91c4726668c2fddeab40051338fd5e6a90b3704 100644
--- a/nomad/datamodel/metainfo/workflow.py
+++ b/nomad/datamodel/metainfo/workflow.py
@@ -4,7 +4,7 @@ from nptyping import NDArray
 from nomad.metainfo import (  # pylint: disable=unused-import
     MSection, MEnum, Quantity, Section, SubSection, SectionProxy,
     Reference, derived)
-from nomad.datamodel.metainfo.simulation.calculation import Calculation
+from nomad.datamodel.metainfo.simulation.calculation import Calculation, Dos
 from nomad.datamodel.metainfo.simulation.run import Run
 from nomad.datamodel.metainfo.simulation.system import System, Atoms, AtomsGroup
 from .common import FastAccess
@@ -1988,6 +1988,40 @@ class MeanSquaredDisplacement(CorrelationFunction):
     mean_squared_displacement_values = SubSection(sub_section=MeanSquaredDisplacementValues.m_def, repeats=True)
 
 
+class GW(MSection):
+    '''
+    Section containing results of a GW workflow
+    '''
+
+    m_def = Section(validate=False)
+
+    # TODO external referencing is a bit tricky for the gui
+    dos_dft = Quantity(
+        type=Reference(Dos),
+        description='''
+        DFT density of states
+        ''')
+
+    dos_gw = Quantity(
+        type=Reference(Dos),
+        description='''
+        GW density of states
+        ''')
+
+    # dos_dft = Quantity(
+    #     type=Dos,
+    #     shape=['*']
+    # )
+    # dos_gw = Quantity(
+    #     type=Dos,
+    #     shape=['*']
+    # )
+
+    # dos_dft = SubSection(sub_section=Dos.m_def, repeats=False)
+
+    # dos_gw = SubSection(sub_section=Dos.m_def, repeats=False)
+
+
 class SinglePoint(MSection):
     '''
     Section containing results of a single point workflow.
@@ -2120,6 +2154,7 @@ class Workflow(MSection):
 
     type = Quantity(
         type=MEnum([
+            "gw",
             "single_point",
             "geometry_optimization",
             "phonon",
@@ -2208,8 +2243,11 @@ class Workflow(MSection):
 
     single_point = SubSection(
         sub_section=SinglePoint.m_def,
-        # TODO determine if there is a need for this to be a repeating section
-        # such as in the context of fhi-vibes single_point
+        repeats=False,
+        categories=[FastAccess])
+
+    gw = SubSection(
+        sub_section=GW.m_def,
         repeats=False,
         categories=[FastAccess])
 
diff --git a/nomad/datamodel/results.py b/nomad/datamodel/results.py
index a166e4a45434de38d1978d78086f500f51e54460..f12faacf8f1d223b07383f41060f8c653aa0176c 100644
--- a/nomad/datamodel/results.py
+++ b/nomad/datamodel/results.py
@@ -1519,6 +1519,12 @@ class DOSElectronic(DOS):
         Contains the total electronic density of states.
         ''',
     )
+    name = Quantity(
+        type=str,
+        description='''
+        Label to identify the DOS data, e.g. the method employed.
+        ''')
+
     spin_polarized = Quantity(
         type=bool,
         description='''
@@ -1824,7 +1830,7 @@ class ElectronicProperties(MSection):
         ''',
     )
     band_structure_electronic = SubSection(sub_section=BandStructureElectronic.m_def, repeats=False)
-    dos_electronic = SubSection(sub_section=DOSElectronic.m_def, repeats=False)
+    dos_electronic = SubSection(sub_section=DOSElectronic.m_def, repeats=True)
 
 
 class QuantityDynamic(MSection):
diff --git a/nomad/normalizing/results.py b/nomad/normalizing/results.py
index 765919918959cd1f830fb785e8aab51d35ae362b..f2d6a25a8e6cc993fecf0d9808b705f1674b600d 100644
--- a/nomad/normalizing/results.py
+++ b/nomad/normalizing/results.py
@@ -278,7 +278,7 @@ class ResultsNormalizer(Normalizer):
 
         return None
 
-    def dos_electronic(self) -> Union[DOSElectronic, None]:
+    def dos_electronic(self) -> List[Union[DOSElectronic, None]]:
         """Returns a reference to the section containing an electronic dos. In
         the case of multiple valid DOSes, only the latest one is reported.
 
@@ -286,25 +286,40 @@ class ResultsNormalizer(Normalizer):
           - There is a non-empty array of dos_values_normalized.
           - There is a non-empty array of dos_energies.
         """
-        path = ["run", "calculation", "dos_electronic"]
-        for dos in self.traverse_reversed(path):
-            energies = dos.energies
-            values = np.array([d.value.magnitude for d in dos.total])
-            if valid_array(energies) and valid_array(values):
-                dos_new = DOSElectronic()
-                dos_new.energies = dos
-                dos_new.total = dos.total
-                n_channels = values.shape[0]
-                dos_new.spin_polarized = n_channels > 1
-                dos_new.energy_fermi = dos.energy_fermi
-                for info in dos.band_gap:
-                    info_new = dos_new.m_create(BandGap)
-                    info_new.index = info.index
-                    info_new.energy_highest_occupied = info.energy_highest_occupied
-                    info_new.energy_lowest_unoccupied = info.energy_lowest_unoccupied
-                return dos_new
 
-        return None
+        def resolve_dos(path):
+            for dos in self.traverse_reversed(path):
+                energies = dos.energies
+                values = np.array([d.value.magnitude for d in dos.total])
+                if valid_array(energies) and valid_array(values):
+                    dos_new = DOSElectronic()
+                    dos_new.energies = dos
+                    dos_new.total = dos.total
+                    n_channels = values.shape[0]
+                    dos_new.spin_polarized = n_channels > 1
+                    dos_new.energy_fermi = dos.energy_fermi
+                    for info in dos.band_gap:
+                        info_new = dos_new.m_create(BandGap)
+                        info_new.index = info.index
+                        info_new.energy_highest_occupied = info.energy_highest_occupied
+                        info_new.energy_lowest_unoccupied = info.energy_lowest_unoccupied
+                    return dos_new
+
+        try:
+            workflow_type = self.entry_archive.workflow[-1].type
+        except Exception:
+            workflow_type = None
+
+        if workflow_type == 'gw':
+            dos_dft = resolve_dos(["workflow", "gw", "dos_dft"])
+            dos_dft.name = 'DFT'
+            dos_gw = resolve_dos(["workflow", "gw", "dos_gw"])
+            dos_gw.name = 'GW'
+            return [dos_dft, dos_gw] if dos_dft and dos_gw else []
+        elif workflow_type == 'single_point':
+            return [resolve_dos(["run", "calculation", "dos_electronic"])]
+        else:
+            return []
 
     def band_structure_phonon(self) -> Union[BandStructurePhonon, None]:
         """Returns a new section containing a phonon band structure. In
diff --git a/nomad/normalizing/workflow.py b/nomad/normalizing/workflow.py
index e5a1a5adbdc105c0794ac2ca2dfb41322296f83a..770420e458685690818b5aadfe60d89e37331d46 100644
--- a/nomad/normalizing/workflow.py
+++ b/nomad/normalizing/workflow.py
@@ -507,7 +507,9 @@ class WorkflowNormalizer(Normalizer):
         if not self.entry_archive.run:
             return
 
+        created = False
         if not self.entry_archive.workflow:
+            created = True
             self.entry_archive.m_create(Workflow)
 
         for n, sec_workflow in enumerate(self.entry_archive.workflow):
@@ -547,5 +549,5 @@ class WorkflowNormalizer(Normalizer):
             ThermodynamicsNormalizer(self.entry_archive, n).normalize()
 
             # remove the section workflow again, if the parser/normalizer could not produce a result
-            if sec_workflow.calculation_result_ref is None:
+            if sec_workflow.calculation_result_ref is None and created:
                 self.entry_archive.m_remove_sub_section(EntryArchive.workflow, n)
diff --git a/nomad/parsing/parser.py b/nomad/parsing/parser.py
index e488a22d94a807d179430c7c5f02c1f86fdf3aff..26cdd0984ab499bd59ead0fe71b0210578eb7fba 100644
--- a/nomad/parsing/parser.py
+++ b/nomad/parsing/parser.py
@@ -347,6 +347,9 @@ class MatchingParserInterface(MatchingParser):
         return self._mainfile_parser
 
     def parse(self, mainfile: str, archive: EntryArchive, logger=None, child_archives=None):
+        # TODO include child_archives in parse
+        if child_archives:
+            self.mainfile_parser._child_archives = child_archives
         self.mainfile_parser.parse(mainfile, archive, logger)
 
     def import_parser_class(self):
@@ -361,6 +364,22 @@ class MatchingParserInterface(MatchingParser):
 
         return parser
 
+    def is_mainfile(
+            self, filename: str, mime: str, buffer: bytes, decoded_buffer: str,
+            compression: str = None) -> Union[bool, Iterable[str]]:
+        is_mainfile = super().is_mainfile(
+            filename=filename, mime=mime, buffer=buffer,
+            decoded_buffer=decoded_buffer, compression=compression)
+        if is_mainfile:
+            try:
+                self.creates_children = True
+                # try to resolve mainfile keys from parser
+                mainfile_keys = self.mainfile_parser.get_mainfile_keys(filename)
+                return mainfile_keys
+            except Exception:
+                return is_mainfile
+        return is_mainfile
+
 
 class ArchiveParser(MatchingParser):
     def __init__(self):