@@ -354,6 +354,47 @@ def mae(self, other: PhononDos, two_sided: bool = True) -> float:
354
354
355
355
return self_mae
356
356
357
+ def get_last_peak (self , threshold : float = 0.1 ) -> float :
358
+ """Find the last peak in the phonon DOS defined as the highest frequency with a DOS
359
+ value at least threshold * height of the overall highest DOS peak.
360
+ A peak is any local maximum of the DOS as a function of frequency.
361
+ Use dos.get_interpolated_value(peak_freq) to get density at peak_freq.
362
+
363
+ TODO method added by @janosh on 2023-12-18. seems to work well in most cases but
364
+ was not extensively tested. PRs with improvements welcome!
365
+
366
+ Args:
367
+ threshold (float, optional): Minimum ratio of the height of the last peak
368
+ to the height of the highest peak. Defaults to 0.1 = 10%. In case no peaks
369
+ are high enough to match, the threshold is reset to half the height of the
370
+ second-highest peak.
371
+
372
+ Returns:
373
+ float: last DOS peak frequency (in THz)
374
+ """
375
+ first_deriv = np .gradient (self .densities , self .frequencies )
376
+ second_deriv = np .gradient (first_deriv , self .frequencies )
377
+
378
+ maxima = ( # maxima indices of the first DOS derivative w.r.t. frequency
379
+ (first_deriv [:- 1 ] > 0 ) & (first_deriv [1 :] < 0 ) & (second_deriv [:- 1 ] < 0 )
380
+ )
381
+ # get mean of the two nearest frequencies around the maximum as better estimate
382
+ maxima_freqs = (self .frequencies [:- 1 ][maxima ] + self .frequencies [1 :][maxima ]) / 2
383
+
384
+ # filter maxima based on the threshold
385
+ max_dos = max (self .densities )
386
+ threshold = threshold * max_dos
387
+ filtered_maxima_freqs = maxima_freqs [self .densities [:- 1 ][maxima ] >= threshold ]
388
+
389
+ if len (filtered_maxima_freqs ) == 0 :
390
+ # if no maxima reach the threshold (i.e. 1 super high peak and all other peaks
391
+ # tiny), use half the height of second highest peak as threshold
392
+ second_highest_peak = sorted (self .densities )[- 2 ]
393
+ threshold = second_highest_peak / 2
394
+ filtered_maxima_freqs = maxima_freqs [self .densities [:- 1 ][maxima ] >= threshold ]
395
+
396
+ return max (filtered_maxima_freqs )
397
+
357
398
358
399
class CompletePhononDos (PhononDos ):
359
400
"""This wrapper class defines a total dos, and also provides a list of PDos.
0 commit comments