Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Random parser improvements #239

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions electronicparsers/openmx/parser.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have your request about the k-line density scheduled next.

Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
Scf,
BasisSetContainer,
CoreHole,
KMesh,
)
from nomad.parsing.file_parser import TextParser, Quantity
from simulationworkflowschema import (
Expand Down Expand Up @@ -257,6 +258,11 @@ def convert_eigenvalues(string):
r'scf.ElectronicTemperature\s+(\S+)',
repeats=False,
),
Quantity(
'scf.Kgrid',
r'scf.Kgrid\s+(\d+\s+\d+\s+\d+)',
repeats=False,
)
Quantity('scf.dftD', r'scf.dftD\s+([a-z]+)', repeats=False),
Quantity('version.dftD', r'version.dftD\s+([23])', repeats=False),
Quantity(
Expand Down Expand Up @@ -726,18 +732,39 @@ def parse_method(self):
else:
sec_electronic.van_der_waals_method = ''

def parse_eigenvalues(self):
def parse_eigenvalues_and_kmesh(self):
eigenvalues = BandEnergies()

sec_k_mesh = KMesh()
self.archive.run[-1].method[-1].k_mesh = sec_k_mesh

k_mesh_grid = mainfile_parser.get('scf.Kgrid')
if k_mesh_grid is not None:
sec_k_mesh.grid = k_mesh_grid

self.archive.run[-1].calculation[-1].eigenvalues.append(eigenvalues)
values = mainfile_parser.get('eigenvalues')
if values is not None:
kpoints = values.get('kpoints')
if kpoints is not None:
eigenvalues.kpoints = kpoints
eigenvalues.n_kpoints = len(kpoints)
# OpenMX uses only inversion symmetry so every k-point except gamma-point has multiplicity of 2
ondracka marked this conversation as resolved.
Show resolved Hide resolved
kpoints_multiplicities = []
for kpoint in kpoints:
if np.allclose(kpoint, [[0.0, 0.0, 0.0]], rtol=0.0):
kpoints_multiplicities.append(1)
else:
kpoints_multiplicities.append(2)
sec_k_mesh.points = np.array(kpoints).astype(complex)
sec_k_mesh.multiplicities = kpoints_multiplicities
eigenvalues.kpoints_multiplicities = kpoints_multiplicities
else:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe a comment saying # fall back to gamma-point

Copy link
Collaborator Author

@ondracka ondracka Sep 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe
# if no explicit k-points are written we have gamma-point only

eigenvalues.kpoints = [[0, 0, 0]]
eigenvalues.n_kpoints = 1
eigenvalues.kpoints_multiplicities = [1]
sec_k_mesh.points = [[0, 0, 0]]
sec_k_mesh.multiplicities = [1]
values = values.get('eigenvalues')
if values is not None:
if self.spinpolarized:
Expand Down Expand Up @@ -915,4 +942,4 @@ def parse(self, mainfile: str, archive: EntryArchive, logger):
except (IndexError, AttributeError):
pass

self.parse_eigenvalues()
self.parse_eigenvalues_and_kmesh()
6 changes: 5 additions & 1 deletion electronicparsers/quantumespresso/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
BasisSetContainer,
AtomParameters,
KMesh,
Scf,
)
from runschema.system import System, Atoms
from runschema.calculation import (
Expand Down Expand Up @@ -3248,6 +3249,8 @@ def parse_method(self, run):
sec_method.dft = sec_dft
sec_electronic = Electronic()
sec_method.electronic = sec_electronic
sec_scf = Scf()
sec_method.scf = sec_scf
Comment on lines +3252 to +3253
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the existence of the Scf section be contingent on that of scf_threshold_energy_change?
I wouldn't split the logic, staying just with:

if (threshold := run.get_header('scf_threshold_energy_change')) is not None:
   sec_method.scf = Scf(threshold_energy_change = threshold)


starting_magnetization = run.get_header('starting_magnetization')
spin_orbit_mode = run.get_header('spin_orbit_mode')
Expand All @@ -3260,6 +3263,8 @@ def parse_method(self, run):
sec_kmesh.n_points = run.get_header('k_points', {}).get('nk', 1)
sec_kmesh.points = run.get_header('k_points', {}).get('points', None)

sec_scf.threshold_energy_change = run.get_header('scf_threshold_energy_change')

g_vector_sticks = run.get_header('g_vector_sticks', {}).get('Sum', None)
if g_vector_sticks is not None:
names = [
Expand Down Expand Up @@ -3330,7 +3335,6 @@ def parse_method(self, run):

# other method variables
names = [
'scf_threshold_energy_change',
'x_qe_core_charge_realspace',
'x_qe_exact_exchange_fraction',
'x_qe_diagonalization_algorithm',
Expand Down
21 changes: 21 additions & 0 deletions tests/test_openmxparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ def test_HfO2(parser):
assert method.electronic.smearing.width == approx(K_to_J(300))
assert method.dft.xc_functional.correlation[0].name == 'GGA_C_PBE'
assert method.dft.xc_functional.exchange[0].name == 'GGA_X_PBE'
assert (method.k_mesh.grid == [10, 10, 10]).all()
assert np.allclose(method.k_mesh.points[0], np.array([-0.45000, -0.45000, -0.45000]).astype(complex), rtol=0.0)
assert np.allclose(method.k_mesh.points[499], np.array([-0.05000, 0.45000, 0.45000]).astype(complex), rtol=0.0)
assert method.k_mesh.multiplicities[0] == approx(2.0)
assert method.k_mesh.multiplicities[0] == approx(2.0)

system = run.system[0]
assert system.atoms.periodic == [True, True, True]
Expand All @@ -90,6 +95,9 @@ def test_HfO2(parser):
assert len(system.atoms.labels) == 12
assert system.atoms.labels[9] == 'O'

scc = run.calculation
assert scc[-1].eigenvalues[0].kpoints_multiplicities[0] == approx(2.0)


def test_AlN(parser):
"""
Expand Down Expand Up @@ -121,6 +129,9 @@ def test_AlN(parser):
scf = scc[3].scf_iteration
assert len(scf) == 6
scf[5].energy.sum_eigenvalues.value.magnitude == approx(-3.4038520917173614e-17)
assert len(scc[-1].eigenvalues[0].kpoints_multiplicities) == 74
assert scc[-1].eigenvalues[0].kpoints_multiplicities[-1] == approx(1.0)
assert scc[-1].eigenvalues[0].kpoints_multiplicities[0] == approx(2.0)

method = run.method[0]
assert method.electronic.n_spin_channels == 1
Expand All @@ -131,6 +142,11 @@ def test_AlN(parser):
assert method.dft.xc_functional.exchange[0].name == 'GGA_X_PBE'
assert method.scf.n_max_iteration == 100
assert method.scf.threshold_energy_change.magnitude == approx(Ha_to_J(1e-7))
assert (method.k_mesh.grid == [7, 7, 3]).all()
assert np.allclose(method.k_mesh.points[0], np.array([ -0.42857, -0.42857, -0.33333]).astype(complex), rtol=0.0)
assert np.allclose(method.k_mesh.points[73], np.array([0.00000, -0.00000, 0.00000]).astype(complex), rtol=0.0)
assert np.allclose(method.k_mesh.multiplicities[0], np.array([2, 2, 2]).astype(complex), rtol=0.0)
assert method.k_mesh.multiplicities[73] == [1]

workflow = archive.workflow2
assert workflow.method.method == 'steepest_descent'
Expand Down Expand Up @@ -209,6 +225,7 @@ def test_C2N2(parser):
assert np.shape(scc[0].forces.total.value) == (4, 3)
assert scc[0].forces.total.value[0][0].magnitude == approx(HaB_to_N(0.10002))
assert scc[99].forces.total.value[2][2].magnitude == approx(HaB_to_N(-0.00989))
assert scc[-1].eigenvalues[0].kpoints_multiplicities == approx(1.0)

assert len(run.system) == 100

Expand All @@ -218,6 +235,8 @@ def test_C2N2(parser):
assert method.electronic.smearing.width == approx(K_to_J(500))
assert method.dft.xc_functional.exchange[0].name == 'LDA_X'
assert method.dft.xc_functional.correlation[0].name == 'LDA_C_PZ'
assert (method.k_mesh.grid == [1, 1, 1]).all()
assert method.k_mesh.multiplicities[0] == approx(1.0)

workflow = archive.workflow2
assert workflow.method.thermodynamic_ensemble == 'NVT'
Expand Down Expand Up @@ -284,6 +303,7 @@ def test_CrO2(parser):
assert method.dft.xc_functional.correlation[0].name == 'LDA_C_PW'
assert method.scf.n_max_iteration == 40
assert method.scf.threshold_energy_change.magnitude == approx(Ha_to_J(1e-7))
assert (method.k_mesh.grid == [5, 5, 8]).all()

eigenvalues = run.calculation[-1].eigenvalues[0]
assert eigenvalues.n_kpoints == 100
Expand Down Expand Up @@ -316,6 +336,7 @@ def test_graphite(parser):
assert method.electronic.van_der_waals_method == 'G10'
assert method.scf.n_max_iteration == 100
assert method.scf.threshold_energy_change.magnitude == approx(Ha_to_J(1e-8))
assert (method.k_mesh.grid == [12, 12, 4]).all()

calculation_first = run.calculation[0]
stress_tensor_first = calculation_first.stress.total.value
Expand Down
9 changes: 9 additions & 0 deletions tests/test_quantumespressoparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def RyB_to_N(value):
return (value * ureg.rydberg / ureg.bohr).to_base_units().magnitude


def Ry_to_eV(value):
return (value * ureg.rydberg).to_base_units().magnitude


Comment on lines +40 to +43
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kind of confused about the naming: should it rather be "Ry_to_J"?

def test_scf(parser):
archive = EntryArchive()
parser.parse('tests/data/quantumespresso/HO_scf/benchmark2.out', archive, None)
Expand Down Expand Up @@ -73,6 +77,7 @@ def test_scf(parser):
assert sec_method.dft.xc_functional.exchange[0].name == 'GGA_X_PBE'
assert sec_method.electronic.n_electrons[0] == 8
assert sec_method.electronic.n_spin_channels == 1
assert sec_method.scf.threshold_energy_change.magnitude == approx(Ry_to_eV(1e-6))
sec_atoms = sec_method.atom_parameters
assert len(sec_atoms) == 2
assert sec_atoms[1].label == 'H'
Expand Down Expand Up @@ -157,6 +162,7 @@ def test_multirun(parser):
assert sec_runs[2].calculation[0].scf_iteration[
11
].time_physical.magnitude == approx(1189.6)
assert sec_method.scf.threshold_energy_change.magnitude == approx(Ry_to_eV(1e-5))


def test_md(parser):
Expand All @@ -168,6 +174,7 @@ def test_md(parser):
sec_method = sec_run.method[0]
assert len(sec_method.k_mesh.points) == 1
assert sec_method.electronic.n_spin_channels == 1
assert sec_method.scf.threshold_energy_change.magnitude == approx(Ry_to_eV(1e-8))
sec_sccs = sec_run.calculation
assert len(sec_sccs) == 50
assert archive.run[0].system[6].atoms.positions[1][2].magnitude == approx(
Expand Down Expand Up @@ -217,6 +224,7 @@ def test_vcrelax(parser):
assert sec_method.electronic.smearing.kind == 'tetrahedra'
assert sec_method.electronic.smearing.width is None
assert sec_method.electronic.n_spin_channels == 1
assert sec_method.scf.threshold_energy_change.magnitude == approx(Ry_to_eV(1e-8))


def test_noncolmag(parser):
Expand All @@ -243,3 +251,4 @@ def test_noncolmag(parser):
== (0.01 * ureg.rydberg).to_base_units().magnitude
)
assert sec_method.electronic.n_spin_channels is None
assert sec_method.scf.threshold_energy_change.magnitude == approx(Ry_to_eV(1e-8))