madman.analysis.ehden
Electron / hole density.
1r"""Electron / hole density.""" 2 3from __future__ import annotations 4from collections.abc import Sequence 5from numbers import Real 6from sys import modules 7from typing import Any, Self, Type 8 9import numpy as np 10from matplotlib import pyplot as plt 11 12from madman.analysis.edos import ( 13 ElectronDensityOfStates, 14 ResolvedElectronDensityOfStates, 15 BandResolvedElectronDensityOfStates, 16 CellResolvedElectronDensityOfStates, 17) 18from madman.analysis.ejdos import ( 19 ElectronJointDensityOfStates, 20 ResolvedElectronJointDensityOfStates, 21 BandResolvedElectronJointDensityOfStates, 22 CellResolvedElectronJointDensityOfStates, 23) 24from madman.analysis.spectrum import ( 25 EnergySpectrumMeta, 26 EnergySpectrum, 27 ResolvedEnergySpectrumMeta, 28 ResolvedEnergySpectrum, 29) 30from madman.constant import Constant 31from madman.utilities import correlate1d 32 33 34def ret_fd_occups( 35 energies: Sequence[Real, ...], 36 *, 37 fermi_lv: Real = 0.0, 38 temperature: Real = 300.0, 39) -> np.ndarray[float]: 40 r"""Return Fermi-Dirac occupations. 41 42 Args: 43 energies: Electron energies [$\mathrm{eV}$]. 44 fermi_lv: Fermi level [$\mathrm{eV}$]. 45 temperature: Temperature [$\mathrm{K}$]. 46 47 Returns: 48 Fermi-Dirac occupations. 49 50 Raises: 51 ValueError: If temperature is non-positive. 52 """ 53 energies = np.asarray(energies, dtype=float).flatten() 54 if temperature <= 0.0: 55 raise ValueError("Non-positive temperature!") 56 red_energies = (energies - fermi_lv) / (Constant.k * temperature) 57 occups = np.where( 58 red_energies == 0.0, 59 0.5, 60 1.0 / (1.0 + np.exp(red_energies)), 61 ) 62 return occups 63 64 65class SpectralCarrierDensityMeta(EnergySpectrumMeta): 66 r"""Metaclass of SpectralCarrierDensity.""" 67 68 @property 69 def std_axes(cls) -> plt.Axes: 70 r"""Standard axes to plot spectral carrier density. 71 72 Returns: 73 Plot axes. 74 """ 75 _, ax = plt.subplots(tight_layout=True) 76 ax.set_xlabel(r"Electron energy / $\mathrm{eV}$") 77 78 if "Carrier" in cls.__name__: 79 ax.set_ylabel(r"Spectral carrier density / $\mathrm{eV^{-1}}$") 80 if "Electron" in cls.__name__: 81 ax.set_ylabel(r"Spectral electron density / $\mathrm{eV^{-1}}$") 82 if "Hole" in cls.__name__: 83 ax.set_ylabel(r"Spectral hole density / $\mathrm{eV^{-1}}$") 84 85 return ax 86 87 88class SpectralCarrierDensity( 89 EnergySpectrum, metaclass=SpectralCarrierDensityMeta 90): 91 r"""Spectral carrier density. 92 93 Note: 94 `energies`: Electron energies [$\mathrm{eV}$]. 95 `values`: Spectral carrier density values [$\mathrm{eV^{-1}}$]. 96 """ 97 98 def __init__( 99 self, 100 edos: ElectronDensityOfStates, 101 *, 102 fermi_lv: Real = 0.0, 103 temperature: Real = 300.0, 104 ) -> None: 105 r"""Initialize SpectralCarrierDensity object. 106 107 Args: 108 edos: Electron density of states. 109 fermi_lv: Fermi level [$\mathrm{eV}$]. 110 temperature: Temperature [$\mathrm{K}$]. 111 112 Raises: 113 TypeError: If `edos` is not a ElectronDensityOfStates object. 114 ValueError: If temperature is non-positive. 115 """ 116 if not isinstance(edos, ElectronDensityOfStates): 117 raise TypeError("Not a ElectronDensityOfStates object!") 118 if temperature <= 0.0: 119 raise ValueError("Non-positive temperature!") 120 121 self._edos = edos 122 self._fermi_lv = float(fermi_lv) 123 self._temperature = float(temperature) 124 self._energies = edos.energies 125 126 if isinstance(self, SpectralElectronDensity): 127 occups = ret_fd_occups( 128 self.energies, 129 fermi_lv=self.fermi_lv, 130 temperature=self.temperature, 131 ) 132 elif isinstance(self, SpectralHoleDensity): 133 occups = 1.0 - ret_fd_occups( 134 self.energies, 135 fermi_lv=self.fermi_lv, 136 temperature=self.temperature, 137 ) 138 else: 139 occups = 1.0 140 141 self._values = occups * edos.values 142 self._integr = np.trapz(self._values, x=self._energies) 143 self._sp_eden = None 144 self._sp_hden = None 145 146 def __add__(self, other: Self) -> Self: 147 r"""Add spectral carrier density. 148 149 Args: 150 other: Spectral carrier density to add. 151 152 Returns: 153 Sum of `self` and `other`. 154 155 Raises: 156 TypeError: If `self` and `other` have incompatible types. 157 ValueError: If `self` and `other`have incompatible Fermi levels. 158 ValueError: If `self` and `other`have incompatible temperatures. 159 """ 160 if type(self) != type(other): 161 raise TypeError("Incompatible types!") 162 if self.fermi_lv != other.fermi_lv: 163 raise ValueError("Incompatible Fermi levels!") 164 if self.temperature != other.temperature: 165 raise ValueError("Incompatible temperatures!") 166 edos = self.edos + other.edos 167 return type(self)( 168 edos, fermi_lv=self.fermi_lv, temperature=self.temperature 169 ) 170 171 @property 172 def edos(self) -> ElectronDensityOfStates: 173 r"""Electron density of states.""" 174 return self._edos 175 176 @property 177 def fermi_lv(self) -> float: 178 r"""Fermi level [$\mathrm{eV}$].""" 179 return self._fermi_lv 180 181 @property 182 def temperature(self) -> float: 183 r"""Temperature [$\mathrm{K}$].""" 184 return self._temperature 185 186 @property 187 def sp_eden(self) -> SpectralElectronDensity: 188 r"""Spectral electron density.""" 189 if self._sp_eden is None: 190 if isinstance(self, SpectralElectronDensity): 191 self._sp_eden = self 192 else: 193 self._sp_eden = SpectralElectronDensity( 194 self.edos, 195 fermi_lv=self.fermi_lv, 196 temperature=self.temperature, 197 ) 198 return self._sp_eden 199 200 @property 201 def sp_hden(self) -> SpectralHoleDensity: 202 r"""Spectral hole density.""" 203 if self._sp_hden is None: 204 if isinstance(self, SpectralHoleDensity): 205 self._sp_hden = self 206 else: 207 self._sp_hden = SpectralHoleDensity( 208 self.edos, 209 fermi_lv=self.fermi_lv, 210 temperature=self.temperature, 211 ) 212 return self._sp_hden 213 214 def ret_zero(self) -> Self: 215 r"""Return zero spectral carrier density.""" 216 return type(self).zero( 217 self.energies, fermi_lv=self.fermi_lv, temperature=self.temperature 218 ) 219 220 def ret_smeared(self, *, sigma: Real) -> Self: 221 r"""Return smeared spectral carrier density. 222 223 Args: 224 sigma: Standard deviation for Gaussian kernel. 225 226 Returns: 227 Smeared spectral carrier density. 228 """ 229 edos = self.edos.ret_smeared(sigma=sigma) 230 return type(self)( 231 edos, fermi_lv=self.fermi_lv, temperature=self.temperature 232 ) 233 234 def ret_band_rsv( 235 self, *, threshold: Real = 0.0 236 ) -> BandResolvedSpectralCarrierDensity: 237 r"""Return band resolved spectral carrier density. 238 239 Args: 240 threshold: Threshold below which electron density of states values 241 are rounded to zero [$\mathrm{eV^{-1}}$]. 242 243 Returns: 244 Band resolved spectral carrier density. 245 """ 246 rsv_edos = self.edos.ret_band_rsv(threshold=threshold) 247 return type(self).band_rsv( 248 rsv_edos, fermi_lv=self.fermi_lv, temperature=self.temperature 249 ) 250 251 def calc_ejdos(self) -> ElectronJointDensityOfStates: 252 r"""Calculate electron joint density of states. 253 254 Returns: 255 Electron joint density of states. 256 """ 257 ejdos_energies, ejdos_values = correlate1d( 258 self.energies, self.sp_eden.values, self.sp_hden.values 259 ) 260 return ElectronJointDensityOfStates(ejdos_energies, ejdos_values) 261 262 def plot_fermi_lv( 263 self, 264 *, 265 ax: plt.Axes, 266 color: str | None = None, 267 label: str | None = None, 268 ) -> plt.Figure: 269 r"""Plot Fermi level. 270 271 Args: 272 ax: Plot axes; if None, new figure and axes are created. 273 color: Line color. 274 label: Line label. 275 276 Returns: 277 Plot figure. 278 """ 279 ax.axvline(self.fermi_lv, linestyle="--", color=color, label=label) 280 return ax.get_figure() 281 282 @classmethod 283 def zero( 284 cls, 285 energies: Sequence[Real, ...], 286 *, 287 d_energy: Real | None = None, 288 fermi_lv: Real = 0.0, 289 temperature: Real = 300.0, 290 ) -> np.ndarray[float]: 291 r"""Zero spectral carrier density. 292 293 Args: 294 energies: Electron energies [$\mathrm{eV}$]. 295 d_energy: Target electron energy increment [$\mathrm{eV}$]. 296 fermi_lv: Fermi level [$\mathrm{eV}$]. 297 temperature: Temperature [$\mathrm{K}$]. 298 299 Returns: 300 Zero spectral carrier density. 301 """ 302 edos = ElectronDensityOfStates.zero(energies, d_energy=d_energy) 303 return cls(edos, fermi_lv=fermi_lv, temperature=temperature) 304 305 @classmethod 306 def piecewise_constant( 307 cls, 308 energy_a: Real, 309 energy_b: Real, 310 d_energy: Real, 311 *, 312 amplitudes: Sequence[Real, ...], 313 low_bounds: Sequence[Real, ...], 314 upp_bounds: Sequence[Real, ...], 315 fermi_lv: Real = 0.0, 316 temperature: Real = 300.0, 317 ) -> Self: 318 r"""Piecewise constant spectral carrier density. 319 320 Args: 321 energy_a: Electron energy minimum [$\mathrm{eV}$]. 322 energy_b: Electron energy maximum [$\mathrm{eV}$]. 323 d_energy: Target electron energy increment [$\mathrm{eV}$]. 324 amplitudes: Electron density of states piece amplitudes 325 [$\mathrm{eV^{-1}}$]. 326 low_bounds: Electron density of states piece lower bounds 327 [$\mathrm{eV}$]. 328 upp_bounds: Electron density of states piece upper bounds 329 [$\mathrm{eV}$]. 330 fermi_lv: Fermi level [$\mathrm{eV}$]. 331 temperature: Temperature [$\mathrm{K}$]. 332 333 Returns: 334 Piecewise constant spectral carrier density. 335 """ 336 edos = ElectronDensityOfStates.piecewise_constant( 337 energy_a, 338 energy_b, 339 d_energy, 340 amplitudes=amplitudes, 341 low_bounds=low_bounds, 342 upp_bounds=upp_bounds, 343 ) 344 return cls(edos, fermi_lv=fermi_lv, temperature=temperature) 345 346 347class SpectralElectronDensity(SpectralCarrierDensity): 348 r"""Spectral electron density. 349 350 Note: 351 `energies`: Electron energies [$\mathrm{eV}$]. 352 `values`: Spectral electron density values [$\mathrm{eV^{-1}}$]. 353 """ 354 355 356class SpectralHoleDensity(SpectralCarrierDensity): 357 r"""Spectral hole density. 358 359 Note: 360 `energies`: Electron energies [$\mathrm{eV}$]. 361 `values`: Spectral hole density values [$\mathrm{eV^{-1}}$]. 362 """ 363 364 365class ResolvedSpectralCarrierDensityMeta(ResolvedEnergySpectrumMeta): 366 r"""Metaclass of ResolvedSpectralCarrierDensity.""" 367 368 @property 369 def rsv_edos(cls) -> Type: 370 r"""Associated resolved electron density of states class.""" 371 module = modules[cls.__module__] 372 name = ( 373 cls.__name__[: cls.__name__.index("Resolved") + len("Resolved")] 374 + "ElectronDensityOfStates" 375 ) 376 return getattr(module, name) 377 378 @property 379 def rsv_sp_eden(cls) -> Type: 380 r"""Associated resolved spectral electron density class.""" 381 module = modules[cls.__module__] 382 name = cls.__name__.replace("Carrier", "Electron").replace( 383 "Hole", "Electron" 384 ) 385 return getattr(module, name) 386 387 @property 388 def rsv_sp_hden(cls) -> Type: 389 r"""Associated resolved spectral hole density class.""" 390 module = modules[cls.__module__] 391 name = cls.__name__.replace("Carrier", "Hole").replace( 392 "Electron", "Hole" 393 ) 394 return getattr(module, name) 395 396 @property 397 def rsv_ejdos(cls) -> Type: 398 r"""Associated resolved electron joint density of states class.""" 399 module = modules[cls.__module__] 400 name = ( 401 cls.__name__[: cls.__name__.index("Resolved") + len("Resolved")] 402 + "ElectronJointDensityOfStates" 403 ) 404 return getattr(module, name) 405 406 407class ResolvedSpectralCarrierDensity( 408 ResolvedEnergySpectrum, metaclass=ResolvedSpectralCarrierDensityMeta 409): 410 r"""Resolved spectral carrier density. 411 412 Note: 413 `energies`: Electron energies [$\mathrm{eV}$]. 414 `rsv_values`: Resolved spectral carrier density values 415 [$\mathrm{eV^{-1}}$]. 416 """ 417 418 def __init__( 419 self, 420 rsv_edos: ResolvedElectronDensityOfStates, 421 *, 422 fermi_lv: Real = 0.0, 423 temperature: Real = 300.0, 424 ) -> None: 425 r"""Initialize ResolvedSpectralCarrierDensity object. 426 427 Args: 428 rsv_edos: Resolved electron density of states. 429 fermi_lv: Fermi level [$\mathrm{eV}$]. 430 temperature: Temperature [$\mathrm{K}$]. 431 432 Raises: 433 TypeError: If resolved electron density of states is incompatible. 434 ValueError: If temperature is non-positive. 435 """ 436 if type(rsv_edos) != type(self).rsv_edos: 437 raise TypeError("Incompatible resolved electron density of states!") 438 if temperature <= 0.0: 439 raise ValueError("Non-positive temperature!") 440 441 self._rsv_edos = rsv_edos 442 self._fermi_lv = float(fermi_lv) 443 self._temperature = float(temperature) 444 self._energies = self.rsv_edos.energies 445 446 if isinstance(self, ResolvedSpectralElectronDensity): 447 occups = ret_fd_occups( 448 self.energies, 449 fermi_lv=self.fermi_lv, 450 temperature=self.temperature, 451 ) 452 elif isinstance(self, ResolvedSpectralHoleDensity): 453 occups = 1.0 - ret_fd_occups( 454 self.energies, 455 fermi_lv=self.fermi_lv, 456 temperature=self.temperature, 457 ) 458 else: 459 occups = 1.0 460 461 self._rsv_values = { 462 feat: occups * edos_values 463 for feat, edos_values in self.rsv_edos.rsv_values.items() 464 } 465 self._rsv_integr = { 466 feat: np.trapz(values, x=self.energies) 467 for feat, values in self._rsv_values.items() 468 } 469 self._total = type(self).total( 470 self.rsv_edos.total, 471 fermi_lv=self.fermi_lv, 472 temperature=self.temperature, 473 ) 474 self._rsv_sp_eden = None 475 self._rsv_sp_hden = None 476 477 @property 478 def rsv_edos(self) -> ResolvedElectronDensityOfStates: 479 r"""Resolved electron density of states.""" 480 return self._rsv_edos 481 482 @property 483 def fermi_lv(self) -> float: 484 r"""Fermi level [$\mathrm{eV}$].""" 485 return self._fermi_lv 486 487 @property 488 def temperature(self) -> float: 489 r"""Temperature [$\mathrm{K}$].""" 490 return self._temperature 491 492 @property 493 def rsv_sp_eden(self) -> ResolvedSpectralElectronDensity: 494 r"""Resolved spectral electron density.""" 495 if self._rsv_sp_eden is None: 496 if isinstance(self, ResolvedSpectralElectronDensity): 497 self._rsv_sp_eden = self 498 else: 499 self._rsv_sp_eden = type(self).rsv_sp_eden( 500 self.rsv_edos, 501 fermi_lv=self.fermi_lv, 502 temperature=self.temperature, 503 ) 504 return self._rsv_sp_eden 505 506 @property 507 def rsv_sp_hden(self) -> ResolvedSpectralHoleDensity: 508 r"""Resolved spectral hole density.""" 509 if self._rsv_sp_hden is None: 510 if isinstance(self, ResolvedSpectralHoleDensity): 511 self._rsv_sp_hden = self 512 else: 513 self._rsv_sp_hden = type(self).rsv_sp_hden( 514 self.rsv_edos, 515 fermi_lv=self.fermi_lv, 516 temperature=self.temperature, 517 ) 518 return self._rsv_sp_hden 519 520 def ret_zero(self) -> Self: 521 r"""Return zero resolved spectral carrier density.""" 522 return type(self).zero( 523 self.rsv_edos.energies, 524 self.rsv_edos.rsv_values.keys(), 525 fermi_lv=self.fermi_lv, 526 temperature=self.temperature, 527 ) 528 529 def ret_smeared(self, *, sigma: Real) -> Self: 530 r"""Return smeared resolved spectral carrier density. 531 532 Args: 533 sigma: Standard deviation for Gaussian kernel. 534 535 Returns: 536 Smeared resolved spectral carrier density. 537 """ 538 rsv_edos = self.rsv_edos.ret_smeared(sigma=sigma) 539 return type(self)( 540 rsv_edos, fermi_lv=self.fermi_lv, temperature=self.temperature 541 ) 542 543 def calc_rsv_ejdos(self) -> ResolvedElectronJointDensityOfStates: 544 r"""Calculate resolved electron joint density of states.""" 545 rsv_ejdos_values = {} 546 for feat_e, values_e in self.rsv_sp_eden.rsv_values.items(): 547 for feat_h, values_h in self.rsv_sp_hden.rsv_values.items(): 548 if isinstance(self, CellResolvedSpectralCarrierDensity): 549 pair = feat_e + feat_h 550 if pair not in {"ii", "vi", "ic", "vc"}: 551 continue 552 else: 553 pair = (feat_e, feat_h) 554 555 ejdos_energies, ejdos_values = correlate1d( 556 self.energies, values_e, values_h 557 ) 558 rsv_ejdos_values[pair] = ejdos_values 559 560 return type(self).rsv_ejdos(ejdos_energies, rsv_ejdos_values) 561 562 def plot_fermi_lv( 563 self, 564 *, 565 ax: plt.Axes, 566 color: str | None = None, 567 label: str | None = None, 568 ) -> plt.Figure: 569 r"""Plot Fermi level. 570 571 Args: 572 ax: Plot axes; if None, new figure and axes are created. 573 color: Line color. 574 label: Line label. 575 576 Returns: 577 Plot figure. 578 """ 579 ax.axvline(self.fermi_lv, linestyle="--", color=color, label=label) 580 return ax.get_figure() 581 582 @classmethod 583 def zero( 584 cls, 585 energies: Sequence[Real, ...], 586 features: Sequence[Any, ...], 587 *, 588 d_energy: Real | None = None, 589 fermi_lv: Real = 0.0, 590 temperature: Real = 300.0, 591 ) -> Self: 592 r"""Zero resolved spectral carrier density. 593 594 Args: 595 energies: Resolved spectral carrier density energies 596 [$\mathrm{eV}$]. 597 features: Resolved spectral carrier density features. 598 d_energy: Target electron energy increment [$\mathrm{eV}$]. 599 fermi_lv: Fermi level [$\mathrm{eV}$]. 600 temperature: Temperature [$\mathrm{K}$]. 601 602 Returns: 603 Zero resolved spectral carrier density. 604 """ 605 rsv_edos = cls.rsv_edos.zero(energies, features, d_energy=d_energy) 606 return cls(rsv_edos, fermi_lv=fermi_lv, temperature=temperature) 607 608 609class ResolvedSpectralElectronDensity(ResolvedSpectralCarrierDensity): 610 r"""Resolved spectral electron density. 611 612 Note: 613 `energies`: Electron energies [$\mathrm{eV}$]. 614 `rsv_values`: Resolved spectral electron density values 615 [$\mathrm{eV^{-1}}$]. 616 """ 617 618 619class ResolvedSpectralHoleDensity(ResolvedSpectralCarrierDensity): 620 r"""Resolved spectral hole density. 621 622 Note: 623 `energies`: Electron energies [$\mathrm{eV}$]. 624 `rsv_values`: Resolved spectral hole density values 625 [$\mathrm{eV^{-1}}$]. 626 """ 627 628 629class BandResolvedSpectralCarrierDensity(ResolvedSpectralCarrierDensity): 630 r"""Band resolved spectral carrier density. 631 632 Note: 633 `energies`: Electron energies [$\mathrm{eV}$]. 634 `rsv_values`: Band resolved spectral carrier density values 635 [$\mathrm{eV^{-1}}$]. 636 637 Note: 638 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 639 """ 640 641 def ret_rsv_fill_type(self, *, tolerance: Real = 0.0) -> dict[int, str]: 642 r"""Return band resolved fill type. 643 644 Args: 645 tolerance: Minimum distance between Fermi level and band edges 646 for band fill type to be determined [$\mathrm{eV}$]. 647 648 Returns: 649 Band resolved fill type. 650 """ 651 rsv_fill_type = {} 652 for i, edos_values in self.rsv_edos.rsv_values.items(): 653 band_energies = self.energies[edos_values > 0.0] 654 if ( 655 np.amin(band_energies) < self.fermi_lv - tolerance 656 and np.amax(band_energies) > self.fermi_lv + tolerance 657 ): 658 rsv_fill_type[i] = "metallic" 659 elif np.all(band_energies < self.fermi_lv + tolerance): 660 rsv_fill_type[i] = "filled" 661 elif np.all(band_energies > self.fermi_lv - tolerance): 662 rsv_fill_type[i] = "empty" 663 else: 664 rsv_fill_type[i] = "undetermined" 665 return rsv_fill_type 666 667 def ret_cell_rsv( 668 self, cell_type, *, tolerance: Real = 0.0 669 ) -> list[CellResolvedSpectralCarrierDensity, ...]: 670 r"""Return cell resolved spectral carrier densities. 671 672 Args: 673 cell_type: Cell type ('sq' ord 'ib'). 674 tolerance: Minimum distance between Fermi level and band edges 675 for band fill type to be determined [$\mathrm{eV}$]. 676 677 Returns: 678 List of cell resolved spectral carrier densities. 679 680 Raises: 681 ValueError: If cell type is not 'sq' or 'ib'. 682 """ 683 if cell_type not in {"sq", "ib"}: 684 raise ValueError("Cell type must be 'sq' or 'ib'!") 685 686 cell_rsv_seq = [] 687 rsv_fill_type = self.ret_rsv_fill_type(tolerance=tolerance) 688 689 if cell_type == "sq": 690 691 if set(rsv_fill_type.values()) == {"filled", "empty"}: 692 cell_rsv_edos_values = {"v": 0, "c": 0} 693 rsv_edos_values = self.rsv_edos.rsv_values 694 for band_i, fill_type in rsv_fill_type.items(): 695 edos_values = rsv_edos_values[band_i] 696 if fill_type == "filled": 697 cell_rsv_edos_values["v"] += edos_values 698 if fill_type == "empty": 699 cell_rsv_edos_values["c"] += edos_values 700 cell_rsv_edos = CellResolvedElectronDensityOfStates( 701 self.energies, cell_rsv_edos_values 702 ) 703 cell_rsv = type(self).total.cell_rsv( 704 cell_rsv_edos, 705 fermi_lv=self.fermi_lv, 706 temperature=self.temperature, 707 ) 708 cell_rsv_seq.append(cell_rsv) 709 710 elif cell_type == "ib": 711 712 if set(rsv_fill_type.values()) == {"filled", "metallic", "empty"}: 713 cell_rsv_edos_values = {"v": 0, "i": 0, "c": 0} 714 rsv_edos_values = self.rsv_edos.rsv_values 715 for band_i, fill_type in rsv_fill_type.items(): 716 edos_values = rsv_edos_values[band_i] 717 if fill_type == "filled": 718 cell_rsv_edos_values["v"] += edos_values 719 if fill_type == "metallic": 720 cell_rsv_edos_values["i"] += edos_values 721 if fill_type == "empty": 722 cell_rsv_edos_values["c"] += edos_values 723 cell_rsv_edos = CellResolvedElectronDensityOfStates( 724 self.energies, cell_rsv_edos_values 725 ) 726 cell_rsv = type(self).total.cell_rsv( 727 cell_rsv_edos, 728 fermi_lv=self.fermi_lv, 729 temperature=self.temperature, 730 ) 731 cell_rsv_seq.append(cell_rsv) 732 733 if set(rsv_fill_type.values()) == {"filled", "empty"}: 734 rsv_edos_values = self.rsv_edos.rsv_values 735 736 rsv_edos_values_filled = [ 737 rsv_edos_values[band_i] 738 for band_i, fill_type in rsv_fill_type.items() 739 if fill_type == "filled" 740 ] 741 rsv_edos_values_filled.sort(key=lambda x: x.min()) 742 743 rsv_edos_values_empty = [ 744 rsv_edos_values[band_i] 745 for band_i, fill_type in rsv_fill_type.items() 746 if fill_type == "empty" 747 ] 748 rsv_edos_values_empty.sort(key=lambda x: x.min()) 749 750 if len(rsv_edos_values_empty) > 1: 751 cell_rsv_edos_values = { 752 "v": sum(rsv_edos_values_filled), 753 "i": rsv_edos_values_empty[0], 754 "c": sum(rsv_edos_values_empty[1:]), 755 } 756 cell_rsv_edos = CellResolvedElectronDensityOfStates( 757 self.energies, cell_rsv_edos_values 758 ) 759 cell_rsv = type(self).total.cell_rsv( 760 cell_rsv_edos, 761 fermi_lv=self.fermi_lv, 762 temperature=self.temperature, 763 ) 764 cell_rsv_seq.append(cell_rsv) 765 766 if len(rsv_edos_values_filled) > 1: 767 cell_rsv_edos_values = { 768 "v": sum(rsv_edos_values_filled[:-1]), 769 "i": rsv_edos_values_filled[-1], 770 "c": sum(rsv_edos_values_empty), 771 } 772 cell_rsv_edos = CellResolvedElectronDensityOfStates( 773 self.energies, cell_rsv_edos_values 774 ) 775 cell_rsv = type(self).total.cell_rsv( 776 cell_rsv_edos, 777 fermi_lv=self.fermi_lv, 778 temperature=self.temperature, 779 ) 780 cell_rsv_seq.append(cell_rsv) 781 782 return cell_rsv_seq 783 784 785class BandResolvedSpectralElectronDensity( 786 ResolvedSpectralElectronDensity, BandResolvedSpectralCarrierDensity 787): 788 r"""Band resolved spectral electron density. 789 790 Note: 791 `energies`: Electron energies [$\mathrm{eV}$]. 792 `rsv_values`: Band resolved spectral electron density values 793 [$\mathrm{eV^{-1}}$]. 794 795 Note: 796 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 797 """ 798 799 800class BandResolvedSpectralHoleDensity( 801 ResolvedSpectralHoleDensity, BandResolvedSpectralCarrierDensity 802): 803 r"""Band resolved spectral hole density. 804 805 Note: 806 `energies`: Electron energies [$\mathrm{eV}$]. 807 `rsv_values`: Band resolved spectral hole density values 808 [$\mathrm{eV^{-1}}$]. 809 810 Note: 811 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 812 """ 813 814 815class CellResolvedSpectralCarrierDensity(ResolvedSpectralCarrierDensity): 816 r"""Cell resolved spectral carrier density. 817 818 Note: 819 `energies`: Electron energies [$\mathrm{eV}$]. 820 `rsv_values`: Cell resolved spectral carrier density values 821 [$\mathrm{eV^{-1}}$]. 822 823 Note: 824 See `madman.analysis.spectrum.CellResolvedEnergySpectrum` for details. 825 """ 826 def ret_rsv_fill_type(self, *, tolerance: Real = 0.0) -> dict[int, str]: 827 r"""Return cell resolved fill type. 828 829 Args: 830 tolerance: Minimum distance between Fermi level and band edges 831 for band fill type to be determined [$\mathrm{eV}$]. 832 833 Returns: 834 Cell resolved fill type. 835 """ 836 rsv_fill_type = {} 837 for i, edos_values in self.rsv_edos.rsv_values.items(): 838 band_energies = self.energies[edos_values > 0.0] 839 if ( 840 np.amin(band_energies) < self.fermi_lv - tolerance 841 and np.amax(band_energies) > self.fermi_lv + tolerance 842 ): 843 rsv_fill_type[i] = "metallic" 844 elif np.all(band_energies < self.fermi_lv + tolerance): 845 rsv_fill_type[i] = "filled" 846 elif np.all(band_energies > self.fermi_lv - tolerance): 847 rsv_fill_type[i] = "empty" 848 else: 849 rsv_fill_type[i] = "undetermined" 850 return rsv_fill_type 851 852 853class CellResolvedSpectralElectronDensity( 854 ResolvedSpectralElectronDensity, CellResolvedSpectralCarrierDensity 855): 856 r"""Cell resolved spectral electron density. 857 858 Note: 859 `energies`: Electron energies [$\mathrm{eV}$]. 860 `rsv_values`: Cell resolved spectral electron density values 861 [$\mathrm{eV^{-1}}$]. 862 863 Note: 864 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 865 """ 866 867 868class CellResolvedSpectralHoleDensity( 869 ResolvedSpectralHoleDensity, CellResolvedSpectralCarrierDensity 870): 871 r"""Cell resolved spectral hole density. 872 873 Note: 874 `energies`: Electron energies [$\mathrm{eV}$]. 875 `rsv_values`: Cell resolved spectral hole density values 876 [$\mathrm{eV^{-1}}$]. 877 878 Note: 879 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 880 """
35def ret_fd_occups( 36 energies: Sequence[Real, ...], 37 *, 38 fermi_lv: Real = 0.0, 39 temperature: Real = 300.0, 40) -> np.ndarray[float]: 41 r"""Return Fermi-Dirac occupations. 42 43 Args: 44 energies: Electron energies [$\mathrm{eV}$]. 45 fermi_lv: Fermi level [$\mathrm{eV}$]. 46 temperature: Temperature [$\mathrm{K}$]. 47 48 Returns: 49 Fermi-Dirac occupations. 50 51 Raises: 52 ValueError: If temperature is non-positive. 53 """ 54 energies = np.asarray(energies, dtype=float).flatten() 55 if temperature <= 0.0: 56 raise ValueError("Non-positive temperature!") 57 red_energies = (energies - fermi_lv) / (Constant.k * temperature) 58 occups = np.where( 59 red_energies == 0.0, 60 0.5, 61 1.0 / (1.0 + np.exp(red_energies)), 62 ) 63 return occups
Return Fermi-Dirac occupations.
Arguments:
- energies: Electron energies [$\mathrm{eV}$].
- fermi_lv: Fermi level [$\mathrm{eV}$].
- temperature: Temperature [$\mathrm{K}$].
Returns:
Fermi-Dirac occupations.
Raises:
- ValueError: If temperature is non-positive.
66class SpectralCarrierDensityMeta(EnergySpectrumMeta): 67 r"""Metaclass of SpectralCarrierDensity.""" 68 69 @property 70 def std_axes(cls) -> plt.Axes: 71 r"""Standard axes to plot spectral carrier density. 72 73 Returns: 74 Plot axes. 75 """ 76 _, ax = plt.subplots(tight_layout=True) 77 ax.set_xlabel(r"Electron energy / $\mathrm{eV}$") 78 79 if "Carrier" in cls.__name__: 80 ax.set_ylabel(r"Spectral carrier density / $\mathrm{eV^{-1}}$") 81 if "Electron" in cls.__name__: 82 ax.set_ylabel(r"Spectral electron density / $\mathrm{eV^{-1}}$") 83 if "Hole" in cls.__name__: 84 ax.set_ylabel(r"Spectral hole density / $\mathrm{eV^{-1}}$") 85 86 return ax
Metaclass of SpectralCarrierDensity.
69 @property 70 def std_axes(cls) -> plt.Axes: 71 r"""Standard axes to plot spectral carrier density. 72 73 Returns: 74 Plot axes. 75 """ 76 _, ax = plt.subplots(tight_layout=True) 77 ax.set_xlabel(r"Electron energy / $\mathrm{eV}$") 78 79 if "Carrier" in cls.__name__: 80 ax.set_ylabel(r"Spectral carrier density / $\mathrm{eV^{-1}}$") 81 if "Electron" in cls.__name__: 82 ax.set_ylabel(r"Spectral electron density / $\mathrm{eV^{-1}}$") 83 if "Hole" in cls.__name__: 84 ax.set_ylabel(r"Spectral hole density / $\mathrm{eV^{-1}}$") 85 86 return ax
Standard axes to plot spectral carrier density.
Returns:
Plot axes.
Inherited Members
- builtins.type
- type
- mro
89class SpectralCarrierDensity( 90 EnergySpectrum, metaclass=SpectralCarrierDensityMeta 91): 92 r"""Spectral carrier density. 93 94 Note: 95 `energies`: Electron energies [$\mathrm{eV}$]. 96 `values`: Spectral carrier density values [$\mathrm{eV^{-1}}$]. 97 """ 98 99 def __init__( 100 self, 101 edos: ElectronDensityOfStates, 102 *, 103 fermi_lv: Real = 0.0, 104 temperature: Real = 300.0, 105 ) -> None: 106 r"""Initialize SpectralCarrierDensity object. 107 108 Args: 109 edos: Electron density of states. 110 fermi_lv: Fermi level [$\mathrm{eV}$]. 111 temperature: Temperature [$\mathrm{K}$]. 112 113 Raises: 114 TypeError: If `edos` is not a ElectronDensityOfStates object. 115 ValueError: If temperature is non-positive. 116 """ 117 if not isinstance(edos, ElectronDensityOfStates): 118 raise TypeError("Not a ElectronDensityOfStates object!") 119 if temperature <= 0.0: 120 raise ValueError("Non-positive temperature!") 121 122 self._edos = edos 123 self._fermi_lv = float(fermi_lv) 124 self._temperature = float(temperature) 125 self._energies = edos.energies 126 127 if isinstance(self, SpectralElectronDensity): 128 occups = ret_fd_occups( 129 self.energies, 130 fermi_lv=self.fermi_lv, 131 temperature=self.temperature, 132 ) 133 elif isinstance(self, SpectralHoleDensity): 134 occups = 1.0 - ret_fd_occups( 135 self.energies, 136 fermi_lv=self.fermi_lv, 137 temperature=self.temperature, 138 ) 139 else: 140 occups = 1.0 141 142 self._values = occups * edos.values 143 self._integr = np.trapz(self._values, x=self._energies) 144 self._sp_eden = None 145 self._sp_hden = None 146 147 def __add__(self, other: Self) -> Self: 148 r"""Add spectral carrier density. 149 150 Args: 151 other: Spectral carrier density to add. 152 153 Returns: 154 Sum of `self` and `other`. 155 156 Raises: 157 TypeError: If `self` and `other` have incompatible types. 158 ValueError: If `self` and `other`have incompatible Fermi levels. 159 ValueError: If `self` and `other`have incompatible temperatures. 160 """ 161 if type(self) != type(other): 162 raise TypeError("Incompatible types!") 163 if self.fermi_lv != other.fermi_lv: 164 raise ValueError("Incompatible Fermi levels!") 165 if self.temperature != other.temperature: 166 raise ValueError("Incompatible temperatures!") 167 edos = self.edos + other.edos 168 return type(self)( 169 edos, fermi_lv=self.fermi_lv, temperature=self.temperature 170 ) 171 172 @property 173 def edos(self) -> ElectronDensityOfStates: 174 r"""Electron density of states.""" 175 return self._edos 176 177 @property 178 def fermi_lv(self) -> float: 179 r"""Fermi level [$\mathrm{eV}$].""" 180 return self._fermi_lv 181 182 @property 183 def temperature(self) -> float: 184 r"""Temperature [$\mathrm{K}$].""" 185 return self._temperature 186 187 @property 188 def sp_eden(self) -> SpectralElectronDensity: 189 r"""Spectral electron density.""" 190 if self._sp_eden is None: 191 if isinstance(self, SpectralElectronDensity): 192 self._sp_eden = self 193 else: 194 self._sp_eden = SpectralElectronDensity( 195 self.edos, 196 fermi_lv=self.fermi_lv, 197 temperature=self.temperature, 198 ) 199 return self._sp_eden 200 201 @property 202 def sp_hden(self) -> SpectralHoleDensity: 203 r"""Spectral hole density.""" 204 if self._sp_hden is None: 205 if isinstance(self, SpectralHoleDensity): 206 self._sp_hden = self 207 else: 208 self._sp_hden = SpectralHoleDensity( 209 self.edos, 210 fermi_lv=self.fermi_lv, 211 temperature=self.temperature, 212 ) 213 return self._sp_hden 214 215 def ret_zero(self) -> Self: 216 r"""Return zero spectral carrier density.""" 217 return type(self).zero( 218 self.energies, fermi_lv=self.fermi_lv, temperature=self.temperature 219 ) 220 221 def ret_smeared(self, *, sigma: Real) -> Self: 222 r"""Return smeared spectral carrier density. 223 224 Args: 225 sigma: Standard deviation for Gaussian kernel. 226 227 Returns: 228 Smeared spectral carrier density. 229 """ 230 edos = self.edos.ret_smeared(sigma=sigma) 231 return type(self)( 232 edos, fermi_lv=self.fermi_lv, temperature=self.temperature 233 ) 234 235 def ret_band_rsv( 236 self, *, threshold: Real = 0.0 237 ) -> BandResolvedSpectralCarrierDensity: 238 r"""Return band resolved spectral carrier density. 239 240 Args: 241 threshold: Threshold below which electron density of states values 242 are rounded to zero [$\mathrm{eV^{-1}}$]. 243 244 Returns: 245 Band resolved spectral carrier density. 246 """ 247 rsv_edos = self.edos.ret_band_rsv(threshold=threshold) 248 return type(self).band_rsv( 249 rsv_edos, fermi_lv=self.fermi_lv, temperature=self.temperature 250 ) 251 252 def calc_ejdos(self) -> ElectronJointDensityOfStates: 253 r"""Calculate electron joint density of states. 254 255 Returns: 256 Electron joint density of states. 257 """ 258 ejdos_energies, ejdos_values = correlate1d( 259 self.energies, self.sp_eden.values, self.sp_hden.values 260 ) 261 return ElectronJointDensityOfStates(ejdos_energies, ejdos_values) 262 263 def plot_fermi_lv( 264 self, 265 *, 266 ax: plt.Axes, 267 color: str | None = None, 268 label: str | None = None, 269 ) -> plt.Figure: 270 r"""Plot Fermi level. 271 272 Args: 273 ax: Plot axes; if None, new figure and axes are created. 274 color: Line color. 275 label: Line label. 276 277 Returns: 278 Plot figure. 279 """ 280 ax.axvline(self.fermi_lv, linestyle="--", color=color, label=label) 281 return ax.get_figure() 282 283 @classmethod 284 def zero( 285 cls, 286 energies: Sequence[Real, ...], 287 *, 288 d_energy: Real | None = None, 289 fermi_lv: Real = 0.0, 290 temperature: Real = 300.0, 291 ) -> np.ndarray[float]: 292 r"""Zero spectral carrier density. 293 294 Args: 295 energies: Electron energies [$\mathrm{eV}$]. 296 d_energy: Target electron energy increment [$\mathrm{eV}$]. 297 fermi_lv: Fermi level [$\mathrm{eV}$]. 298 temperature: Temperature [$\mathrm{K}$]. 299 300 Returns: 301 Zero spectral carrier density. 302 """ 303 edos = ElectronDensityOfStates.zero(energies, d_energy=d_energy) 304 return cls(edos, fermi_lv=fermi_lv, temperature=temperature) 305 306 @classmethod 307 def piecewise_constant( 308 cls, 309 energy_a: Real, 310 energy_b: Real, 311 d_energy: Real, 312 *, 313 amplitudes: Sequence[Real, ...], 314 low_bounds: Sequence[Real, ...], 315 upp_bounds: Sequence[Real, ...], 316 fermi_lv: Real = 0.0, 317 temperature: Real = 300.0, 318 ) -> Self: 319 r"""Piecewise constant spectral carrier density. 320 321 Args: 322 energy_a: Electron energy minimum [$\mathrm{eV}$]. 323 energy_b: Electron energy maximum [$\mathrm{eV}$]. 324 d_energy: Target electron energy increment [$\mathrm{eV}$]. 325 amplitudes: Electron density of states piece amplitudes 326 [$\mathrm{eV^{-1}}$]. 327 low_bounds: Electron density of states piece lower bounds 328 [$\mathrm{eV}$]. 329 upp_bounds: Electron density of states piece upper bounds 330 [$\mathrm{eV}$]. 331 fermi_lv: Fermi level [$\mathrm{eV}$]. 332 temperature: Temperature [$\mathrm{K}$]. 333 334 Returns: 335 Piecewise constant spectral carrier density. 336 """ 337 edos = ElectronDensityOfStates.piecewise_constant( 338 energy_a, 339 energy_b, 340 d_energy, 341 amplitudes=amplitudes, 342 low_bounds=low_bounds, 343 upp_bounds=upp_bounds, 344 ) 345 return cls(edos, fermi_lv=fermi_lv, temperature=temperature)
Spectral carrier density.
Note:
energies: Electron energies [$\mathrm{eV}$].values: Spectral carrier density values [$\mathrm{eV^{-1}}$].
99 def __init__( 100 self, 101 edos: ElectronDensityOfStates, 102 *, 103 fermi_lv: Real = 0.0, 104 temperature: Real = 300.0, 105 ) -> None: 106 r"""Initialize SpectralCarrierDensity object. 107 108 Args: 109 edos: Electron density of states. 110 fermi_lv: Fermi level [$\mathrm{eV}$]. 111 temperature: Temperature [$\mathrm{K}$]. 112 113 Raises: 114 TypeError: If `edos` is not a ElectronDensityOfStates object. 115 ValueError: If temperature is non-positive. 116 """ 117 if not isinstance(edos, ElectronDensityOfStates): 118 raise TypeError("Not a ElectronDensityOfStates object!") 119 if temperature <= 0.0: 120 raise ValueError("Non-positive temperature!") 121 122 self._edos = edos 123 self._fermi_lv = float(fermi_lv) 124 self._temperature = float(temperature) 125 self._energies = edos.energies 126 127 if isinstance(self, SpectralElectronDensity): 128 occups = ret_fd_occups( 129 self.energies, 130 fermi_lv=self.fermi_lv, 131 temperature=self.temperature, 132 ) 133 elif isinstance(self, SpectralHoleDensity): 134 occups = 1.0 - ret_fd_occups( 135 self.energies, 136 fermi_lv=self.fermi_lv, 137 temperature=self.temperature, 138 ) 139 else: 140 occups = 1.0 141 142 self._values = occups * edos.values 143 self._integr = np.trapz(self._values, x=self._energies) 144 self._sp_eden = None 145 self._sp_hden = None
Initialize SpectralCarrierDensity object.
Arguments:
- edos: Electron density of states.
- fermi_lv: Fermi level [$\mathrm{eV}$].
- temperature: Temperature [$\mathrm{K}$].
Raises:
- TypeError: If
edosis not a ElectronDensityOfStates object. - ValueError: If temperature is non-positive.
172 @property 173 def edos(self) -> ElectronDensityOfStates: 174 r"""Electron density of states.""" 175 return self._edos
Electron density of states.
177 @property 178 def fermi_lv(self) -> float: 179 r"""Fermi level [$\mathrm{eV}$].""" 180 return self._fermi_lv
Fermi level [$\mathrm{eV}$].
182 @property 183 def temperature(self) -> float: 184 r"""Temperature [$\mathrm{K}$].""" 185 return self._temperature
Temperature [$\mathrm{K}$].
187 @property 188 def sp_eden(self) -> SpectralElectronDensity: 189 r"""Spectral electron density.""" 190 if self._sp_eden is None: 191 if isinstance(self, SpectralElectronDensity): 192 self._sp_eden = self 193 else: 194 self._sp_eden = SpectralElectronDensity( 195 self.edos, 196 fermi_lv=self.fermi_lv, 197 temperature=self.temperature, 198 ) 199 return self._sp_eden
Spectral electron density.
201 @property 202 def sp_hden(self) -> SpectralHoleDensity: 203 r"""Spectral hole density.""" 204 if self._sp_hden is None: 205 if isinstance(self, SpectralHoleDensity): 206 self._sp_hden = self 207 else: 208 self._sp_hden = SpectralHoleDensity( 209 self.edos, 210 fermi_lv=self.fermi_lv, 211 temperature=self.temperature, 212 ) 213 return self._sp_hden
Spectral hole density.
215 def ret_zero(self) -> Self: 216 r"""Return zero spectral carrier density.""" 217 return type(self).zero( 218 self.energies, fermi_lv=self.fermi_lv, temperature=self.temperature 219 )
Return zero spectral carrier density.
221 def ret_smeared(self, *, sigma: Real) -> Self: 222 r"""Return smeared spectral carrier density. 223 224 Args: 225 sigma: Standard deviation for Gaussian kernel. 226 227 Returns: 228 Smeared spectral carrier density. 229 """ 230 edos = self.edos.ret_smeared(sigma=sigma) 231 return type(self)( 232 edos, fermi_lv=self.fermi_lv, temperature=self.temperature 233 )
Return smeared spectral carrier density.
Arguments:
- sigma: Standard deviation for Gaussian kernel.
Returns:
Smeared spectral carrier density.
235 def ret_band_rsv( 236 self, *, threshold: Real = 0.0 237 ) -> BandResolvedSpectralCarrierDensity: 238 r"""Return band resolved spectral carrier density. 239 240 Args: 241 threshold: Threshold below which electron density of states values 242 are rounded to zero [$\mathrm{eV^{-1}}$]. 243 244 Returns: 245 Band resolved spectral carrier density. 246 """ 247 rsv_edos = self.edos.ret_band_rsv(threshold=threshold) 248 return type(self).band_rsv( 249 rsv_edos, fermi_lv=self.fermi_lv, temperature=self.temperature 250 )
Return band resolved spectral carrier density.
Arguments:
- threshold: Threshold below which electron density of states values are rounded to zero [$\mathrm{eV^{-1}}$].
Returns:
Band resolved spectral carrier density.
252 def calc_ejdos(self) -> ElectronJointDensityOfStates: 253 r"""Calculate electron joint density of states. 254 255 Returns: 256 Electron joint density of states. 257 """ 258 ejdos_energies, ejdos_values = correlate1d( 259 self.energies, self.sp_eden.values, self.sp_hden.values 260 ) 261 return ElectronJointDensityOfStates(ejdos_energies, ejdos_values)
Calculate electron joint density of states.
Returns:
Electron joint density of states.
263 def plot_fermi_lv( 264 self, 265 *, 266 ax: plt.Axes, 267 color: str | None = None, 268 label: str | None = None, 269 ) -> plt.Figure: 270 r"""Plot Fermi level. 271 272 Args: 273 ax: Plot axes; if None, new figure and axes are created. 274 color: Line color. 275 label: Line label. 276 277 Returns: 278 Plot figure. 279 """ 280 ax.axvline(self.fermi_lv, linestyle="--", color=color, label=label) 281 return ax.get_figure()
Plot Fermi level.
Arguments:
- ax: Plot axes; if None, new figure and axes are created.
- color: Line color.
- label: Line label.
Returns:
Plot figure.
283 @classmethod 284 def zero( 285 cls, 286 energies: Sequence[Real, ...], 287 *, 288 d_energy: Real | None = None, 289 fermi_lv: Real = 0.0, 290 temperature: Real = 300.0, 291 ) -> np.ndarray[float]: 292 r"""Zero spectral carrier density. 293 294 Args: 295 energies: Electron energies [$\mathrm{eV}$]. 296 d_energy: Target electron energy increment [$\mathrm{eV}$]. 297 fermi_lv: Fermi level [$\mathrm{eV}$]. 298 temperature: Temperature [$\mathrm{K}$]. 299 300 Returns: 301 Zero spectral carrier density. 302 """ 303 edos = ElectronDensityOfStates.zero(energies, d_energy=d_energy) 304 return cls(edos, fermi_lv=fermi_lv, temperature=temperature)
Zero spectral carrier density.
Arguments:
- energies: Electron energies [$\mathrm{eV}$].
- d_energy: Target electron energy increment [$\mathrm{eV}$].
- fermi_lv: Fermi level [$\mathrm{eV}$].
- temperature: Temperature [$\mathrm{K}$].
Returns:
Zero spectral carrier density.
306 @classmethod 307 def piecewise_constant( 308 cls, 309 energy_a: Real, 310 energy_b: Real, 311 d_energy: Real, 312 *, 313 amplitudes: Sequence[Real, ...], 314 low_bounds: Sequence[Real, ...], 315 upp_bounds: Sequence[Real, ...], 316 fermi_lv: Real = 0.0, 317 temperature: Real = 300.0, 318 ) -> Self: 319 r"""Piecewise constant spectral carrier density. 320 321 Args: 322 energy_a: Electron energy minimum [$\mathrm{eV}$]. 323 energy_b: Electron energy maximum [$\mathrm{eV}$]. 324 d_energy: Target electron energy increment [$\mathrm{eV}$]. 325 amplitudes: Electron density of states piece amplitudes 326 [$\mathrm{eV^{-1}}$]. 327 low_bounds: Electron density of states piece lower bounds 328 [$\mathrm{eV}$]. 329 upp_bounds: Electron density of states piece upper bounds 330 [$\mathrm{eV}$]. 331 fermi_lv: Fermi level [$\mathrm{eV}$]. 332 temperature: Temperature [$\mathrm{K}$]. 333 334 Returns: 335 Piecewise constant spectral carrier density. 336 """ 337 edos = ElectronDensityOfStates.piecewise_constant( 338 energy_a, 339 energy_b, 340 d_energy, 341 amplitudes=amplitudes, 342 low_bounds=low_bounds, 343 upp_bounds=upp_bounds, 344 ) 345 return cls(edos, fermi_lv=fermi_lv, temperature=temperature)
Piecewise constant spectral carrier density.
Arguments:
- energy_a: Electron energy minimum [$\mathrm{eV}$].
- energy_b: Electron energy maximum [$\mathrm{eV}$].
- d_energy: Target electron energy increment [$\mathrm{eV}$].
- amplitudes: Electron density of states piece amplitudes [$\mathrm{eV^{-1}}$].
- low_bounds: Electron density of states piece lower bounds [$\mathrm{eV}$].
- upp_bounds: Electron density of states piece upper bounds [$\mathrm{eV}$].
- fermi_lv: Fermi level [$\mathrm{eV}$].
- temperature: Temperature [$\mathrm{K}$].
Returns:
Piecewise constant spectral carrier density.
Inherited Members
348class SpectralElectronDensity(SpectralCarrierDensity): 349 r"""Spectral electron density. 350 351 Note: 352 `energies`: Electron energies [$\mathrm{eV}$]. 353 `values`: Spectral electron density values [$\mathrm{eV^{-1}}$]. 354 """
357class SpectralHoleDensity(SpectralCarrierDensity): 358 r"""Spectral hole density. 359 360 Note: 361 `energies`: Electron energies [$\mathrm{eV}$]. 362 `values`: Spectral hole density values [$\mathrm{eV^{-1}}$]. 363 """
366class ResolvedSpectralCarrierDensityMeta(ResolvedEnergySpectrumMeta): 367 r"""Metaclass of ResolvedSpectralCarrierDensity.""" 368 369 @property 370 def rsv_edos(cls) -> Type: 371 r"""Associated resolved electron density of states class.""" 372 module = modules[cls.__module__] 373 name = ( 374 cls.__name__[: cls.__name__.index("Resolved") + len("Resolved")] 375 + "ElectronDensityOfStates" 376 ) 377 return getattr(module, name) 378 379 @property 380 def rsv_sp_eden(cls) -> Type: 381 r"""Associated resolved spectral electron density class.""" 382 module = modules[cls.__module__] 383 name = cls.__name__.replace("Carrier", "Electron").replace( 384 "Hole", "Electron" 385 ) 386 return getattr(module, name) 387 388 @property 389 def rsv_sp_hden(cls) -> Type: 390 r"""Associated resolved spectral hole density class.""" 391 module = modules[cls.__module__] 392 name = cls.__name__.replace("Carrier", "Hole").replace( 393 "Electron", "Hole" 394 ) 395 return getattr(module, name) 396 397 @property 398 def rsv_ejdos(cls) -> Type: 399 r"""Associated resolved electron joint density of states class.""" 400 module = modules[cls.__module__] 401 name = ( 402 cls.__name__[: cls.__name__.index("Resolved") + len("Resolved")] 403 + "ElectronJointDensityOfStates" 404 ) 405 return getattr(module, name)
Metaclass of ResolvedSpectralCarrierDensity.
369 @property 370 def rsv_edos(cls) -> Type: 371 r"""Associated resolved electron density of states class.""" 372 module = modules[cls.__module__] 373 name = ( 374 cls.__name__[: cls.__name__.index("Resolved") + len("Resolved")] 375 + "ElectronDensityOfStates" 376 ) 377 return getattr(module, name)
Associated resolved electron density of states class.
379 @property 380 def rsv_sp_eden(cls) -> Type: 381 r"""Associated resolved spectral electron density class.""" 382 module = modules[cls.__module__] 383 name = cls.__name__.replace("Carrier", "Electron").replace( 384 "Hole", "Electron" 385 ) 386 return getattr(module, name)
Associated resolved spectral electron density class.
388 @property 389 def rsv_sp_hden(cls) -> Type: 390 r"""Associated resolved spectral hole density class.""" 391 module = modules[cls.__module__] 392 name = cls.__name__.replace("Carrier", "Hole").replace( 393 "Electron", "Hole" 394 ) 395 return getattr(module, name)
Associated resolved spectral hole density class.
397 @property 398 def rsv_ejdos(cls) -> Type: 399 r"""Associated resolved electron joint density of states class.""" 400 module = modules[cls.__module__] 401 name = ( 402 cls.__name__[: cls.__name__.index("Resolved") + len("Resolved")] 403 + "ElectronJointDensityOfStates" 404 ) 405 return getattr(module, name)
Associated resolved electron joint density of states class.
Inherited Members
- builtins.type
- type
- mro
408class ResolvedSpectralCarrierDensity( 409 ResolvedEnergySpectrum, metaclass=ResolvedSpectralCarrierDensityMeta 410): 411 r"""Resolved spectral carrier density. 412 413 Note: 414 `energies`: Electron energies [$\mathrm{eV}$]. 415 `rsv_values`: Resolved spectral carrier density values 416 [$\mathrm{eV^{-1}}$]. 417 """ 418 419 def __init__( 420 self, 421 rsv_edos: ResolvedElectronDensityOfStates, 422 *, 423 fermi_lv: Real = 0.0, 424 temperature: Real = 300.0, 425 ) -> None: 426 r"""Initialize ResolvedSpectralCarrierDensity object. 427 428 Args: 429 rsv_edos: Resolved electron density of states. 430 fermi_lv: Fermi level [$\mathrm{eV}$]. 431 temperature: Temperature [$\mathrm{K}$]. 432 433 Raises: 434 TypeError: If resolved electron density of states is incompatible. 435 ValueError: If temperature is non-positive. 436 """ 437 if type(rsv_edos) != type(self).rsv_edos: 438 raise TypeError("Incompatible resolved electron density of states!") 439 if temperature <= 0.0: 440 raise ValueError("Non-positive temperature!") 441 442 self._rsv_edos = rsv_edos 443 self._fermi_lv = float(fermi_lv) 444 self._temperature = float(temperature) 445 self._energies = self.rsv_edos.energies 446 447 if isinstance(self, ResolvedSpectralElectronDensity): 448 occups = ret_fd_occups( 449 self.energies, 450 fermi_lv=self.fermi_lv, 451 temperature=self.temperature, 452 ) 453 elif isinstance(self, ResolvedSpectralHoleDensity): 454 occups = 1.0 - ret_fd_occups( 455 self.energies, 456 fermi_lv=self.fermi_lv, 457 temperature=self.temperature, 458 ) 459 else: 460 occups = 1.0 461 462 self._rsv_values = { 463 feat: occups * edos_values 464 for feat, edos_values in self.rsv_edos.rsv_values.items() 465 } 466 self._rsv_integr = { 467 feat: np.trapz(values, x=self.energies) 468 for feat, values in self._rsv_values.items() 469 } 470 self._total = type(self).total( 471 self.rsv_edos.total, 472 fermi_lv=self.fermi_lv, 473 temperature=self.temperature, 474 ) 475 self._rsv_sp_eden = None 476 self._rsv_sp_hden = None 477 478 @property 479 def rsv_edos(self) -> ResolvedElectronDensityOfStates: 480 r"""Resolved electron density of states.""" 481 return self._rsv_edos 482 483 @property 484 def fermi_lv(self) -> float: 485 r"""Fermi level [$\mathrm{eV}$].""" 486 return self._fermi_lv 487 488 @property 489 def temperature(self) -> float: 490 r"""Temperature [$\mathrm{K}$].""" 491 return self._temperature 492 493 @property 494 def rsv_sp_eden(self) -> ResolvedSpectralElectronDensity: 495 r"""Resolved spectral electron density.""" 496 if self._rsv_sp_eden is None: 497 if isinstance(self, ResolvedSpectralElectronDensity): 498 self._rsv_sp_eden = self 499 else: 500 self._rsv_sp_eden = type(self).rsv_sp_eden( 501 self.rsv_edos, 502 fermi_lv=self.fermi_lv, 503 temperature=self.temperature, 504 ) 505 return self._rsv_sp_eden 506 507 @property 508 def rsv_sp_hden(self) -> ResolvedSpectralHoleDensity: 509 r"""Resolved spectral hole density.""" 510 if self._rsv_sp_hden is None: 511 if isinstance(self, ResolvedSpectralHoleDensity): 512 self._rsv_sp_hden = self 513 else: 514 self._rsv_sp_hden = type(self).rsv_sp_hden( 515 self.rsv_edos, 516 fermi_lv=self.fermi_lv, 517 temperature=self.temperature, 518 ) 519 return self._rsv_sp_hden 520 521 def ret_zero(self) -> Self: 522 r"""Return zero resolved spectral carrier density.""" 523 return type(self).zero( 524 self.rsv_edos.energies, 525 self.rsv_edos.rsv_values.keys(), 526 fermi_lv=self.fermi_lv, 527 temperature=self.temperature, 528 ) 529 530 def ret_smeared(self, *, sigma: Real) -> Self: 531 r"""Return smeared resolved spectral carrier density. 532 533 Args: 534 sigma: Standard deviation for Gaussian kernel. 535 536 Returns: 537 Smeared resolved spectral carrier density. 538 """ 539 rsv_edos = self.rsv_edos.ret_smeared(sigma=sigma) 540 return type(self)( 541 rsv_edos, fermi_lv=self.fermi_lv, temperature=self.temperature 542 ) 543 544 def calc_rsv_ejdos(self) -> ResolvedElectronJointDensityOfStates: 545 r"""Calculate resolved electron joint density of states.""" 546 rsv_ejdos_values = {} 547 for feat_e, values_e in self.rsv_sp_eden.rsv_values.items(): 548 for feat_h, values_h in self.rsv_sp_hden.rsv_values.items(): 549 if isinstance(self, CellResolvedSpectralCarrierDensity): 550 pair = feat_e + feat_h 551 if pair not in {"ii", "vi", "ic", "vc"}: 552 continue 553 else: 554 pair = (feat_e, feat_h) 555 556 ejdos_energies, ejdos_values = correlate1d( 557 self.energies, values_e, values_h 558 ) 559 rsv_ejdos_values[pair] = ejdos_values 560 561 return type(self).rsv_ejdos(ejdos_energies, rsv_ejdos_values) 562 563 def plot_fermi_lv( 564 self, 565 *, 566 ax: plt.Axes, 567 color: str | None = None, 568 label: str | None = None, 569 ) -> plt.Figure: 570 r"""Plot Fermi level. 571 572 Args: 573 ax: Plot axes; if None, new figure and axes are created. 574 color: Line color. 575 label: Line label. 576 577 Returns: 578 Plot figure. 579 """ 580 ax.axvline(self.fermi_lv, linestyle="--", color=color, label=label) 581 return ax.get_figure() 582 583 @classmethod 584 def zero( 585 cls, 586 energies: Sequence[Real, ...], 587 features: Sequence[Any, ...], 588 *, 589 d_energy: Real | None = None, 590 fermi_lv: Real = 0.0, 591 temperature: Real = 300.0, 592 ) -> Self: 593 r"""Zero resolved spectral carrier density. 594 595 Args: 596 energies: Resolved spectral carrier density energies 597 [$\mathrm{eV}$]. 598 features: Resolved spectral carrier density features. 599 d_energy: Target electron energy increment [$\mathrm{eV}$]. 600 fermi_lv: Fermi level [$\mathrm{eV}$]. 601 temperature: Temperature [$\mathrm{K}$]. 602 603 Returns: 604 Zero resolved spectral carrier density. 605 """ 606 rsv_edos = cls.rsv_edos.zero(energies, features, d_energy=d_energy) 607 return cls(rsv_edos, fermi_lv=fermi_lv, temperature=temperature)
Resolved spectral carrier density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Resolved spectral carrier density values [$\mathrm{eV^{-1}}$].
419 def __init__( 420 self, 421 rsv_edos: ResolvedElectronDensityOfStates, 422 *, 423 fermi_lv: Real = 0.0, 424 temperature: Real = 300.0, 425 ) -> None: 426 r"""Initialize ResolvedSpectralCarrierDensity object. 427 428 Args: 429 rsv_edos: Resolved electron density of states. 430 fermi_lv: Fermi level [$\mathrm{eV}$]. 431 temperature: Temperature [$\mathrm{K}$]. 432 433 Raises: 434 TypeError: If resolved electron density of states is incompatible. 435 ValueError: If temperature is non-positive. 436 """ 437 if type(rsv_edos) != type(self).rsv_edos: 438 raise TypeError("Incompatible resolved electron density of states!") 439 if temperature <= 0.0: 440 raise ValueError("Non-positive temperature!") 441 442 self._rsv_edos = rsv_edos 443 self._fermi_lv = float(fermi_lv) 444 self._temperature = float(temperature) 445 self._energies = self.rsv_edos.energies 446 447 if isinstance(self, ResolvedSpectralElectronDensity): 448 occups = ret_fd_occups( 449 self.energies, 450 fermi_lv=self.fermi_lv, 451 temperature=self.temperature, 452 ) 453 elif isinstance(self, ResolvedSpectralHoleDensity): 454 occups = 1.0 - ret_fd_occups( 455 self.energies, 456 fermi_lv=self.fermi_lv, 457 temperature=self.temperature, 458 ) 459 else: 460 occups = 1.0 461 462 self._rsv_values = { 463 feat: occups * edos_values 464 for feat, edos_values in self.rsv_edos.rsv_values.items() 465 } 466 self._rsv_integr = { 467 feat: np.trapz(values, x=self.energies) 468 for feat, values in self._rsv_values.items() 469 } 470 self._total = type(self).total( 471 self.rsv_edos.total, 472 fermi_lv=self.fermi_lv, 473 temperature=self.temperature, 474 ) 475 self._rsv_sp_eden = None 476 self._rsv_sp_hden = None
Initialize ResolvedSpectralCarrierDensity object.
Arguments:
- rsv_edos: Resolved electron density of states.
- fermi_lv: Fermi level [$\mathrm{eV}$].
- temperature: Temperature [$\mathrm{K}$].
Raises:
- TypeError: If resolved electron density of states is incompatible.
- ValueError: If temperature is non-positive.
478 @property 479 def rsv_edos(self) -> ResolvedElectronDensityOfStates: 480 r"""Resolved electron density of states.""" 481 return self._rsv_edos
Resolved electron density of states.
483 @property 484 def fermi_lv(self) -> float: 485 r"""Fermi level [$\mathrm{eV}$].""" 486 return self._fermi_lv
Fermi level [$\mathrm{eV}$].
488 @property 489 def temperature(self) -> float: 490 r"""Temperature [$\mathrm{K}$].""" 491 return self._temperature
Temperature [$\mathrm{K}$].
493 @property 494 def rsv_sp_eden(self) -> ResolvedSpectralElectronDensity: 495 r"""Resolved spectral electron density.""" 496 if self._rsv_sp_eden is None: 497 if isinstance(self, ResolvedSpectralElectronDensity): 498 self._rsv_sp_eden = self 499 else: 500 self._rsv_sp_eden = type(self).rsv_sp_eden( 501 self.rsv_edos, 502 fermi_lv=self.fermi_lv, 503 temperature=self.temperature, 504 ) 505 return self._rsv_sp_eden
Resolved spectral electron density.
507 @property 508 def rsv_sp_hden(self) -> ResolvedSpectralHoleDensity: 509 r"""Resolved spectral hole density.""" 510 if self._rsv_sp_hden is None: 511 if isinstance(self, ResolvedSpectralHoleDensity): 512 self._rsv_sp_hden = self 513 else: 514 self._rsv_sp_hden = type(self).rsv_sp_hden( 515 self.rsv_edos, 516 fermi_lv=self.fermi_lv, 517 temperature=self.temperature, 518 ) 519 return self._rsv_sp_hden
Resolved spectral hole density.
521 def ret_zero(self) -> Self: 522 r"""Return zero resolved spectral carrier density.""" 523 return type(self).zero( 524 self.rsv_edos.energies, 525 self.rsv_edos.rsv_values.keys(), 526 fermi_lv=self.fermi_lv, 527 temperature=self.temperature, 528 )
Return zero resolved spectral carrier density.
530 def ret_smeared(self, *, sigma: Real) -> Self: 531 r"""Return smeared resolved spectral carrier density. 532 533 Args: 534 sigma: Standard deviation for Gaussian kernel. 535 536 Returns: 537 Smeared resolved spectral carrier density. 538 """ 539 rsv_edos = self.rsv_edos.ret_smeared(sigma=sigma) 540 return type(self)( 541 rsv_edos, fermi_lv=self.fermi_lv, temperature=self.temperature 542 )
Return smeared resolved spectral carrier density.
Arguments:
- sigma: Standard deviation for Gaussian kernel.
Returns:
Smeared resolved spectral carrier density.
544 def calc_rsv_ejdos(self) -> ResolvedElectronJointDensityOfStates: 545 r"""Calculate resolved electron joint density of states.""" 546 rsv_ejdos_values = {} 547 for feat_e, values_e in self.rsv_sp_eden.rsv_values.items(): 548 for feat_h, values_h in self.rsv_sp_hden.rsv_values.items(): 549 if isinstance(self, CellResolvedSpectralCarrierDensity): 550 pair = feat_e + feat_h 551 if pair not in {"ii", "vi", "ic", "vc"}: 552 continue 553 else: 554 pair = (feat_e, feat_h) 555 556 ejdos_energies, ejdos_values = correlate1d( 557 self.energies, values_e, values_h 558 ) 559 rsv_ejdos_values[pair] = ejdos_values 560 561 return type(self).rsv_ejdos(ejdos_energies, rsv_ejdos_values)
Calculate resolved electron joint density of states.
563 def plot_fermi_lv( 564 self, 565 *, 566 ax: plt.Axes, 567 color: str | None = None, 568 label: str | None = None, 569 ) -> plt.Figure: 570 r"""Plot Fermi level. 571 572 Args: 573 ax: Plot axes; if None, new figure and axes are created. 574 color: Line color. 575 label: Line label. 576 577 Returns: 578 Plot figure. 579 """ 580 ax.axvline(self.fermi_lv, linestyle="--", color=color, label=label) 581 return ax.get_figure()
Plot Fermi level.
Arguments:
- ax: Plot axes; if None, new figure and axes are created.
- color: Line color.
- label: Line label.
Returns:
Plot figure.
583 @classmethod 584 def zero( 585 cls, 586 energies: Sequence[Real, ...], 587 features: Sequence[Any, ...], 588 *, 589 d_energy: Real | None = None, 590 fermi_lv: Real = 0.0, 591 temperature: Real = 300.0, 592 ) -> Self: 593 r"""Zero resolved spectral carrier density. 594 595 Args: 596 energies: Resolved spectral carrier density energies 597 [$\mathrm{eV}$]. 598 features: Resolved spectral carrier density features. 599 d_energy: Target electron energy increment [$\mathrm{eV}$]. 600 fermi_lv: Fermi level [$\mathrm{eV}$]. 601 temperature: Temperature [$\mathrm{K}$]. 602 603 Returns: 604 Zero resolved spectral carrier density. 605 """ 606 rsv_edos = cls.rsv_edos.zero(energies, features, d_energy=d_energy) 607 return cls(rsv_edos, fermi_lv=fermi_lv, temperature=temperature)
Zero resolved spectral carrier density.
Arguments:
- energies: Resolved spectral carrier density energies [$\mathrm{eV}$].
- features: Resolved spectral carrier density features.
- d_energy: Target electron energy increment [$\mathrm{eV}$].
- fermi_lv: Fermi level [$\mathrm{eV}$].
- temperature: Temperature [$\mathrm{K}$].
Returns:
Zero resolved spectral carrier density.
610class ResolvedSpectralElectronDensity(ResolvedSpectralCarrierDensity): 611 r"""Resolved spectral electron density. 612 613 Note: 614 `energies`: Electron energies [$\mathrm{eV}$]. 615 `rsv_values`: Resolved spectral electron density values 616 [$\mathrm{eV^{-1}}$]. 617 """
Resolved spectral electron density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Resolved spectral electron density values [$\mathrm{eV^{-1}}$].
Inherited Members
620class ResolvedSpectralHoleDensity(ResolvedSpectralCarrierDensity): 621 r"""Resolved spectral hole density. 622 623 Note: 624 `energies`: Electron energies [$\mathrm{eV}$]. 625 `rsv_values`: Resolved spectral hole density values 626 [$\mathrm{eV^{-1}}$]. 627 """
Resolved spectral hole density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Resolved spectral hole density values [$\mathrm{eV^{-1}}$].
Inherited Members
630class BandResolvedSpectralCarrierDensity(ResolvedSpectralCarrierDensity): 631 r"""Band resolved spectral carrier density. 632 633 Note: 634 `energies`: Electron energies [$\mathrm{eV}$]. 635 `rsv_values`: Band resolved spectral carrier density values 636 [$\mathrm{eV^{-1}}$]. 637 638 Note: 639 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 640 """ 641 642 def ret_rsv_fill_type(self, *, tolerance: Real = 0.0) -> dict[int, str]: 643 r"""Return band resolved fill type. 644 645 Args: 646 tolerance: Minimum distance between Fermi level and band edges 647 for band fill type to be determined [$\mathrm{eV}$]. 648 649 Returns: 650 Band resolved fill type. 651 """ 652 rsv_fill_type = {} 653 for i, edos_values in self.rsv_edos.rsv_values.items(): 654 band_energies = self.energies[edos_values > 0.0] 655 if ( 656 np.amin(band_energies) < self.fermi_lv - tolerance 657 and np.amax(band_energies) > self.fermi_lv + tolerance 658 ): 659 rsv_fill_type[i] = "metallic" 660 elif np.all(band_energies < self.fermi_lv + tolerance): 661 rsv_fill_type[i] = "filled" 662 elif np.all(band_energies > self.fermi_lv - tolerance): 663 rsv_fill_type[i] = "empty" 664 else: 665 rsv_fill_type[i] = "undetermined" 666 return rsv_fill_type 667 668 def ret_cell_rsv( 669 self, cell_type, *, tolerance: Real = 0.0 670 ) -> list[CellResolvedSpectralCarrierDensity, ...]: 671 r"""Return cell resolved spectral carrier densities. 672 673 Args: 674 cell_type: Cell type ('sq' ord 'ib'). 675 tolerance: Minimum distance between Fermi level and band edges 676 for band fill type to be determined [$\mathrm{eV}$]. 677 678 Returns: 679 List of cell resolved spectral carrier densities. 680 681 Raises: 682 ValueError: If cell type is not 'sq' or 'ib'. 683 """ 684 if cell_type not in {"sq", "ib"}: 685 raise ValueError("Cell type must be 'sq' or 'ib'!") 686 687 cell_rsv_seq = [] 688 rsv_fill_type = self.ret_rsv_fill_type(tolerance=tolerance) 689 690 if cell_type == "sq": 691 692 if set(rsv_fill_type.values()) == {"filled", "empty"}: 693 cell_rsv_edos_values = {"v": 0, "c": 0} 694 rsv_edos_values = self.rsv_edos.rsv_values 695 for band_i, fill_type in rsv_fill_type.items(): 696 edos_values = rsv_edos_values[band_i] 697 if fill_type == "filled": 698 cell_rsv_edos_values["v"] += edos_values 699 if fill_type == "empty": 700 cell_rsv_edos_values["c"] += edos_values 701 cell_rsv_edos = CellResolvedElectronDensityOfStates( 702 self.energies, cell_rsv_edos_values 703 ) 704 cell_rsv = type(self).total.cell_rsv( 705 cell_rsv_edos, 706 fermi_lv=self.fermi_lv, 707 temperature=self.temperature, 708 ) 709 cell_rsv_seq.append(cell_rsv) 710 711 elif cell_type == "ib": 712 713 if set(rsv_fill_type.values()) == {"filled", "metallic", "empty"}: 714 cell_rsv_edos_values = {"v": 0, "i": 0, "c": 0} 715 rsv_edos_values = self.rsv_edos.rsv_values 716 for band_i, fill_type in rsv_fill_type.items(): 717 edos_values = rsv_edos_values[band_i] 718 if fill_type == "filled": 719 cell_rsv_edos_values["v"] += edos_values 720 if fill_type == "metallic": 721 cell_rsv_edos_values["i"] += edos_values 722 if fill_type == "empty": 723 cell_rsv_edos_values["c"] += edos_values 724 cell_rsv_edos = CellResolvedElectronDensityOfStates( 725 self.energies, cell_rsv_edos_values 726 ) 727 cell_rsv = type(self).total.cell_rsv( 728 cell_rsv_edos, 729 fermi_lv=self.fermi_lv, 730 temperature=self.temperature, 731 ) 732 cell_rsv_seq.append(cell_rsv) 733 734 if set(rsv_fill_type.values()) == {"filled", "empty"}: 735 rsv_edos_values = self.rsv_edos.rsv_values 736 737 rsv_edos_values_filled = [ 738 rsv_edos_values[band_i] 739 for band_i, fill_type in rsv_fill_type.items() 740 if fill_type == "filled" 741 ] 742 rsv_edos_values_filled.sort(key=lambda x: x.min()) 743 744 rsv_edos_values_empty = [ 745 rsv_edos_values[band_i] 746 for band_i, fill_type in rsv_fill_type.items() 747 if fill_type == "empty" 748 ] 749 rsv_edos_values_empty.sort(key=lambda x: x.min()) 750 751 if len(rsv_edos_values_empty) > 1: 752 cell_rsv_edos_values = { 753 "v": sum(rsv_edos_values_filled), 754 "i": rsv_edos_values_empty[0], 755 "c": sum(rsv_edos_values_empty[1:]), 756 } 757 cell_rsv_edos = CellResolvedElectronDensityOfStates( 758 self.energies, cell_rsv_edos_values 759 ) 760 cell_rsv = type(self).total.cell_rsv( 761 cell_rsv_edos, 762 fermi_lv=self.fermi_lv, 763 temperature=self.temperature, 764 ) 765 cell_rsv_seq.append(cell_rsv) 766 767 if len(rsv_edos_values_filled) > 1: 768 cell_rsv_edos_values = { 769 "v": sum(rsv_edos_values_filled[:-1]), 770 "i": rsv_edos_values_filled[-1], 771 "c": sum(rsv_edos_values_empty), 772 } 773 cell_rsv_edos = CellResolvedElectronDensityOfStates( 774 self.energies, cell_rsv_edos_values 775 ) 776 cell_rsv = type(self).total.cell_rsv( 777 cell_rsv_edos, 778 fermi_lv=self.fermi_lv, 779 temperature=self.temperature, 780 ) 781 cell_rsv_seq.append(cell_rsv) 782 783 return cell_rsv_seq
Band resolved spectral carrier density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Band resolved spectral carrier density values [$\mathrm{eV^{-1}}$].
Note:
See
madman.analysis.spectrum.BandResolvedEnergySpectrumfor details.
642 def ret_rsv_fill_type(self, *, tolerance: Real = 0.0) -> dict[int, str]: 643 r"""Return band resolved fill type. 644 645 Args: 646 tolerance: Minimum distance between Fermi level and band edges 647 for band fill type to be determined [$\mathrm{eV}$]. 648 649 Returns: 650 Band resolved fill type. 651 """ 652 rsv_fill_type = {} 653 for i, edos_values in self.rsv_edos.rsv_values.items(): 654 band_energies = self.energies[edos_values > 0.0] 655 if ( 656 np.amin(band_energies) < self.fermi_lv - tolerance 657 and np.amax(band_energies) > self.fermi_lv + tolerance 658 ): 659 rsv_fill_type[i] = "metallic" 660 elif np.all(band_energies < self.fermi_lv + tolerance): 661 rsv_fill_type[i] = "filled" 662 elif np.all(band_energies > self.fermi_lv - tolerance): 663 rsv_fill_type[i] = "empty" 664 else: 665 rsv_fill_type[i] = "undetermined" 666 return rsv_fill_type
Return band resolved fill type.
Arguments:
- tolerance: Minimum distance between Fermi level and band edges for band fill type to be determined [$\mathrm{eV}$].
Returns:
Band resolved fill type.
668 def ret_cell_rsv( 669 self, cell_type, *, tolerance: Real = 0.0 670 ) -> list[CellResolvedSpectralCarrierDensity, ...]: 671 r"""Return cell resolved spectral carrier densities. 672 673 Args: 674 cell_type: Cell type ('sq' ord 'ib'). 675 tolerance: Minimum distance between Fermi level and band edges 676 for band fill type to be determined [$\mathrm{eV}$]. 677 678 Returns: 679 List of cell resolved spectral carrier densities. 680 681 Raises: 682 ValueError: If cell type is not 'sq' or 'ib'. 683 """ 684 if cell_type not in {"sq", "ib"}: 685 raise ValueError("Cell type must be 'sq' or 'ib'!") 686 687 cell_rsv_seq = [] 688 rsv_fill_type = self.ret_rsv_fill_type(tolerance=tolerance) 689 690 if cell_type == "sq": 691 692 if set(rsv_fill_type.values()) == {"filled", "empty"}: 693 cell_rsv_edos_values = {"v": 0, "c": 0} 694 rsv_edos_values = self.rsv_edos.rsv_values 695 for band_i, fill_type in rsv_fill_type.items(): 696 edos_values = rsv_edos_values[band_i] 697 if fill_type == "filled": 698 cell_rsv_edos_values["v"] += edos_values 699 if fill_type == "empty": 700 cell_rsv_edos_values["c"] += edos_values 701 cell_rsv_edos = CellResolvedElectronDensityOfStates( 702 self.energies, cell_rsv_edos_values 703 ) 704 cell_rsv = type(self).total.cell_rsv( 705 cell_rsv_edos, 706 fermi_lv=self.fermi_lv, 707 temperature=self.temperature, 708 ) 709 cell_rsv_seq.append(cell_rsv) 710 711 elif cell_type == "ib": 712 713 if set(rsv_fill_type.values()) == {"filled", "metallic", "empty"}: 714 cell_rsv_edos_values = {"v": 0, "i": 0, "c": 0} 715 rsv_edos_values = self.rsv_edos.rsv_values 716 for band_i, fill_type in rsv_fill_type.items(): 717 edos_values = rsv_edos_values[band_i] 718 if fill_type == "filled": 719 cell_rsv_edos_values["v"] += edos_values 720 if fill_type == "metallic": 721 cell_rsv_edos_values["i"] += edos_values 722 if fill_type == "empty": 723 cell_rsv_edos_values["c"] += edos_values 724 cell_rsv_edos = CellResolvedElectronDensityOfStates( 725 self.energies, cell_rsv_edos_values 726 ) 727 cell_rsv = type(self).total.cell_rsv( 728 cell_rsv_edos, 729 fermi_lv=self.fermi_lv, 730 temperature=self.temperature, 731 ) 732 cell_rsv_seq.append(cell_rsv) 733 734 if set(rsv_fill_type.values()) == {"filled", "empty"}: 735 rsv_edos_values = self.rsv_edos.rsv_values 736 737 rsv_edos_values_filled = [ 738 rsv_edos_values[band_i] 739 for band_i, fill_type in rsv_fill_type.items() 740 if fill_type == "filled" 741 ] 742 rsv_edos_values_filled.sort(key=lambda x: x.min()) 743 744 rsv_edos_values_empty = [ 745 rsv_edos_values[band_i] 746 for band_i, fill_type in rsv_fill_type.items() 747 if fill_type == "empty" 748 ] 749 rsv_edos_values_empty.sort(key=lambda x: x.min()) 750 751 if len(rsv_edos_values_empty) > 1: 752 cell_rsv_edos_values = { 753 "v": sum(rsv_edos_values_filled), 754 "i": rsv_edos_values_empty[0], 755 "c": sum(rsv_edos_values_empty[1:]), 756 } 757 cell_rsv_edos = CellResolvedElectronDensityOfStates( 758 self.energies, cell_rsv_edos_values 759 ) 760 cell_rsv = type(self).total.cell_rsv( 761 cell_rsv_edos, 762 fermi_lv=self.fermi_lv, 763 temperature=self.temperature, 764 ) 765 cell_rsv_seq.append(cell_rsv) 766 767 if len(rsv_edos_values_filled) > 1: 768 cell_rsv_edos_values = { 769 "v": sum(rsv_edos_values_filled[:-1]), 770 "i": rsv_edos_values_filled[-1], 771 "c": sum(rsv_edos_values_empty), 772 } 773 cell_rsv_edos = CellResolvedElectronDensityOfStates( 774 self.energies, cell_rsv_edos_values 775 ) 776 cell_rsv = type(self).total.cell_rsv( 777 cell_rsv_edos, 778 fermi_lv=self.fermi_lv, 779 temperature=self.temperature, 780 ) 781 cell_rsv_seq.append(cell_rsv) 782 783 return cell_rsv_seq
Return cell resolved spectral carrier densities.
Arguments:
- cell_type: Cell type ('sq' ord 'ib').
- tolerance: Minimum distance between Fermi level and band edges for band fill type to be determined [$\mathrm{eV}$].
Returns:
List of cell resolved spectral carrier densities.
Raises:
- ValueError: If cell type is not 'sq' or 'ib'.
Inherited Members
786class BandResolvedSpectralElectronDensity( 787 ResolvedSpectralElectronDensity, BandResolvedSpectralCarrierDensity 788): 789 r"""Band resolved spectral electron density. 790 791 Note: 792 `energies`: Electron energies [$\mathrm{eV}$]. 793 `rsv_values`: Band resolved spectral electron density values 794 [$\mathrm{eV^{-1}}$]. 795 796 Note: 797 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 798 """
Band resolved spectral electron density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Band resolved spectral electron density values [$\mathrm{eV^{-1}}$].
Note:
See
madman.analysis.spectrum.BandResolvedEnergySpectrumfor details.
Inherited Members
801class BandResolvedSpectralHoleDensity( 802 ResolvedSpectralHoleDensity, BandResolvedSpectralCarrierDensity 803): 804 r"""Band resolved spectral hole density. 805 806 Note: 807 `energies`: Electron energies [$\mathrm{eV}$]. 808 `rsv_values`: Band resolved spectral hole density values 809 [$\mathrm{eV^{-1}}$]. 810 811 Note: 812 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 813 """
Band resolved spectral hole density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Band resolved spectral hole density values [$\mathrm{eV^{-1}}$].
Note:
See
madman.analysis.spectrum.BandResolvedEnergySpectrumfor details.
Inherited Members
816class CellResolvedSpectralCarrierDensity(ResolvedSpectralCarrierDensity): 817 r"""Cell resolved spectral carrier density. 818 819 Note: 820 `energies`: Electron energies [$\mathrm{eV}$]. 821 `rsv_values`: Cell resolved spectral carrier density values 822 [$\mathrm{eV^{-1}}$]. 823 824 Note: 825 See `madman.analysis.spectrum.CellResolvedEnergySpectrum` for details. 826 """ 827 def ret_rsv_fill_type(self, *, tolerance: Real = 0.0) -> dict[int, str]: 828 r"""Return cell resolved fill type. 829 830 Args: 831 tolerance: Minimum distance between Fermi level and band edges 832 for band fill type to be determined [$\mathrm{eV}$]. 833 834 Returns: 835 Cell resolved fill type. 836 """ 837 rsv_fill_type = {} 838 for i, edos_values in self.rsv_edos.rsv_values.items(): 839 band_energies = self.energies[edos_values > 0.0] 840 if ( 841 np.amin(band_energies) < self.fermi_lv - tolerance 842 and np.amax(band_energies) > self.fermi_lv + tolerance 843 ): 844 rsv_fill_type[i] = "metallic" 845 elif np.all(band_energies < self.fermi_lv + tolerance): 846 rsv_fill_type[i] = "filled" 847 elif np.all(band_energies > self.fermi_lv - tolerance): 848 rsv_fill_type[i] = "empty" 849 else: 850 rsv_fill_type[i] = "undetermined" 851 return rsv_fill_type
Cell resolved spectral carrier density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Cell resolved spectral carrier density values [$\mathrm{eV^{-1}}$].
Note:
See
madman.analysis.spectrum.CellResolvedEnergySpectrumfor details.
827 def ret_rsv_fill_type(self, *, tolerance: Real = 0.0) -> dict[int, str]: 828 r"""Return cell resolved fill type. 829 830 Args: 831 tolerance: Minimum distance between Fermi level and band edges 832 for band fill type to be determined [$\mathrm{eV}$]. 833 834 Returns: 835 Cell resolved fill type. 836 """ 837 rsv_fill_type = {} 838 for i, edos_values in self.rsv_edos.rsv_values.items(): 839 band_energies = self.energies[edos_values > 0.0] 840 if ( 841 np.amin(band_energies) < self.fermi_lv - tolerance 842 and np.amax(band_energies) > self.fermi_lv + tolerance 843 ): 844 rsv_fill_type[i] = "metallic" 845 elif np.all(band_energies < self.fermi_lv + tolerance): 846 rsv_fill_type[i] = "filled" 847 elif np.all(band_energies > self.fermi_lv - tolerance): 848 rsv_fill_type[i] = "empty" 849 else: 850 rsv_fill_type[i] = "undetermined" 851 return rsv_fill_type
Return cell resolved fill type.
Arguments:
- tolerance: Minimum distance between Fermi level and band edges for band fill type to be determined [$\mathrm{eV}$].
Returns:
Cell resolved fill type.
Inherited Members
854class CellResolvedSpectralElectronDensity( 855 ResolvedSpectralElectronDensity, CellResolvedSpectralCarrierDensity 856): 857 r"""Cell resolved spectral electron density. 858 859 Note: 860 `energies`: Electron energies [$\mathrm{eV}$]. 861 `rsv_values`: Cell resolved spectral electron density values 862 [$\mathrm{eV^{-1}}$]. 863 864 Note: 865 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 866 """
Cell resolved spectral electron density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Cell resolved spectral electron density values [$\mathrm{eV^{-1}}$].
Note:
See
madman.analysis.spectrum.BandResolvedEnergySpectrumfor details.
Inherited Members
869class CellResolvedSpectralHoleDensity( 870 ResolvedSpectralHoleDensity, CellResolvedSpectralCarrierDensity 871): 872 r"""Cell resolved spectral hole density. 873 874 Note: 875 `energies`: Electron energies [$\mathrm{eV}$]. 876 `rsv_values`: Cell resolved spectral hole density values 877 [$\mathrm{eV^{-1}}$]. 878 879 Note: 880 See `madman.analysis.spectrum.BandResolvedEnergySpectrum` for details. 881 """
Cell resolved spectral hole density.
Note:
energies: Electron energies [$\mathrm{eV}$].rsv_values: Cell resolved spectral hole density values [$\mathrm{eV^{-1}}$].
Note:
See
madman.analysis.spectrum.BandResolvedEnergySpectrumfor details.