From d868fb16249251e8b4915ea1bdb5273155b6162e Mon Sep 17 00:00:00 2001 From: Edward Linscott Date: Wed, 8 Jul 2026 10:31:52 +0200 Subject: [PATCH 1/6] Handle nscf outputs that lack the scf-Fermi stdout marker QE >= 7.6-dev no longer prints the "(compare with: ... computed in scf)" line in nscf runs, so get_fermi_energy_from_nscf silently returned None, which then crashed deep inside the .win writer with an opaque "Invalid value" error. Fall back to the Fermi energy the parser extracted from the nscf output itself, and raise loudly in prepare_wannier90_pp_inputs if the value still resolves to None. Co-Authored-By: Claude Fable 5 --- src/aiida_wannier90_workflows/utils/workflows/pw.py | 9 ++++++++- src/aiida_wannier90_workflows/workflows/wannier90.py | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/aiida_wannier90_workflows/utils/workflows/pw.py b/src/aiida_wannier90_workflows/utils/workflows/pw.py index f4b3635c..cd546f7b 100644 --- a/src/aiida_wannier90_workflows/utils/workflows/pw.py +++ b/src/aiida_wannier90_workflows/utils/workflows/pw.py @@ -28,7 +28,7 @@ def get_fermi_energy(output_parameters: orm.Dict) -> ty.Optional[float]: def get_fermi_energy_from_nscf( calc_nscf: ty.Union[PwBaseWorkChain, PwCalculation] -) -> float: +) -> ty.Optional[float]: """Parse nscf output to get the scf Fermi energy. :param calc_nscf: a nscf PwBaseWorkChain or PwCalculation @@ -69,4 +69,11 @@ def get_fermi_energy_from_nscf( fermi_energy = float(match.group(1)) break + if fermi_energy is None: + # Newer QE versions no longer print the "(compare with: ... computed + # in scf)" companion line in nscf runs; fall back to the Fermi energy + # the parser extracted from the nscf output itself. + output_parameters = calc_nscf.outputs.output_parameters.get_dict() + fermi_energy = output_parameters.get("fermi_energy") + return fermi_energy diff --git a/src/aiida_wannier90_workflows/workflows/wannier90.py b/src/aiida_wannier90_workflows/workflows/wannier90.py index abee5dce..f6346a1b 100644 --- a/src/aiida_wannier90_workflows/workflows/wannier90.py +++ b/src/aiida_wannier90_workflows/workflows/wannier90.py @@ -820,6 +820,13 @@ def prepare_wannier90_pp_inputs(self): # pylint: disable=too-many-statements fermi_energy = parameters["fermi_energy"] else: raise ValueError("Cannot retrieve Fermi energy from scf or nscf output") + if fermi_energy is None: + # Fail loudly here rather than passing None through to the .win + # writer, which rejects it with an opaque "Invalid value" error. + raise ValueError( + f"Fermi energy resolved to None (nscf {self.ctx.get('workchain_nscf', 'N/A')}): " + "neither the stdout marker nor the parsed output_parameters provided a value." + ) parameters["fermi_energy"] = fermi_energy inputs.parameters = orm.Dict(parameters) From a594b2c37ccbca6238e45254ddf26e89ca1f0411 Mon Sep 17 00:00:00 2001 From: Edward Linscott Date: Mon, 13 Jul 2026 15:33:05 +0200 Subject: [PATCH 2/6] Handle per-channel Fermi energies in the nscf fallback Spin-polarised runs with a constrained total magnetization report fermi_energy_up / fermi_energy_down instead of a single fermi_energy; take the highest of the two (the electron chemical potential across both channels). Co-Authored-By: Claude Fable 5 --- src/aiida_wannier90_workflows/utils/workflows/pw.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/aiida_wannier90_workflows/utils/workflows/pw.py b/src/aiida_wannier90_workflows/utils/workflows/pw.py index cd546f7b..a2171308 100644 --- a/src/aiida_wannier90_workflows/utils/workflows/pw.py +++ b/src/aiida_wannier90_workflows/utils/workflows/pw.py @@ -75,5 +75,13 @@ def get_fermi_energy_from_nscf( # the parser extracted from the nscf output itself. output_parameters = calc_nscf.outputs.output_parameters.get_dict() fermi_energy = output_parameters.get("fermi_energy") + if fermi_energy is None: + # Spin-polarised runs with a constrained total magnetization + # report one Fermi level per channel; take the highest (the + # electron chemical potential across both channels). + up = output_parameters.get("fermi_energy_up") + down = output_parameters.get("fermi_energy_down") + if up is not None and down is not None: + fermi_energy = max(up, down) return fermi_energy From f7c22f4daf5cd1ea91399056d3d56b2fe926fd43 Mon Sep 17 00:00:00 2001 From: Edward Linscott Date: Fri, 17 Jul 2026 11:11:42 +0200 Subject: [PATCH 3/6] Guard nscf Fermi-energy fallback on units and cover all callers The nscf fallback read output_parameters["fermi_energy"] with no units check, unlike get_fermi_energy which returns None unless the units are eV; add the same units guard so a non-eV value cannot be returned silently. Reword the fallback's docstring/comments: the stdout marker is governed by the nscf occupation/spin type (QE prints the single-value "compare with" line only for a metallic, single-Fermi-energy nscf), not by QE version, and max(up, down) is a conservative frozen-window reference, not a chemical potential. Also guard get_workchain_fermi_energy in plot/bands.py: its nscf branches consume the same helper and could return None into the band-plotting arithmetic, mirroring the guard already added in prepare_wannier90_pp_inputs. --- .../utils/workflows/plot/bands.py | 7 +++ .../utils/workflows/pw.py | 46 +++++++++++++------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/aiida_wannier90_workflows/utils/workflows/plot/bands.py b/src/aiida_wannier90_workflows/utils/workflows/plot/bands.py index 26565244..35512499 100755 --- a/src/aiida_wannier90_workflows/utils/workflows/plot/bands.py +++ b/src/aiida_wannier90_workflows/utils/workflows/plot/bands.py @@ -379,6 +379,13 @@ def get_workchain_fermi_energy( else: raise ValueError("Cannot find fermi energy") + if fermi_energy is None: + # `get_fermi_energy_from_nscf` (used by the nscf branches above) can + # return None when neither the stdout marker nor the parsed + # output_parameters yield a value. Fail loudly here rather than letting + # None flow into the band-plotting arithmetic downstream. + raise ValueError(f"Fermi energy from {workchain} resolved to None") + return fermi_energy diff --git a/src/aiida_wannier90_workflows/utils/workflows/pw.py b/src/aiida_wannier90_workflows/utils/workflows/pw.py index a2171308..b6fe4870 100644 --- a/src/aiida_wannier90_workflows/utils/workflows/pw.py +++ b/src/aiida_wannier90_workflows/utils/workflows/pw.py @@ -29,12 +29,19 @@ def get_fermi_energy(output_parameters: orm.Dict) -> ty.Optional[float]: def get_fermi_energy_from_nscf( calc_nscf: ty.Union[PwBaseWorkChain, PwCalculation] ) -> ty.Optional[float]: - """Parse nscf output to get the scf Fermi energy. + """Get a Fermi energy from an nscf run. + + Prefer the scf Fermi energy reported in the nscf stdout via the + ``(compare with: ... computed in scf)`` marker. When that marker is absent + (see the fallback below), return the nscf's own Fermi energy instead, taken + from the parsed ``output_parameters``. The two can differ; the scf value is + kept as the first choice to preserve existing behaviour. :param calc_nscf: a nscf PwBaseWorkChain or PwCalculation :type calc_nscf: ty.Union[PwBaseWorkChain, PwCalculation] - :return: scf Fermi energy - :rtype: float + :return: the scf Fermi energy if the stdout marker is present, otherwise the + nscf Fermi energy from ``output_parameters``, else None. Unit is eV. + :rtype: float, None """ import re @@ -70,18 +77,27 @@ def get_fermi_energy_from_nscf( break if fermi_energy is None: - # Newer QE versions no longer print the "(compare with: ... computed - # in scf)" companion line in nscf runs; fall back to the Fermi energy - # the parser extracted from the nscf output itself. + # The regex above only matches the single-value "(compare with: X eV, + # computed in scf)" marker. QE prints that marker only for a metallic + # (smearing/tetrahedra), single-Fermi-energy nscf run: insulators print + # HOMO/LUMO instead, and constrained-magnetization runs print a + # two-value variant the regex does not match (see QE + # PW/src/print_ks_energies.f90). In those cases fall back to the Fermi + # energy the parser stored from this nscf run. output_parameters = calc_nscf.outputs.output_parameters.get_dict() - fermi_energy = output_parameters.get("fermi_energy") - if fermi_energy is None: - # Spin-polarised runs with a constrained total magnetization - # report one Fermi level per channel; take the highest (the - # electron chemical potential across both channels). - up = output_parameters.get("fermi_energy_up") - down = output_parameters.get("fermi_energy_down") - if up is not None and down is not None: - fermi_energy = max(up, down) + # The aiida-quantumespresso parser always stores Fermi energies in eV, + # but guard on the units regardless, to mirror `get_fermi_energy` and + # avoid silently returning a value in the wrong unit. + if output_parameters.get("fermi_energy_units") == "eV": + fermi_energy = output_parameters.get("fermi_energy") + if fermi_energy is None: + # Spin-polarised runs with a constrained total magnetization + # report one Fermi level per channel and have no single chemical + # potential. Take the higher of the two as a conservative + # reference for the (frozen) energy windows. + up = output_parameters.get("fermi_energy_up") + down = output_parameters.get("fermi_energy_down") + if up is not None and down is not None: + fermi_energy = max(up, down) return fermi_energy From 3094bebb90996dac02e69eb24a9527191c16bf4e Mon Sep 17 00:00:00 2001 From: Edward Linscott Date: Fri, 17 Jul 2026 11:11:42 +0200 Subject: [PATCH 4/6] Add unit tests for get_fermi_energy_from_nscf Cover marker-present (scf value used), marker-absent fallback to the parsed nscf Fermi energy, the spin-polarised max(up, down) branch, the None-when-unavailable case, and the non-eV units guard. Pure-function tests with stubbed nodes; not executed under pytest in this environment because the suite's autouse fixture requires a database profile. --- tests/utils/workflows/test_pw.py | 116 +++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 tests/utils/workflows/test_pw.py diff --git a/tests/utils/workflows/test_pw.py b/tests/utils/workflows/test_pw.py new file mode 100644 index 00000000..e63b8436 --- /dev/null +++ b/tests/utils/workflows/test_pw.py @@ -0,0 +1,116 @@ +"""Unit tests for :py:mod:`aiida_wannier90_workflows.utils.workflows.pw`.""" + +import pytest + +from aiida_quantumespresso.calculations.pw import PwCalculation + +from aiida_wannier90_workflows.utils.workflows.pw import get_fermi_energy_from_nscf + +# stdout of an nscf run that still prints the scf-Fermi companion marker. +NSCF_STDOUT_WITH_MARKER = """ + End of band structure calculation + + the Fermi energy is 5.9816 ev + (compare with: 5.9034 eV, computed in scf) + + Writing output data file aiida.save +""" + +# stdout of an nscf run that only prints its own Fermi energy (no marker). +NSCF_STDOUT_WITHOUT_MARKER = """ + End of band structure calculation + + the Fermi energy is 5.9816 ev + + Writing output data file aiida.save +""" + + +class _FakeRetrieved: + """Stand in for the ``retrieved`` FolderData node.""" + + def __init__(self, content): + self._content = content + + def get_object_content(self, name): # pylint: disable=unused-argument + return self._content + + +class _FakeDict: + """Stand in for an ``orm.Dict`` output node.""" + + def __init__(self, dictionary): + self._dictionary = dictionary + + def get_dict(self): + return dict(self._dictionary) + + +class _FakeOutputs: + def __init__(self, stdout, output_parameters): + self.retrieved = _FakeRetrieved(stdout) + self.output_parameters = _FakeDict(output_parameters) + + +class _FakeNscfCalc: + """Minimal stub of a finished nscf ``PwCalculation`` node. + + Only the attributes accessed by ``get_fermi_energy_from_nscf`` are + implemented, so the test needs no AiiDA profile or database. + """ + + process_class = PwCalculation + is_finished_ok = True + + def __init__(self, stdout, output_parameters): + self.outputs = _FakeOutputs(stdout, output_parameters) + + +def test_get_fermi_energy_from_nscf_marker_present(): + """Marker present: the scf value from stdout is used, not the fallback.""" + calc = _FakeNscfCalc( + NSCF_STDOUT_WITH_MARKER, + # A different value here would be returned only if the fallback ran. + {"fermi_energy": 7.0, "fermi_energy_units": "eV"}, + ) + assert get_fermi_energy_from_nscf(calc) == pytest.approx(5.9034) + + +def test_get_fermi_energy_from_nscf_fallback_to_parsed_value(): + """Marker absent: fall back to the parsed nscf Fermi energy.""" + calc = _FakeNscfCalc( + NSCF_STDOUT_WITHOUT_MARKER, + {"fermi_energy": 5.9816, "fermi_energy_units": "eV"}, + ) + assert get_fermi_energy_from_nscf(calc) == pytest.approx(5.9816) + + +def test_get_fermi_energy_from_nscf_fallback_spin_polarised(): + """Marker absent, two Fermi levels: return the higher of the two.""" + calc = _FakeNscfCalc( + NSCF_STDOUT_WITHOUT_MARKER, + { + "fermi_energy_up": 5.5, + "fermi_energy_down": 6.1, + "fermi_energy_units": "eV", + }, + ) + assert get_fermi_energy_from_nscf(calc) == pytest.approx(6.1) + + +def test_get_fermi_energy_from_nscf_returns_none_when_unavailable(): + """Marker absent and nothing parsed: return None (guarded by callers).""" + calc = _FakeNscfCalc( + NSCF_STDOUT_WITHOUT_MARKER, + {"fermi_energy_units": "eV"}, + ) + assert get_fermi_energy_from_nscf(calc) is None + + +def test_get_fermi_energy_from_nscf_ignores_non_ev_units(): + """A parsed Fermi energy in non-eV units is not used by the fallback.""" + calc = _FakeNscfCalc( + NSCF_STDOUT_WITHOUT_MARKER, + {"fermi_energy": 0.44, "fermi_energy_units": "Ry"}, + ) + assert get_fermi_energy_from_nscf(calc) is None From ba48565f3eafb82c80db93928b84a641d43693e5 Mon Sep 17 00:00:00 2001 From: Edward Linscott Date: Fri, 14 Aug 2026 12:07:51 +0200 Subject: [PATCH 5/6] Give the mocked scf output parameters their Fermi units test_scdm mocked the scf output_parameters with fermi_energy but no fermi_energy_units, so get_fermi_energy returned None and the new guard raised "Fermi energy resolved to None". Add the units key, and assert that the Fermi energy reaches the wannier90 pp parameters, which the test previously left unchecked. Also reword both guards: they named the nscf workchain and the stdout marker even when the scf branch produced the None, and said nothing about what to change. They now name the workchain actually consulted and the output_parameters keys it must carry. Co-Authored-By: Claude Fable 5 --- .../utils/workflows/plot/bands.py | 12 ++++++++---- .../workflows/wannier90.py | 14 +++++++++----- tests/workflows/test_wannier90.py | 9 ++++++++- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/aiida_wannier90_workflows/utils/workflows/plot/bands.py b/src/aiida_wannier90_workflows/utils/workflows/plot/bands.py index 35512499..47c0aff7 100755 --- a/src/aiida_wannier90_workflows/utils/workflows/plot/bands.py +++ b/src/aiida_wannier90_workflows/utils/workflows/plot/bands.py @@ -381,10 +381,14 @@ def get_workchain_fermi_energy( if fermi_energy is None: # `get_fermi_energy_from_nscf` (used by the nscf branches above) can - # return None when neither the stdout marker nor the parsed - # output_parameters yield a value. Fail loudly here rather than letting - # None flow into the band-plotting arithmetic downstream. - raise ValueError(f"Fermi energy from {workchain} resolved to None") + # return None. Fail loudly here rather than letting None flow into the + # band-plotting arithmetic downstream. + raise ValueError( + f"Could not read a Fermi energy from {workchain}. Its " + "`output_parameters` must contain `fermi_energy` (or both " + "`fermi_energy_up` and `fermi_energy_down`), together with " + "`fermi_energy_units` set to `eV`." + ) return fermi_energy diff --git a/src/aiida_wannier90_workflows/workflows/wannier90.py b/src/aiida_wannier90_workflows/workflows/wannier90.py index f6346a1b..36b3e185 100644 --- a/src/aiida_wannier90_workflows/workflows/wannier90.py +++ b/src/aiida_wannier90_workflows/workflows/wannier90.py @@ -811,11 +811,13 @@ def prepare_wannier90_pp_inputs(self): # pylint: disable=too-many-statements # Add Fermi energy if "workchain_scf" in self.ctx: - scf_output_parameters = self.ctx.workchain_scf.outputs.output_parameters - fermi_energy = get_fermi_energy(scf_output_parameters) + fermi_source = self.ctx.workchain_scf + fermi_energy = get_fermi_energy(fermi_source.outputs.output_parameters) elif "workchain_nscf" in self.ctx: - fermi_energy = get_fermi_energy_from_nscf(self.ctx.workchain_nscf) + fermi_source = self.ctx.workchain_nscf + fermi_energy = get_fermi_energy_from_nscf(fermi_source) else: + fermi_source = None if "fermi_energy" in parameters: fermi_energy = parameters["fermi_energy"] else: @@ -824,8 +826,10 @@ def prepare_wannier90_pp_inputs(self): # pylint: disable=too-many-statements # Fail loudly here rather than passing None through to the .win # writer, which rejects it with an opaque "Invalid value" error. raise ValueError( - f"Fermi energy resolved to None (nscf {self.ctx.get('workchain_nscf', 'N/A')}): " - "neither the stdout marker nor the parsed output_parameters provided a value." + f"Could not read a Fermi energy from {fermi_source}. Its " + "`output_parameters` must contain `fermi_energy` (or both " + "`fermi_energy_up` and `fermi_energy_down`), together with " + "`fermi_energy_units` set to `eV`." ) parameters["fermi_energy"] = fermi_energy diff --git a/tests/workflows/test_wannier90.py b/tests/workflows/test_wannier90.py index bc1a5568..6c4f866d 100644 --- a/tests/workflows/test_wannier90.py +++ b/tests/workflows/test_wannier90.py @@ -35,7 +35,11 @@ def test_scdm( scf_workchain, link_type=LinkType.RETURN, link_label="remote_folder" ) - params = orm.Dict({"fermi_energy": 6.0, "number_of_electrons": 8}) + # The pw.x parser always stores `fermi_energy_units` alongside + # `fermi_energy`; `get_fermi_energy` reads a value only when it does. + params = orm.Dict( + {"fermi_energy": 6.0, "fermi_energy_units": "eV", "number_of_electrons": 8} + ) params.store() params.base.links.add_incoming( scf_workchain, link_type=LinkType.RETURN, link_label="output_parameters" @@ -108,6 +112,9 @@ def test_scdm( # mock run wannier90 pp w90pp_workchain = workchain.run_wannier90_pp()["workchain_wannier90_pp"] + # The scf Fermi energy reaches the wannier90 parameters + assert w90pp_workchain.inputs.wannier90.parameters["fermi_energy"] == 6.0 + # The wannier90 step will use `get_last_calcjob` to retrieve input parameters of the calcjob entry_point_calc_job = "wannier90.wannier90" calcjob = generate_calc_job_node( From d184d2e767afcdfd3900fabd1e142bafba0ce8c3 Mon Sep 17 00:00:00 2001 From: Edward Linscott Date: Fri, 14 Aug 2026 17:59:02 +0200 Subject: [PATCH 6/6] Cover both Fermi-energy sources in the wannier90 pp inputs `prepare_wannier90_pp_inputs` picks the Fermi energy from the nscf run in the context or from the caller's wannier90 parameters, and no test drove either path: the existing `test_scdm` always has an scf run in context. - Read from the nscf run when the parameters carry no `fermi_energy`. - Keep the caller's `fermi_energy` when the parameters carry one, even though an nscf run is in the context. - Reject a `fermi_energy` of None in the parameters, with a message that names the parameters rather than the nscf run. --- tests/workflows/test_wannier90.py | 121 ++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/tests/workflows/test_wannier90.py b/tests/workflows/test_wannier90.py index 6c4f866d..cf0a2b5c 100644 --- a/tests/workflows/test_wannier90.py +++ b/tests/workflows/test_wannier90.py @@ -3,12 +3,26 @@ import io from plumpy.process_states import ProcessState +import pytest from aiida import orm from aiida.common import LinkType from aiida_quantumespresso.calculations.helpers import pw_input_helper +# The scf Fermi energy an nscf run reports in its stdout. Any test that reads a +# different value did not consult the nscf. +NSCF_SCF_FERMI_ENERGY = 5.9034 + +NSCF_STDOUT = f""" + End of band structure calculation + + the Fermi energy is 5.9816 ev + (compare with: {NSCF_SCF_FERMI_ENERGY} eV, computed in scf) + + Writing output data file aiida.save +""" + def test_scdm( generate_workchain_wannier90, @@ -198,3 +212,110 @@ def test_scdm( _ in workchain.outputs for _ in ("scf", "nscf", "projwfc", "wannier90_pp", "pw2wannier90", "wannier90") ) + + +def _generate_finished_nscf_calc(generate_calc_job_node, fixture_localhost): + """Return a finished nscf ``PwCalculation`` node whose stdout reports the scf Fermi energy.""" + node = generate_calc_job_node("quantumespresso.pw", fixture_localhost, store=False) + node.set_process_state(ProcessState.FINISHED) + node.set_exit_status(0) + node.store() + + retrieved = orm.FolderData() + retrieved.put_object_from_filelike(io.StringIO(NSCF_STDOUT), "aiida.out") + retrieved.base.links.add_incoming( + node, link_type=LinkType.CREATE, link_label="retrieved" + ) + retrieved.store() + + return node + + +def _generate_workchain_without_scf_context( + generate_workchain, + generate_inputs_wannier90, + generate_calc_job_node, + fixture_localhost, + w90_parameters, +): + """Return a ``Wannier90WorkChain`` whose context holds an nscf run but no scf run. + + ``w90_parameters`` are the wannier90 parameters the caller supplies, which is + where an externally computed Fermi energy would arrive. + """ + inputs = generate_inputs_wannier90() + inputs["wannier90"]["wannier90"]["parameters"] = orm.Dict(w90_parameters) + + workchain = generate_workchain("wannier90_workflows.wannier90", inputs) + workchain.setup() + workchain.ctx.workchain_nscf = _generate_finished_nscf_calc( + generate_calc_job_node, fixture_localhost + ) + + return workchain + + +def test_prepare_wannier90_pp_inputs_fermi_from_nscf( + generate_workchain, + generate_inputs_wannier90, + generate_calc_job_node, + fixture_localhost, +): # pylint: disable=redefined-outer-name + """Without a Fermi energy in the parameters, read it from the nscf run in the context.""" + workchain = _generate_workchain_without_scf_context( + generate_workchain, + generate_inputs_wannier90, + generate_calc_job_node, + fixture_localhost, + w90_parameters={}, + ) + + inputs = workchain.prepare_wannier90_pp_inputs() + + assert inputs["wannier90"]["parameters"]["fermi_energy"] == pytest.approx( + NSCF_SCF_FERMI_ENERGY + ) + + +def test_prepare_wannier90_pp_inputs_fermi_from_parameters( + generate_workchain, + generate_inputs_wannier90, + generate_calc_job_node, + fixture_localhost, +): # pylint: disable=redefined-outer-name + """A Fermi energy already in the parameters wins over the nscf run in the context.""" + given_fermi_energy = 1.23 + assert given_fermi_energy != NSCF_SCF_FERMI_ENERGY + + workchain = _generate_workchain_without_scf_context( + generate_workchain, + generate_inputs_wannier90, + generate_calc_job_node, + fixture_localhost, + w90_parameters={"fermi_energy": given_fermi_energy}, + ) + + inputs = workchain.prepare_wannier90_pp_inputs() + + assert inputs["wannier90"]["parameters"]["fermi_energy"] == pytest.approx( + given_fermi_energy + ) + + +def test_prepare_wannier90_pp_inputs_rejects_none_fermi_in_parameters( + generate_workchain, + generate_inputs_wannier90, + generate_calc_job_node, + fixture_localhost, +): # pylint: disable=redefined-outer-name + """A `fermi_energy` of None in the parameters is reported against the parameters.""" + workchain = _generate_workchain_without_scf_context( + generate_workchain, + generate_inputs_wannier90, + generate_calc_job_node, + fixture_localhost, + w90_parameters={"fermi_energy": None}, + ) + + with pytest.raises(ValueError, match="wannier90 parameters is None"): + workchain.prepare_wannier90_pp_inputs()