Skip to content
Snippets Groups Projects

Compare DOS for integrals, not means

Merged Nathan Daelman requested to merge 1201-unstable-dos-test into develop
Compare and
4 files
+ 167
98
Compare changes
  • Side-by-side
  • Inline
Files
4
+ 92
0
 
#
 
# Copyright The NOMAD Authors.
 
#
 
# This file is part of NOMAD. See https://nomad-lab.eu for further info.
 
#
 
# Licensed under the Apache License, Version 2.0 (the "License");
 
# you may not use this file except in compliance with the License.
 
# You may obtain a copy of the License at
 
#
 
# http://www.apache.org/licenses/LICENSE-2.0
 
#
 
# Unless required by applicable law or agreed to in writing, software
 
# distributed under the License is distributed on an "AS IS" BASIS,
 
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
# See the License for the specific language governing permissions and
 
# limitations under the License.
 
#
 
 
from nomad.datamodel.metainfo.simulation.calculation import Dos
 
from nomad.utils import get_logger
 
import numpy as np
 
from typing import List, Union
 
 
 
# TODO add tester for all functionalities
 
 
def get_fermi_energy(dos_object, efermi):
 
"""
 
Handle extraction of the Fermi level
 
"""
 
logger = get_logger('get_fermi_energy') # set logger
 
 
if efermi is not None:
 
e_fermi = efermi
 
else:
 
try:
 
e_fermi = dos_object.energy_fermi
 
except AttributeError:
 
logger.warn('Missing Fermi energy')
 
return
 
 
return e_fermi
 
 
 
def get_energy_index(dos_object, energy_level):
 
"""
 
Obtain the closest index that contains all electron states up to `energy_level`
 
"""
 
if hasattr(energy_level, 'magnitude'):
 
dos_energies = dos_object.energies.to(energy_level.units).magnitude # ensure that the units are correct
 
energy_level = energy_level.magnitude # convert to float if necessary
 
else:
 
dos_energies = dos_object.energies.magnitude # now it's up to the user to ensure correct units
 
 
for i, energy in enumerate(dos_energies):
 
if energy >= energy_level:
 
return i
 
 
 
def integrate_dos(dos_object: Dos, spin_channels: List[int] = [0, 1],
 
limits: List[str] = ['min', 'fermi'], efermi: Union[float, None] = None):
 
"""
 
Integrate a NOMAD run `dos_object` over the stated `spin_channels`. In unnormalized cases, this simply yields the number of band electrons.
 
- `limits`: 2-object array determining the integration range in energy units. Outside of explicit values, one can also choose `min`, `max` and `fermi`.
 
- `efermi`: explicitly passed Fermi level. To be used when the DOS object does not contain any Fermi level itself.
 
"""
 
logger = get_logger('integrate_dos') # set logger
 
 
# Set integral limits
 
limit_keywords_map = {'min': 0, 'max': -1,
 
'fermi': get_energy_index(dos_object, get_fermi_energy(dos_object, efermi))}
 
if len(limits) != 2:
 
logger.warn('Expected a list of length 2, but got {}'.format(len(limits)))
 
return
 
mapped_limits = []
 
for limit in limits:
 
try:
 
mapped_limits.append(limit_keywords_map[limit])
 
except KeyError:
 
mapped_limits.append(get_energy_index(dos_object, limit))
 
 
# Extract energies and DOS values to perform the integration
 
sel_energies = dos_object.energies.magnitude[mapped_limits[0]:mapped_limits[1]]
 
dos_integrated = 0.
 
for spin_channel in spin_channels:
 
try:
 
dos_values = dos_object.total[spin_channel].value.magnitude[mapped_limits[0]:mapped_limits[1]]
 
dos_integrated += np.trapz(x=sel_energies, y=dos_values)
 
except IndexError:
 
continue
 
 
return dos_integrated
Loading