Commit 640c7e9a authored by Alvin Noe Ladines's avatar Alvin Noe Ladines
Browse files

Added more quantities to single_point workflow

parent 0d34d12b
Pipeline #98250 passed with stages
in 31 minutes and 22 seconds
...@@ -6847,14 +6847,24 @@ class SinglePoint(MSection): ...@@ -6847,14 +6847,24 @@ class SinglePoint(MSection):
''', ''',
a_legacy=LegacyDefinition(name='single_point_calculation_method')) a_legacy=LegacyDefinition(name='single_point_calculation_method'))
scf_steps = Quantity( number_of_scf_steps = Quantity(
type=int, type=int,
shape=[], shape=[],
description=''' description='''
Number of self-consistent steps for the calculation Number of self-consistent steps in the calculation
''', ''',
a_legacy=LegacyDefinition(name='number_of_scf_steps')) a_legacy=LegacyDefinition(name='number_of_scf_steps'))
final_scf_energy_difference = Quantity(
type=np.dtype(np.float64),
shape=[],
unit='joule',
description='''
The difference in the energy between the last two scf steps.
''',
a_search=Search(),
a_legacy=LegacyDefinition(name='final_scf_energy_difference'))
is_converged = Quantity( is_converged = Quantity(
type=bool, type=bool,
shape=[], shape=[],
...@@ -6863,6 +6873,46 @@ class SinglePoint(MSection): ...@@ -6863,6 +6873,46 @@ class SinglePoint(MSection):
''', ''',
a_legacy=LegacyDefinition(name='is_converged')) a_legacy=LegacyDefinition(name='is_converged'))
with_density_of_states = Quantity(
type=bool,
shape=[],
description='''
Indicates if the calculation contains density of states data
''',
a_legacy=LegacyDefinition(name='with_density_of_states'))
with_bandstructure = Quantity(
type=bool,
shape=[],
description='''
Indicates if the calculation contains bandstructure data
''',
a_legacy=LegacyDefinition(name='with_bandstructure'))
with_eigenvalues = Quantity(
type=bool,
shape=[],
description='''
Indicates if the calculation contains eigenvalue data
''',
a_legacy=LegacyDefinition(name='with_eigenvalues'))
with_volumetric_data = Quantity(
type=bool,
shape=[],
description='''
Indicates if the calculation contains volumetric data
''',
a_legacy=LegacyDefinition(name='with_volumetric_data'))
with_excited_states = Quantity(
type=bool,
shape=[],
description='''
Indicates if the calculation contains excited states data
''',
a_legacy=LegacyDefinition(name='with_excited_states'))
class Workflow(MSection): class Workflow(MSection):
''' '''
...@@ -6878,7 +6928,7 @@ class Workflow(MSection): ...@@ -6878,7 +6928,7 @@ class Workflow(MSection):
shape=[], shape=[],
description=''' description='''
The type of calculation workflow. Can be one of geometry_optimization, elastic, The type of calculation workflow. Can be one of geometry_optimization, elastic,
phonon, molecular_dynamics. phonon, molecular_dynamics, single_point.
''', ''',
a_search=Search(), a_search=Search(),
a_legacy=LegacyDefinition(name='workflow_type')) a_legacy=LegacyDefinition(name='workflow_type'))
...@@ -6913,6 +6963,8 @@ class Workflow(MSection): ...@@ -6913,6 +6963,8 @@ class Workflow(MSection):
section_single_point = SubSection( section_single_point = SubSection(
sub_section=SectionProxy('SinglePoint'), sub_section=SectionProxy('SinglePoint'),
# 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, repeats=False,
categories=[FastAccess], categories=[FastAccess],
a_legacy=LegacyDefinition(name='section_single_point')) a_legacy=LegacyDefinition(name='section_single_point'))
......
...@@ -24,6 +24,18 @@ from nomad.datamodel.metainfo.public import Workflow, GeometryOptimization, Phon ...@@ -24,6 +24,18 @@ from nomad.datamodel.metainfo.public import Workflow, GeometryOptimization, Phon
MolecularDynamics, SinglePoint MolecularDynamics, SinglePoint
def resolve_energy_difference(energies):
delta_energy = None
energies = [e for e in energies if e is not None]
for n in range(-1, -len(energies), -1):
delta_energy = abs(energies[n] - energies[n - 1])
if delta_energy != 0.0:
break
return delta_energy
class SinglePointNormalizer(Normalizer): class SinglePointNormalizer(Normalizer):
def __init__(self, entry_archive): def __init__(self, entry_archive):
super().__init__(entry_archive) super().__init__(entry_archive)
...@@ -40,9 +52,40 @@ class SinglePointNormalizer(Normalizer): ...@@ -40,9 +52,40 @@ class SinglePointNormalizer(Normalizer):
except Exception: except Exception:
pass pass
if not self.section.scf_steps: scc = self.section_run.section_single_configuration_calculation
scc = self.section_run.section_single_configuration_calculation if not scc:
self.section.scf_steps = len(scc[-1].section_scf_iteration) return
if not self.section.number_of_scf_steps:
self.section.number_of_scf_steps = len(scc[-1].section_scf_iteration)
energies = [scf.energy_total_scf_iteration for scf in scc[-1].section_scf_iteration]
delta_energy = resolve_energy_difference(energies)
if not self.section.final_scf_energy_difference and delta_energy is not None:
self.section.final_scf_energy_difference = delta_energy
if not self.section.is_converged and delta_energy is not None:
try:
threshold = self.section.section_method[-1].scf_threshold_energy_change
if threshold <= delta_energy:
self.section.is_converged = True
except Exception:
pass
if not self.section.with_density_of_states:
self.section.with_density_of_states = len(scc[-1].section_dos) > 0
if not self.section.with_bandstructure:
self.section.with_bandstructure = len(scc[-1].section_k_band) > 0
if not self.section.with_eigenvalues:
self.section.with_eigenvalues = len(scc[-1].section_eigenvalues) > 0
if not self.section.with_volumetric_data:
self.section.with_volumetric_data = len(scc[-1].section_volumetric_data) > 0
if not self.section.with_excited_states:
self.section.with_excited_states = len(scc[-1].section_excited_states) > 0
class GeometryOptimizationNormalizer(Normalizer): class GeometryOptimizationNormalizer(Normalizer):
...@@ -117,17 +160,8 @@ class GeometryOptimizationNormalizer(Normalizer): ...@@ -117,17 +160,8 @@ class GeometryOptimizationNormalizer(Normalizer):
if scc.energy_total_T0: if scc.energy_total_T0:
energies.append(scc.energy_total_T0) energies.append(scc.energy_total_T0)
delta_energy = None delta_energy = resolve_energy_difference(energies)
if len(energies) > 1: if delta_energy is not None:
delta_energy = abs(energies[-1] - energies[-2])
if delta_energy == 0.0:
try:
delta_energy = abs(energies[-1] - energies[-3])
except Exception:
pass
if delta_energy:
self.section.final_energy_difference = delta_energy self.section.final_energy_difference = delta_energy
if not self.section.final_force_maximum: if not self.section.final_force_maximum:
...@@ -292,16 +326,20 @@ class WorkflowNormalizer(Normalizer): ...@@ -292,16 +326,20 @@ class WorkflowNormalizer(Normalizer):
self._phonon_programs = ['phonopy'] self._phonon_programs = ['phonopy']
def _resolve_workflow_type_vasp(self): def _resolve_workflow_type_vasp(self):
try: sec_method = self.section_run.section_method
ibrion = self.section_run.section_method[0].x_vasp_incarOut_IBRION if not sec_method:
except Exception: return
ibrion = 1
incar = self.section_run.section_method[0].x_vasp_incar_out
nsw = incar.get('NSW')
ibrion = -1 if nsw == 0 else incar.get('IBRION', 0)
if ibrion == 0: if ibrion == -1:
workflow_type = "molecular_dynamics" return 'single_point'
elif ibrion == 0:
return 'molecular_dynamics'
else: else:
workflow_type = "geometry_optimization" return 'geometry_optimization'
return workflow_type
def _resolve_workflow_type(self): def _resolve_workflow_type(self):
# first get it from section_sampling_method # first get it from section_sampling_method
...@@ -331,6 +369,11 @@ class WorkflowNormalizer(Normalizer): ...@@ -331,6 +369,11 @@ class WorkflowNormalizer(Normalizer):
elif program_name == 'phonopy': elif program_name == 'phonopy':
workflow_type = 'phonon' workflow_type = 'phonon'
# resolve if from scc
if not workflow_type:
if len(self.section_run.section_single_configuration_calculation) == 1:
workflow_type = 'single_point'
return workflow_type return workflow_type
def normalize(self, logger=None) -> None: def normalize(self, logger=None) -> None:
......
This diff is collapsed.
...@@ -37,6 +37,24 @@ def test_no_workflow(workflow_archive): ...@@ -37,6 +37,24 @@ def test_no_workflow(workflow_archive):
assert vasp_archive.section_workflow is None assert vasp_archive.section_workflow is None
def test_single_point_workflow(workflow_archive):
vasp_archive = workflow_archive(
'parsers/vasp', 'tests/data/normalizers/workflow/vasp/vasprun.xml.static')
sec_workflow = vasp_archive.section_workflow
assert sec_workflow.workflow_type == 'single_point'
assert sec_workflow.calculations_ref is not None
assert sec_workflow.calculation_result_ref.m_def.name == 'SingleConfigurationCalculation'
assert sec_workflow.section_single_point.single_point_calculation_method == 'DFT'
assert sec_workflow.section_single_point.number_of_scf_steps == 9
assert sec_workflow.section_single_point.final_scf_energy_difference > 0
assert sec_workflow.section_single_point.with_density_of_states
assert not sec_workflow.section_single_point.with_bandstructure
assert sec_workflow.section_single_point.with_eigenvalues
assert not sec_workflow.section_single_point.with_volumetric_data
assert not sec_workflow.section_single_point.with_excited_states
def test_geometry_optimization_workflow(workflow_archive): def test_geometry_optimization_workflow(workflow_archive):
vasp_archive = workflow_archive( vasp_archive = workflow_archive(
'parsers/vasp', 'tests/data/normalizers/workflow/vasp/vasprun.xml') 'parsers/vasp', 'tests/data/normalizers/workflow/vasp/vasprun.xml')
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment