From aa0279f31eb1a4c667491aea19c91a2fd2b254ad Mon Sep 17 00:00:00 2001 From: "Kieran B. Spooner" Date: Tue, 15 Aug 2023 16:30:38 +0100 Subject: [PATCH] tp plot transport fixes and refinement tp plot transport now works with mobility axes limits and scaling now fully implemented in tp plor transport developer-side streamlining of cli options --- tp/cli/cli.py | 190 ++++++++++++++++++++++++++++----------------- tp/cli/options.py | 154 ++++++++++++++++-------------------- tp/plot/phonons.py | 2 +- 3 files changed, 187 insertions(+), 159 deletions(-) diff --git a/tp/cli/cli.py b/tp/cli/cli.py index 309c458..d2daf01 100644 --- a/tp/cli/cli.py +++ b/tp/cli/cli.py @@ -126,8 +126,8 @@ def get(): default='conductivity', show_default=True) @doping_type_option -@doping_option -@direction_option +@doping_function() +@direction_function() @temperature_option @click.option('--spin', help='Spin direction.', @@ -253,8 +253,8 @@ def get_amset(amset_file, quantity, dtype, doping, direction, temperature, spin, default='conductivity', show_default=True) @doping_type_option -@doping_option -@direction_option +@doping_function() +@direction_function() @temperature_option def get_boltztrap(boltztrap_hdf5, quantity, dtype, doping, direction, temperature): @@ -311,7 +311,7 @@ def get_boltztrap(boltztrap_hdf5, quantity, dtype, doping, direction, temperatur help='Quantity to read.', default='lattice_thermal_conductivity', show_default=True) -@direction_option +@direction_function() @temperature_option @click.option('-b', '--band', help='Phonon band index (1-indexed).', @@ -404,8 +404,8 @@ def get_phono3py(kappa_hdf5, quantity, direction, temperature, band, qpoint, help='Phono3py kappa-mxxx.hdf5.', type=click.Path(exists=True, file_okay=True, dir_okay=False)) @doping_type_option -@doping_option -@direction_option +@doping_function() +@direction_function() @temperature_option @click.option('--max', is_flag=True, @@ -569,7 +569,7 @@ def save(): help='x-axis quantity. [default: frequency]', default=False, show_default=False) -@direction_option +@direction_function() @temperature_option @click.option('-o', '--output', help='Output filename, sans extension.', @@ -598,7 +598,7 @@ def save_cumkappa(kappa_hdf5, mfp, direction, temperature, output, extension): @save.command('kappa') @inputs_function('kappa_hdf5', nargs=1) -@directions_option +@direction_function(multiple=True) @click.option('-o', '--output', help='Output filenames, sans extension.', default='tp-kappa', @@ -632,7 +632,7 @@ def save_kappa(kappa_hdf5, direction, output): help='Phono3py kappa-mxxx.hdf5.', type=click.Path(exists=True, file_okay=True, dir_okay=False)) @doping_type_option -@direction_option +@direction_function() @interpolate_options @click.option('-o', '--output', help='Output filename, sans extension.', @@ -676,7 +676,7 @@ def plot(): @click.option('--crt', help='Constant relaxation time rate. [default: off]', type=float) -@doping_option +@doping_function() @temperature_option @click.option('-c', '--colour', @@ -687,7 +687,7 @@ def plot(): show_default=True) @line_options -@xy_limit_options +@axes_limit_function() @plot_io_function('tp-avg-rates') @verbose_option @@ -853,7 +853,7 @@ def avg_rates(mesh_h5, total, x, crt, doping, temperature, colour, linestyle, multiple=True, type=float) -@directions_option +@direction_function(multiple=True) @temperature_option @click.option('--xmin', help='Override minimum x.', @@ -871,7 +871,7 @@ def avg_rates(mesh_h5, total, x, crt, doping, temperature, colour, linestyle, @fill_options @line_options -@xy_limit_options +@axes_limit_function() @legend_function(toggle=False) @plot_io_function('tp-cumkappa') @verbose_option @@ -960,7 +960,7 @@ def cumkappa(kappa_hdf5, mfp, percent, xmarkers, ymarkers, direction, @fill_options @line_options -@xy_limit_options +@axes_limit_function() @legend_function(label=False) @plot_io_function('tp-dos') @@ -1031,7 +1031,7 @@ def dos(dos_dat, poscar, atoms, sigma, projected, total, total_label, type=click.Choice(['lattice', 'electronic', 'total'], case_sensitive=False), show_default=True) -@directions_option +@direction_function(multiple=True) @click.option('--tmin', help='Minimum temperature to plot, by default in K.', default=300., @@ -1041,7 +1041,7 @@ def dos(dos_dat, poscar, atoms, sigma, projected, total, total_label, default=np.inf, show_default=False) @doping_type_option -@doping_option +@doping_function() @click.option('-c', '--colour', help='Colourmap name or min and max colours or list of ' @@ -1051,7 +1051,7 @@ def dos(dos_dat, poscar, atoms, sigma, projected, total, total_label, show_default=True) @line_options -@xy_limit_options +@axes_limit_function() @legend_function() @plot_io_function('tp-kappa') @@ -1277,7 +1277,7 @@ def kappa(kfile, efile, component, direction, tmin, tmax, dtype, doping, default=2., show_default=True) -@direction_option +@direction_function() @interpolate_options @click.option('-c', '--colour', @@ -1293,8 +1293,7 @@ def kappa(kfile, efile, component, direction, tmin, tmax, dtype, doping, default='grey', show_default=True) -@xy_limit_options -@c_limit_options +@axes_limit_function(c=True) @plot_io_function('tp-kappa-target') def kappa_target(transport_file, zt, direction, interpolate, kind, colour, @@ -1464,7 +1463,7 @@ def converge_phonons(band_yaml, bandmin, bandmax, colour, alpha, linestyle, default=['conductivity', 'seebeck', 'electronic_thermal_conductivity'], show_default=True) -@directions_option +@direction_function(multiple=True) @click.option('--tmin', help='Minimum temperature to plot, by default in K.', default=300., @@ -1474,7 +1473,16 @@ def converge_phonons(band_yaml, bandmin, bandmax, colour, alpha, linestyle, default=np.inf, show_default=False) @doping_type_option -@dopings_option +@doping_function(multiple=True) +@click.option('--stype', + help='Scattering type(s) for mobility. Cedes precedence ' + 'other options (e.g. doping). If other options are ' + 'specified, only shows the first stype supplied, ' + 'Total by default. Otherwise defaults to show all ' + 'scattering types including Total.', + multiple=True, + default=[None], + show_default=False) @click.option('-c', '--colour', help='Colourmap name or min and max colours or list of ' @@ -1484,24 +1492,34 @@ def converge_phonons(band_yaml, bandmin, bandmax, colour, alpha, linestyle, show_default=True) @line_options -@xy_limit_options +@axes_limit_function(multiple=True) +@click.option('--xscale', + help='x-scale.', + type=click.Choice(['linear', 'log'], case_sensitive=False), + multiple=True, + default=['linear'], + show_default=True) +@click.option('--yscale', + help='y-scale.', + type=click.Choice(['linear', 'log'], case_sensitive=False), + multiple=True, + default=['linear'], + show_default=True) @legend_function() @plot_io_function('tp-transport') def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, - doping, colour, linestyle, marker, xmin, xmax, ymin, ymax, - label, legend_title, legend, location, style, large, save, show, - extension, output): + doping, stype, colour, linestyle, marker, xmin, xmax, ymin, + ymax, xscale, yscale, label, legend_title, legend, location, style, large, save, + show, extension, output): """Plots line graphs of transport properties against temperature. Currently not all combinations of inputs work. The order of - precedence is lines represent doping > direction > files. - If using multiple sets of files (so only one doping and direction), - either there must be the same number of each, or only one file of - one type, in which case it is used for all instances of the other. - - Changing the y-axis limits is also not currently supported (we - recommend changing the temperatures plotted instead). + precedence is lines represent doping > direction > files > + scattering type. If using multiple sets of files (so only one + doping and direction), either there must be the same number of + each, or only one file of one type, in which case it is used for + all instances of the other. """ if len(quantity) < 1 or len(quantity) > 4: @@ -1524,13 +1542,15 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, fig, ax, add_legend = axf[len(quantity) - 1](style) if len(quantity) == 4: ax = [ax[0][0], ax[0][1], ax[1][0], ax[1][1]] + elif len(quantity) == 1: + ax = [ax] edata = [] for f in transport_file: try: - edata.append(tp.data.load.amset(f)) + edata.append(tp.data.load.amset(f, quantity)) except UnicodeDecodeError: - edata.append(tp.data.load.boltztrap(f, doping=dtype)) + edata.append(tp.data.load.boltztrap(f, quantity, doping=dtype)) if ltc in quantity or tc in quantity: if len(kfile) != 0: kdata = [] @@ -1547,6 +1567,12 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, else: kdata = None + if stype in [None, [None], (None,)]: + if len(doping) > 1 or len(direction) > 1 or len(edata) > 1: + stype = ['Total'] + elif 'stype' in edata[0]: + stype = edata[0]['stype'] + for e in edata: e['doping'] = np.abs(e['doping']) @@ -1582,7 +1608,8 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, for d in doping: edata2 = deepcopy(edata[0]) edata2 = tp.data.utilities.resolve(edata2, q, doping=d, - direction=direction[0]) + direction=direction[0], + stype=stype[0]) dopelist.append('{:.2e}'.format(edata2['meta']['doping'])) data[i].append({'temperature': edata2['temperature'], q: edata2[q]}) @@ -1617,7 +1644,8 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, edata2 = deepcopy(edata[0]) edata2 = tp.data.utilities.resolve(edata2, q, doping=doping[0], - direction=d) + direction=d, + stype=stype[0]) data[i].append({'temperature': edata2['temperature'], q: edata2[q]}) elif q in kdata[0] and 'temperature' in kdata[0]['meta']['dimensions'][q]: @@ -1690,13 +1718,27 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, elif defleg['title'] is None: defleg['title'] = 'Electronic Data' defleg['labels'] = transport_file - for j in range(len(edata)): - edata2 = deepcopy(edata[j]) - edata2 = tp.data.utilities.resolve(edata2, q, - doping=doping[0], - direction=direction[0]) - data[i].append({'temperature': edata2['temperature'], - q: edata2[q]}) + if len(edata) > 1 or len(stype) == 1: + for j in range(len(edata)): + edata2 = deepcopy(edata[j]) + edata2 = tp.data.utilities.resolve(edata2, q, + doping=doping[0], + direction=direction[0], + stype=stype[0]) + data[i].append({'temperature': edata2['temperature'], + q: edata2[q]}) + else: + lendata = len(stype) + defleg['title'] = 'Scattering Type' + defleg['labels'] = stype + for j in range(len(stype)): + edata2 = deepcopy(edata[0]) + edata2 = tp.data.utilities.resolve(edata2, q, + doping=doping[0], + direction=direction[0], + stype=stype[j]) + data[i].append({'temperature': edata2['temperature'], + q: edata2[q]}) elif q in kdata[0] and 'temperature' in kdata[0]['meta']['dimensions'][q]: if len(kdata) > 1: lendata = len(kdata) @@ -1744,7 +1786,6 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, d2['temperature'] = np.array(d2['temperature']) k = np.where((d2['temperature'] <= tmax) & (d2['temperature'] >= tmin))[0] - ax[i].plot(d2['temperature'][k], d2[quantity[i]][k], linestyle=linestyle[j], marker=marker[j], c=colours[j], label=label[j]) @@ -1762,22 +1803,32 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, else: add_legend(title=legend_title, location=location) - for a in ax: - if xmin is not None: - if xmax is not None: - a.set_xlim(xmin, xmax) - else: - a.set_xlim(left=xmin) - elif xmax is not None: - a.set_xlim(right=xmax) - - #if ymin is not None: - # if ymax is not None: - # ax.set_ylim(ymin, ymax) - # else: - # ax.set_ylim(bottom=ymin) - #elif ymax is not None: - # ax.set_ylim(top=ymax) + lims = {'xmin': list(xmin), + 'xmax': list(xmax), + 'ymin': list(ymin), + 'ymax': list(ymax), + 'xscale': list(xscale), + 'yscale': list(yscale)} + for l in lims: + if lims[l] not in [None, [None], (None,), (), []]: + if len(lims[l]) > len(ax): + lims[l] = lims[l][:len(ax)] + while len(lims[l]) < len(ax): + lims[l].append(lims[l][-1]) + else: + lims[l] = None + + for i, a in enumerate(ax): + if lims['xmin'] is not None: + a.set_xlim(left=lims['xmin'][i]) + if lims['xmax'] is not None: + a.set_xlim(right=lims['xmax'][i]) + if lims['ymin'] is not None: + a.set_ylim(bottom=lims['ymin'][i]) + if lims['ymax'] is not None: + a.set_ylim(top=lims['ymax'][i]) + tp.plot.utilities.set_locators(a, x=lims['xscale'][i], + y=lims['yscale'][i]) if save: for ext in extension: @@ -1808,7 +1859,7 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, 'frequency, kappa, group_velocity, lifetime, ' 'mean_free_path, occupation and ph_ph_strength.') -@direction_option +@direction_function() @temperature_option @click.option('-c', '--colour', @@ -1850,8 +1901,7 @@ def transport(transport_file, kfile, quantity, direction, tmin, tmax, dtype, @click.option('--cscale', help='Override colour-scale if projected.', type=click.Choice(['linear', 'log'], case_sensitive=False)) -@xy_limit_options -@c_limit_options +@axes_limit_function(c=True) @plot_io_function('tp-waterfall') @verbose_option @@ -2010,7 +2060,7 @@ def wideband(band_yaml, kappa_hdf5, temperature, poscar, colour, smoothing, styl 'otherwise unspecified, set to 1 (W m-1 K-1).', type=click.Path(file_okay=True, dir_okay=False)) -@direction_option +@direction_function() @doping_type_option @interpolate_options @@ -2022,8 +2072,7 @@ def wideband(band_yaml, kappa_hdf5, temperature, poscar, colour, smoothing, styl default=['viridis'], show_default=True) -@xy_limit_options -@c_limit_options +@axes_limit_function(c=True) @plot_io_function('tp-ztmap') def ztmap(transport_file, pf, kappa, direction, dtype, interpolate, kind, colour, @@ -2081,7 +2130,7 @@ def ztmap(transport_file, pf, kappa, direction, dtype, interpolate, kind, colour type=click.Path(file_okay=True, dir_okay=False), nargs=2) -@direction_option +@direction_function() @doping_type_option @interpolate_options @@ -2097,8 +2146,7 @@ def ztmap(transport_file, pf, kappa, direction, dtype, interpolate, kind, colour default='white', show_default=True) -@xy_limit_options -@c_limit_options +@axes_limit_function(c=True) @legend_function() @plot_io_function('tp-ztdiff') diff --git a/tp/cli/options.py b/tp/cli/options.py index 8c27c9e..87ce48e 100644 --- a/tp/cli/options.py +++ b/tp/cli/options.py @@ -3,11 +3,9 @@ Functions --------- - direction_option - directions_option + direction_function doping_type_option - doping_option - dopings_option + doping_function dos_function input_argument inputs_function @@ -19,42 +17,29 @@ plot_io_function temperature_option verbose_option - xy_limit_options - c_limit_options + axes_limit_function """ import click -def direction_option(f): - """Option for singular option for anisotropic data.""" - - f = click.option('-d', '--direction', - help='Direction(s) for anisotropic data.', - type=click.Choice(['a', 'b', 'c', - 'x', 'y', 'z', - 'average', 'avg', - 'normal', 'norm'], - case_sensitive=False), - default='avg', - show_default=True)(f) - - return f - -def directions_option(f): - """Option for multiple directions for anisotropic data.""" - - f = click.option('-d', '--direction', - help='Direction(s) for anisotropic data.', - multiple=True, - type=click.Choice(['a', 'b', 'c', - 'x', 'y', 'z', - 'average', 'avg', - 'normal', 'norm'], - case_sensitive=False), - default=['avg'], - show_default=True)(f) - - return f +def direction_function(multiple=False): + default = ['avg'] if multiple else 'avg' + def direction_option(f): + """Option for anisotropic data.""" + + f = click.option('-d', '--direction', + help='Direction(s) for anisotropic data.', + type=click.Choice(['a', 'b', 'c', + 'x', 'y', 'z', + 'average', 'avg', + 'normal', 'norm'], + case_sensitive=False), + multiple=multiple, + default=default, + show_default=True)(f) + + return f + return direction_option def doping_type_option(f): """Option for doping type.""" @@ -67,28 +52,20 @@ def doping_type_option(f): return f -def doping_option(f): - """Option for a doping concentration.""" - - f = click.option('-n', '--concentration', 'doping', - help='Doping concentration (will be rounded).', - default=1.e19, - type=float, - show_default=True)(f) - - return f - -def dopings_option(f): - """Option for doping concentrations.""" - - f = click.option('-n', '--concentration', 'doping', - help='Doping concentration(s) (will be rounded).', - multiple=True, - default=[1.e19], - type=float, - show_default=True)(f) - - return f +def doping_function(multiple=False): + default = [1e19] if multiple else 1e19 + def doping_option(f): + """Option for doping concentration.""" + + f = click.option('-n', '--concentration', 'doping', + help='Doping concentration(s) (will be rounded).', + multiple=multiple, + default=default, + type=float, + show_default=True)(f) + + return f + return doping_option def dos_function(dosargs=['-c', '--colour']): if isinstance(dosargs, str): @@ -306,32 +283,35 @@ def verbose_option(f): return f -def xy_limit_options(f): - """Options for x and y axes limits.""" - - f = click.option('--xmin', - help='Override minimum x.', - type=float)(f) - f = click.option('--xmax', - help='Override maximum x.', - type=float)(f) - f = click.option('--ymin', - help='Override minimum y.', - type=float)(f) - f = click.option('--ymax', - help='Override maximum y.', - type=float)(f) - - return f - -def c_limit_options(f): - """Options for colour axes limits.""" - - f = click.option('--cmin', - help='Override minimum colour value.', - type=float)(f) - f = click.option('--cmax', - help='Override maximum colour value.', - type=float)(f) - - return f +def axes_limit_function(multiple=False, c=False): + def axes_limit_options(f): + """Options for axes limits.""" + + f = click.option('--xmin', + help='Override minimum x.', + multiple=multiple, + type=float)(f) + f = click.option('--xmax', + help='Override maximum x.', + multiple=multiple, + type=float)(f) + f = click.option('--ymin', + help='Override minimum y.', + multiple=multiple, + type=float)(f) + f = click.option('--ymax', + help='Override maximum y.', + multiple=multiple, + type=float)(f) + if c: + f = click.option('--cmin', + help='Override minimum colour value.', + multiple=multiple, + type=float)(f) + f = click.option('--cmax', + help='Override maximum colour value.', + multiple=multiple, + type=float)(f) + return f + return axes_limit_options + \ No newline at end of file diff --git a/tp/plot/phonons.py b/tp/plot/phonons.py index a42538d..dbaf326 100644 --- a/tp/plot/phonons.py +++ b/tp/plot/phonons.py @@ -307,7 +307,7 @@ def add_multi(ax, data, bandmin=None, bandmax=None, main=True, label=None, else: colours = colour - if label is None: + if label is None or label == [None]: label = np.full(len(data), None) if isinstance(linestyle, str) or len(linestyle) == 1: