41
41
from pymatgen .symmetry .bandstructure import HighSymmKpath
42
42
43
43
if TYPE_CHECKING :
44
- from typing import Literal
44
+ from typing import Any , Literal
45
45
46
46
from numpy .typing import ArrayLike
47
47
from typing_extensions import Self
@@ -1426,96 +1426,98 @@ def get_complexity_factor(
1426
1426
1427
1427
def get_extreme (
1428
1428
self ,
1429
- target_prop ,
1430
- maximize = True ,
1431
- min_temp = None ,
1432
- max_temp = None ,
1433
- min_doping = None ,
1434
- max_doping = None ,
1435
- isotropy_tolerance = 0.05 ,
1436
- use_average = True ,
1437
- ):
1429
+ target_prop : Literal [ "seebeck" , "power factor" , "conductivity" , "kappa" , "zt" ] ,
1430
+ maximize : bool = True ,
1431
+ min_temp : float | None = None ,
1432
+ max_temp : float | None = None ,
1433
+ min_doping : float | None = None ,
1434
+ max_doping : float | None = None ,
1435
+ isotropy_tolerance : float = 0.05 ,
1436
+ use_average : bool = True ,
1437
+ ) -> dict [ Literal [ "p" , "n" , "best" ], dict [ str , Any ]] :
1438
1438
"""Use eigenvalues over a range of carriers, temperatures, and doping levels, to estimate the "best"
1439
1439
value that can be achieved for the given target_property. Note that
1440
1440
this method searches the doping dict only, not the full mu dict.
1441
1441
1442
1442
Args:
1443
- target_prop: target property, i.e. "seebeck", "power factor", "conductivity", "kappa", or "zt"
1444
- maximize: True to maximize, False to minimize (e.g. kappa)
1445
- min_temp: minimum temperature allowed
1446
- max_temp: maximum temperature allowed
1447
- min_doping: minimum doping allowed (e.g., 1E18)
1448
- max_doping: maximum doping allowed (e.g., 1E20)
1449
- isotropy_tolerance: tolerance for isotropic (0.05 = 5%)
1450
- use_average: True for avg of eigenval, False for max eigenval
1443
+ target_prop ( "seebeck", "power factor", "conductivity", "kappa", "zt"): target property.
1444
+ maximize (bool) : True to maximize, False to minimize (e.g. kappa)
1445
+ min_temp (float) : minimum temperature allowed
1446
+ max_temp (float) : maximum temperature allowed
1447
+ min_doping (float) : minimum doping allowed (e.g., 1E18)
1448
+ max_doping (float) : maximum doping allowed (e.g., 1E20)
1449
+ isotropy_tolerance (float) : tolerance for isotropic (0.05 = 5%)
1450
+ use_average (bool) : True for average of eigenval, False for max eigenval.
1451
1451
1452
1452
Returns:
1453
- A dictionary with keys {"p", "n", "best"} with sub-keys:
1454
- {"value", "temperature", "doping", "isotropic"}
1453
+ A dictionary with the following keys: {"p", "n", "best"}.
1454
+ Each key maps to a sub-dictionary with the following keys:
1455
+ {"value", "temperature", "doping", "isotropic", "carrier_type"}.
1455
1456
"""
1456
1457
1457
- def is_isotropic (x , isotropy_tolerance ) -> bool :
1458
- """Internal method to tell you if 3-vector "x" is isotropic.
1458
+ def is_isotropic (x , isotropy_tolerance : float ) -> bool :
1459
+ """Helper function to determine if 3D vector is isotropic.
1459
1460
1460
1461
Args:
1461
1462
x: the vector to determine isotropy for
1462
- isotropy_tolerance: tolerance, e.g. 0.05 is 5%
1463
+ isotropy_tolerance (float) : tolerance, e.g. 0.05 is 5%
1463
1464
"""
1464
1465
if len (x ) != 3 :
1465
- raise ValueError ("Invalid input to is_isotropic!" )
1466
+ raise ValueError ("Invalid vector length to is_isotropic!" )
1466
1467
1467
1468
st = sorted (x )
1469
+
1468
1470
return bool (
1469
1471
all ([st [0 ], st [1 ], st [2 ]])
1470
1472
and (abs ((st [1 ] - st [0 ]) / st [1 ]) <= isotropy_tolerance )
1471
- and (abs (st [2 ] - st [0 ]) / st [2 ] <= isotropy_tolerance )
1473
+ and (abs (( st [2 ] - st [0 ]) / st [2 ]) <= isotropy_tolerance )
1472
1474
and (abs ((st [2 ] - st [1 ]) / st [2 ]) <= isotropy_tolerance )
1473
1475
)
1474
1476
1475
1477
if target_prop .lower () == "seebeck" :
1476
- d = self .get_seebeck (output = "eigs" , doping_levels = True )
1478
+ dct = self .get_seebeck (output = "eigs" , doping_levels = True )
1477
1479
1478
1480
elif target_prop .lower () == "power factor" :
1479
- d = self .get_power_factor (output = "eigs" , doping_levels = True )
1481
+ dct = self .get_power_factor (output = "eigs" , doping_levels = True )
1480
1482
1481
1483
elif target_prop .lower () == "conductivity" :
1482
- d = self .get_conductivity (output = "eigs" , doping_levels = True )
1484
+ dct = self .get_conductivity (output = "eigs" , doping_levels = True )
1483
1485
1484
1486
elif target_prop .lower () == "kappa" :
1485
- d = self .get_thermal_conductivity (output = "eigs" , doping_levels = True )
1487
+ dct = self .get_thermal_conductivity (output = "eigs" , doping_levels = True )
1486
1488
elif target_prop .lower () == "zt" :
1487
- d = self .get_zt (output = "eigs" , doping_levels = True )
1489
+ dct = self .get_zt (output = "eigs" , doping_levels = True )
1488
1490
1489
1491
else :
1490
1492
raise ValueError (f"Unrecognized { target_prop = } " )
1491
1493
1492
- abs_val = True # take the absolute value of properties
1494
+ abs_val : bool = True # take the absolute value of properties
1493
1495
1494
1496
x_val = x_temp = x_doping = x_isotropic = None
1495
- output = {}
1497
+ output : dict [ Literal [ "p" , "n" , "best" ], dict [ str , Any ]] = {}
1496
1498
1497
1499
min_temp = min_temp or 0
1498
1500
max_temp = max_temp or float ("inf" )
1499
1501
min_doping = min_doping or 0
1500
1502
max_doping = max_doping or float ("inf" )
1501
1503
1502
- for pn in ("p" , "n" ):
1503
- for t in d [ pn ]: # temperatures
1504
- if min_temp <= float (t ) <= max_temp :
1505
- for didx , evs in enumerate (d [ pn ][ t ]):
1506
- doping_lvl = self .doping [pn ][ didx ]
1504
+ for pn_type in ("p" , "n" ):
1505
+ for temperature in dct [ pn_type ]:
1506
+ if min_temp <= float (temperature ) <= max_temp :
1507
+ for idx , eig_vals in enumerate (dct [ pn_type ][ temperature ]):
1508
+ doping_lvl = self .doping [pn_type ][ idx ]
1507
1509
if min_doping <= doping_lvl <= max_doping :
1508
- isotropic = is_isotropic (evs , isotropy_tolerance )
1510
+ isotropic : bool = is_isotropic (eig_vals , isotropy_tolerance )
1509
1511
if abs_val :
1510
- evs = [abs (x ) for x in evs ]
1511
- val = float (sum (evs )) / len (evs ) if use_average else max (evs )
1512
+ eig_vals = [abs (x ) for x in eig_vals ]
1513
+ val = float (sum (eig_vals )) / len (eig_vals ) if use_average else max (eig_vals )
1512
1514
if x_val is None or (val > x_val and maximize ) or (val < x_val and not maximize ):
1513
1515
x_val = val
1514
- x_temp = t
1516
+ x_temp = temperature
1515
1517
x_doping = doping_lvl
1516
1518
x_isotropic = isotropic
1517
1519
1518
- output [pn ] = {
1520
+ output [pn_type ] = {
1519
1521
"value" : x_val ,
1520
1522
"temperature" : x_temp ,
1521
1523
"doping" : x_doping ,
@@ -1524,7 +1526,7 @@ def is_isotropic(x, isotropy_tolerance) -> bool:
1524
1526
x_val = None
1525
1527
1526
1528
if maximize :
1527
- max_type = "p" if output ["p" ]["value" ] >= output ["n" ]["value" ] else "n"
1529
+ max_type : Literal [ "p" , "n" ] = "p" if output ["p" ]["value" ] >= output ["n" ]["value" ] else "n"
1528
1530
else :
1529
1531
max_type = "p" if output ["p" ]["value" ] <= output ["n" ]["value" ] else "n"
1530
1532
@@ -1589,10 +1591,10 @@ def get_complete_dos(self, structure: Structure, analyzer_for_second_spin=None):
1589
1591
Example of use in case of spin polarized case:
1590
1592
1591
1593
BoltztrapRunner(bs=bs,nelec=10,run_type="DOS",spin=1).run(path_dir='dos_up/')
1592
- an_up=BoltztrapAnalyzer.from_files("dos_up/boltztrap/",dos_spin=1)
1594
+ an_up=BoltztrapAnalyzer.from_files("dos_up/boltztrap/", dos_spin=1)
1593
1595
1594
1596
BoltztrapRunner(bs=bs,nelec=10,run_type="DOS",spin=-1).run(path_dir='dos_dw/')
1595
- an_dw=BoltztrapAnalyzer.from_files("dos_dw/boltztrap/",dos_spin=-1)
1597
+ an_dw=BoltztrapAnalyzer.from_files("dos_dw/boltztrap/", dos_spin=-1)
1596
1598
1597
1599
cdos=an_up.get_complete_dos(bs.structure,an_dw)
1598
1600
"""
@@ -1602,10 +1604,10 @@ def get_complete_dos(self, structure: Structure, analyzer_for_second_spin=None):
1602
1604
1603
1605
if analyzer_for_second_spin :
1604
1606
if not np .all (self .dos .energies == analyzer_for_second_spin .dos .energies ):
1605
- raise BoltztrapError ("Dos merging error: energies of the two dos are different" )
1607
+ raise BoltztrapError ("DOS merging error: energies of the two DOS are different" )
1606
1608
1607
1609
if spin_1 == spin_2 :
1608
- raise BoltztrapError ("Dos merging error: spin component are the same" )
1610
+ raise BoltztrapError ("DOS merging error: spin component are the same" )
1609
1611
1610
1612
for s in self ._dos_partial :
1611
1613
idx = int (s )
0 commit comments