From e0c113b8930402ab52684ffa39b2f21c29a149ad Mon Sep 17 00:00:00 2001 From: Bonan Zhu <33688599+zhubonan@users.noreply.github.com> Date: Wed, 28 Jun 2023 13:14:05 +0100 Subject: [PATCH] Code clean-up, CI update and add custom matplotlib stylesheet (#24) * Clean up code and add pre-commit CI action * README.md update * Added option to use custom mpl style sheet * Update pylintrc * Update pylintrc * Clarify the `--no-expand` option --- .github/workflows/ci.yaml | 20 +++++++- .pylintrc | 24 ++++----- README.md | 52 +++++++++++--------- docs/examples/example_si222.md | 18 ++++++- docs/tutorial.md | 10 ++++ easyunfold/cli.py | 24 ++++++--- easyunfold/plotting.py | 68 +++++++++++++------------- easyunfold/procar.py | 3 +- easyunfold/unfold.py | 21 -------- pyproject.toml | 1 + tests/test_cli.py | 6 +++ tests/test_data/Si-project/my.mplstyle | 1 + 12 files changed, 146 insertions(+), 102 deletions(-) create mode 100644 tests/test_data/Si-project/my.mplstyle diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index ce66a4c..3136a78 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,6 +6,25 @@ name: Python package on: [push, pull_request] jobs: + + pre-commit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: "3.9" + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ".[pre-commit]" + + - name: Run pre-commit + run: "pre-commit run --all" + build: runs-on: ubuntu-latest @@ -23,7 +42,6 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install git+https://github.com/zhubonan/castepxbin.git@pr-checkfile pip install ".[test]" - name: Test with pytest run: | diff --git a/.pylintrc b/.pylintrc index 1cfab67..5f9f31b 100644 --- a/.pylintrc +++ b/.pylintrc @@ -50,7 +50,7 @@ confidence= # --enable=similarities". If you want to run only the classes checker, but have # no Warning level messages displayed, use"--disable=all --enable=classes # --disable=W" -disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,fixme +# disable=import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,fixme # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option @@ -93,13 +93,13 @@ max-nested-blocks=5 [BASIC] # Naming hint for argument names -argument-name-hint=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ +#argument-name-hint=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ # Regular expression matching correct argument names argument-rgx=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ # Naming hint for attribute names -attr-name-hint=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ +#attr-name-hint=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ # Regular expression matching correct attribute names attr-rgx=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ @@ -108,19 +108,19 @@ attr-rgx=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ bad-names=foo,bar,baz,toto,tutu,tata # Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$ +#class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$ # Regular expression matching correct class attribute names class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{1,30}|(__.*__))$ # Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ +#class-name-hint=[A-Z_][a-zA-Z0-9]+$ # Regular expression matching correct class names class-rgx=[A-Z_][a-zA-Z0-9]+$ # Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ +#const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression matching correct constant names const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ @@ -130,7 +130,7 @@ const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ docstring-min-length=6 # Naming hint for function names -function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ +# function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ # Regular expression matching correct function names function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ @@ -142,19 +142,19 @@ good-names=x,y,z,X,Y,Z,tmp,ax,i,j,k,ex,Run,_, _INPUT_FILE_NAME, _OUTPUT_FILE_NAM include-naming-hint=no # Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ +#inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Naming hint for method names -method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ +#method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$ # Regular expression matching correct method names method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*)|(setUp)|(tearDown))$ # Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ +#module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression matching correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ @@ -172,7 +172,7 @@ no-docstring-rgx=^_,setUp,tearDown property-classes=abc.abstractproperty # Naming hint for variable names -variable-name-hint=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ +#variable-name-hint=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ # Regular expression matching correct variable names variable-rgx=(([a-z][a-z0-9_]{1,30})|(_[a-z0-9_]*))$ @@ -203,7 +203,7 @@ max-module-lines=4000 # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. -no-space-check=trailing-comma,dict-separator +# no-space-check=trailing-comma,dict-separator # Allow the body of a class to be on the same line as the declaration if body # contains single statement. diff --git a/README.md b/README.md index 97e18a7..1800485 100644 --- a/README.md +++ b/README.md @@ -9,41 +9,41 @@ svg)](https://doi.org/10.21105/joss.)---> [![easyunfold](docs/img/logo.svg)](https://smtg-ucl.github.io/easyunfold/) `Easyunfold` is intended for obtaining the effective band structure of a supercell for a certain _k_-point -path of the primitive cell. It was originally based on -[PyVaspwfc](https://github.com/QijingZheng/VaspBandUnfolding) for reading VASP wavefunction outputs, -with a notable improvement being that symmetry-breaking is properly accounted for by sampling necessary -additional _k_-points and averaging accordingly. Documentation site +path of the primitive cell. It was originally based on +[PyVaspwfc](https://github.com/QijingZheng/VaspBandUnfolding) for reading VASP wavefunction outputs, +with a notable improvement being that symmetry-breaking is properly accounted for by sampling necessary +additional _k_-points and averaging accordingly. Documentation site [here](https://smtg-ucl.github.io/easyunfold/)! -Our goal is to implement the band structure unfolding workflow in a robust and user-friendly software +Our goal is to implement the band structure unfolding workflow in a robust and user-friendly software package. -For the methodology of supercell band unfolding, see +For the methodology of supercell band unfolding, see [here](https://link.aps.org/doi/10.1103/PhysRevB.85.085201). ## Usage To generate an unfolded band structure, one typically needs to perform the following steps: -1. Create a primitive unit cell, and generate a band structure _k_-point path corresponding to this +1. Create a primitive unit cell, and generate a band structure _k_-point path corresponding to this primitive cell. 2. Create a supercell (e.g. disordered, defective, surface slab etc.), and obtain its optimised structure. 3. Generate a series of _k_-points for the supercell to be calculated. 4. Perform a band structure calculation with the supercell, and save its wavefunction output to file. -5. Post-process the supercell wavefunction to obtain the unfolded band structure in the _k_-point path +5. Post-process the supercell wavefunction to obtain the unfolded band structure in the _k_-point path of the primitive unit cell. -These generation and analysis steps are automated in `easyunfold`, with only the primitive unit cell and +These generation and analysis steps are automated in `easyunfold`, with only the primitive unit cell and supercell structures required as inputs from the user. -Typically, the supercell comprises some form of symmetry-breaking relative to the primitive cell, such -as defects, disorder (e.g. special quasi-random structures (SQS) for site disorder – other forms of -disorder such as magnetic, dynamic/vibrational, polar, elastic etc. also possible), or a surface/interface +Typically, the supercell comprises some form of symmetry-breaking relative to the primitive cell, such +as defects, disorder (e.g. special quasi-random structures (SQS) for site disorder – other forms of +disorder such as magnetic, dynamic/vibrational, polar, elastic etc. also possible), or a surface/interface slab. In all cases, the supercell symmetry is lowered compared to the pristine primitive cell. -Hence, for a given _k_-point path in the primitive cell Brillouin Zone, additional _k_-points are -required to be sampled for the supercell, and the extracted spectral weights need to be appropriately -averaged to obtain the correct effective band structure (EBS). See the docs +Hence, for a given _k_-point path in the primitive cell Brillouin Zone, additional _k_-points are +required to be sampled for the supercell, and the extracted spectral weights need to be appropriately +averaged to obtain the correct effective band structure (EBS). See the docs [Theory](https://smtg-ucl.github.io/easyunfold/theory.html) page for more details. @@ -78,7 +78,8 @@ Commands: ``` ### Developer Installation (from source) -A recent version of `pip` is needed to do this, due to the new style of the `pyproject.toml` configuration + +A recent version of `pip` is needed to do this, due to the new style of the `pyproject.toml` configuration file. To upgrade your `pip`, do: @@ -89,9 +90,12 @@ pip install -U pip Assuming the package is in the `easyunfold` folder, use the following command to install: ``` -pip install ./easyunfold +pip install "./easyunfold[test,doc,pre-commit]" ``` +which also installs additional dependencies for building documentation (`doc`), running tests (`test`) and +dependencies for using pre-commit hooks (`pre-commit`). + ## Studies using `easyunfold` We'll add papers that use `easyunfold` to this list as they come out! @@ -108,21 +112,21 @@ In principle, support for other plane wave DFT code can be added by: - Implementing a subclass of `WaveFunction` that handles reading the wave function output. - Implementing functions for reading/writing _k_-points. -- Adding branches for dispatching based on the `dft_code` attribute of the `UnfoldKSet` object in +- Adding branches for dispatching based on the `dft_code` attribute of the `UnfoldKSet` object in various places within the code. -The Atomic Simulation Environment ([ASE](https://wiki.fysik.dtu.dk/ase/)) is used by `easyunfold` for +The Atomic Simulation Environment ([ASE](https://wiki.fysik.dtu.dk/ase/)) is used by `easyunfold` for reading in structures, so structure file IO is natively supported for essentially all public DFT codes. ### Code Compatibility Notes - Atom-projected band structures are currently only supported for `VASP` calculation outputs. -- Gamma-only and non-collinear spin calculations are not supported for `CASTEP`. +- Gamma-only and non-collinear spin calculations are not supported for `CASTEP`. ## Contributors -- [Bonan Zhu](https://github.com/zhubonan) -- [Seán Kavanagh](https://github.com/kavanase) -- [Adair Nicolson](https://github.com/adair-nicolson) +- [Bonan Zhu](https://github.com/zhubonan) +- [Seán Kavanagh](https://github.com/kavanase) +- [Adair Nicolson](https://github.com/adair-nicolson) And those who helped in the development: -- [Joe Willis](https://github.com/joebesity) +- [Joe Willis](https://github.com/joebesity) - [David O. Scanlon](http://davidscanlon.com/?page_id=5) diff --git a/docs/examples/example_si222.md b/docs/examples/example_si222.md index c120aff..9f28dfe 100644 --- a/docs/examples/example_si222.md +++ b/docs/examples/example_si222.md @@ -137,6 +137,11 @@ Primitive cell band structure of Si. ## What happens if symmetry is not properly taken into account? +It is quite common that the supercell has lower symmetry compared to the primitive cell. +By default, `easyunfold` takes account of such symmetry breaking effect by including +additional _k_-points that no longer equivalent under the symmetry of the supercell cell. + +In this example, we show what happens if we **do not** include the additional kpoints. We can create a new unfolding project (`json` data file) using the following command: ```bash @@ -189,7 +194,7 @@ Primitive cell information: Point group: m-3m No. of k points in the primitive cell : 73 -No. of (non-symmetry-reduced) supercell kpoints : 70 (73) +No. of supercell kpoints : 70 No. of primitive cell symmetry operations : 48 No. of supercell symmetry operations : 6 @@ -200,4 +205,13 @@ Path in the primitive cell: X : 50 \Gamma : 73 Unfolding had been performed - use `unfold plot` to plot the spectral function. -``` \ No newline at end of file +``` + +Note that in most cases one would always want to include the additional kpoints to correctly capture the effect of symmetry breaking. +The `--no-expand` option should be used with care and **only when there is no alternative**, +for example, +when the expansion gives too many kpoints for very large supercells of special quasi-random structures. + +:::{note} +One can always split the workload into multiple calculations with `--nk-per-split` to fit the computational resources available for individual calculations. +::: diff --git a/docs/tutorial.md b/docs/tutorial.md index c49f792..097e762 100644 --- a/docs/tutorial.md +++ b/docs/tutorial.md @@ -189,6 +189,16 @@ BuPu `cmap` | viridis `cmap` | :-------------------------:|:-------------------------------------------------------:|:-------------------------: ![](../examples/NaBiS2/NaBiS2_unfold-plot_BuPu.png) | ![](../examples/NaBiS2/NaBiS2_unfold-plot_viridis.png) | atom-projected NaBiS2 band structure +:::{tip} +Figure can be further customised by passing a path to a matplotlib style sheet file, for example: + +``` +easyunfold unfold --mpl-style-file plot +``` + +which can be used to change the font, font sizes, ticks styles etc. +Read more on [the matplotlib tutorial page](https://matplotlib.org/stable/tutorials/introductory/customizing.html#using-style-sheets). +::: [^vasp]: https://www.vasp.at [^castep]: http://www.castep.org \ No newline at end of file diff --git a/easyunfold/cli.py b/easyunfold/cli.py index bfc805b..0d7220b 100644 --- a/easyunfold/cli.py +++ b/easyunfold/cli.py @@ -18,7 +18,7 @@ 'BuGn', 'YlGn' ] -CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help']) +CONTEXT_SETTINGS = {'help_option_names': ['-h', '--help']} @click.group('easyunfold', context_settings=CONTEXT_SETTINGS) @@ -143,8 +143,13 @@ def generate(pc_file, code, sc_file, matrix, kpoints, time_reversal, out_file, n @easyunfold.group('unfold') @click.option('--data-file', default='easyunfold.json', type=click.Path(exists=True, file_okay=True, dir_okay=False), show_default=True) +@click.option('--mpl-style-file', + type=click.Path(exists=True, file_okay=True, dir_okay=False), + show_default=True, + required=False, + help='Use this file to customise the matplotlib style sheet') @click.pass_context -def unfold(ctx, data_file): +def unfold(ctx, data_file, mpl_style_file): """ Perform unfolding and plotting @@ -154,6 +159,10 @@ def unfold(ctx, data_file): unfoldset = loadfn(data_file) click.echo(f'Loaded data from {data_file}') ctx.obj = {'obj': unfoldset, 'fname': data_file} + if mpl_style_file: + click.echo(f'Using custom plotting style from {mpl_style_file}') + import matplotlib.style + matplotlib.style.use(mpl_style_file) @unfold.command('status') @@ -234,6 +243,7 @@ def add_plot_options(func): click.option('--title', help='Title to be used')(func) click.option('--width', help='Width of the figure', type=float, default=4., show_default=True)(func) click.option('--height', help='Height of the figure', type=float, default=3., show_default=True)(func) + click.option('--dpi', help='DPI for the figure when saved as raster image.', type=int, default=300, show_default=True)(func) return func @@ -341,14 +351,14 @@ def print_data(entries, tag='me'): @click.pass_context @add_plot_options def unfold_plot(ctx, gamma, npoints, sigma, eref, out_file, show, emin, emax, cmap, ncl, no_symm_average, vscale, procar, atoms_idx, - orbitals, title, width, height): + orbitals, title, width, height, dpi): """ Plot the spectral function This command uses the stored unfolding data to plot the effective bands structure (EBS) using the spectral function. """ _unfold_plot(ctx, gamma, npoints, sigma, eref, out_file, show, emin, emax, cmap, ncl, no_symm_average, vscale, procar, atoms_idx, - orbitals, title, width, height) + orbitals, title, width, height, dpi) @unfold.command('plot-projections') @@ -358,7 +368,7 @@ def unfold_plot(ctx, gamma, npoints, sigma, eref, out_file, show, emin, emax, cm @click.option('--intensity', default=1.0, help='Color intensity for combined plot', type=float, show_default=True) @click.option('--colors', help='Colors to be used for combined plot, comma separated.', default='r,g,b,purple', show_default=True) def unfold_plot_projections(ctx, gamma, npoints, sigma, eref, out_file, show, emin, emax, cmap, ncl, no_symm_average, vscale, procar, - atoms_idx, orbitals, title, combined, intensity, colors, width, height): + atoms_idx, orbitals, title, combined, intensity, colors, width, height, dpi): """ Plot the effective band structure with atomic projections. """ @@ -389,7 +399,7 @@ def unfold_plot_projections(ctx, gamma, npoints, sigma, eref, out_file, show, em colors=colors.split(',') if colors is not None else None) if out_file: - fig.savefig(out_file, dpi=300) + fig.savefig(out_file, dpi=dpi) click.echo(f'Unfolded band structure saved to {out_file}') if show: @@ -415,6 +425,7 @@ def _unfold_plot(ctx, title, width, height, + dpi, ax=None): """ Routine for plotting the spectral function. @@ -466,6 +477,7 @@ def _unfold_plot(ctx, vscale=vscale, cmap=cmap, title=title, + dpi=dpi, ax=ax) if out_file: diff --git a/easyunfold/plotting.py b/easyunfold/plotting.py index 484ac32..0152503 100644 --- a/easyunfold/plotting.py +++ b/easyunfold/plotting.py @@ -1,7 +1,7 @@ """ Plotting utilities """ -from typing import Union +from typing import Union, Sequence import matplotlib.pyplot as plt import numpy as np @@ -122,7 +122,7 @@ def plot_spectral_function( fig.tight_layout(pad=0.2) if save: - fig.savefig(save, dpi=300) + fig.savefig(save, dpi=dpi) if show: fig.show() return fig @@ -207,7 +207,7 @@ def _plot_spectral_function_rgba( fig.tight_layout(pad=0.2) if save: - fig.savefig(save, dpi=300) + fig.savefig(save, dpi=dpi) if show: fig.show() return fig @@ -395,39 +395,39 @@ def plot_spectral_weights( fig.tight_layout(pad=0.2) if save: - fig.savefig(save, dpi=300) + fig.savefig(save, dpi=dpi) if show: fig.show() return fig def plot_projected( - self, - procar: Union[str, list], - eref=None, - gamma=False, - npoints=2000, - sigma=0.2, - ncl=False, - symm_average=True, - figsize=(4, 3), - ylim=(-3, 3), - dpi=150, - vscale=1.0, - contour_plot=False, - alpha=1.0, - save=False, - ax=None, - vmin=None, - vmax=None, - cmap='PuRd', - show=False, - title=None, - atoms_idx=None, - orbitals=None, - intensity=1.0, - use_subplot=False, - colors=["r", "g", "b", "purple"], - colorspace='lab', + self, + procar: Union[str, list], + eref=None, + gamma=False, + npoints=2000, + sigma=0.2, + ncl=False, + symm_average=True, + figsize=(4, 3), + ylim=(-3, 3), + dpi=150, + vscale=1.0, + contour_plot=False, + alpha=1.0, + save=False, + ax=None, + vmin=None, + vmax=None, + cmap='PuRd', + show=False, + title=None, + atoms_idx=None, + orbitals=None, + intensity=1.0, + use_subplot=False, + colors=('r', 'g', 'b', 'purple'), + colorspace='lab', ): """ Plot projected spectral function onto multiple subplots or a single plot with color mapping. @@ -522,7 +522,7 @@ def plot_projected( stacked_sf = np.stack(all_sf, axis=-1).reshape(np.prod(sf_size), len(all_sf)) # Construct the color basis - colors = colors[0:len(all_sf)] + colors = colors[:len(all_sf)] # Compute spectral weight data with RGB reshape it back into the shape (nengs, nk, 3) sf_rgb = interpolate_colors(colors, stacked_sf, colorspace, normalize=True).reshape(sf_size + (3,)) sf_sum = np.sum(all_sf, axis=0)[:, :, :, None] @@ -584,7 +584,7 @@ def plot_effective_mass_fit(efm: EffectiveMass, return fig -def interpolate_colors(colors: list, weights: list, colorspace='lab', normalize=True): +def interpolate_colors(colors: Sequence, weights: list, colorspace='lab', normalize=True): """ Interpolate colors at a number of points within a colorspace. @@ -607,7 +607,7 @@ def interpolate_colors(colors: list, weights: list, colorspace='lab', normalize= 'xyz': XYZColor, } - if colorspace not in list(colorspace_mapping.keys()): + if colorspace not in colorspace_mapping: raise ValueError(f'colorspace must be one of {colorspace_mapping.keys()}') colorspace = colorspace_mapping[colorspace] diff --git a/easyunfold/procar.py b/easyunfold/procar.py index 1a01013..212b272 100644 --- a/easyunfold/procar.py +++ b/easyunfold/procar.py @@ -82,8 +82,7 @@ def _read(self, fobj): self.nspins = proj_data.shape[0] // (self.nion * self.nbands * self.nkpts) self.nspins //= 4 if self._is_soc else 1 - if self._is_soc: - self.spin = self.spin // 4 + # Reshape self.occs.resize((self.nspins, self.nkpts, self.nbands)) self.kvecs.resize((self.nspins, self.nkpts, 3)) diff --git a/easyunfold/unfold.py b/easyunfold/unfold.py index c38bc71..2acf0c8 100644 --- a/easyunfold/unfold.py +++ b/easyunfold/unfold.py @@ -289,7 +289,6 @@ def generate_sc_kpoints(self) -> None: # We now have bunch of supercell kpoints for each set of expanded kpoints # Try to find duplicated SC kpoints - # TODO: We can further reduce this by time-reversal symmetry here all_sc = np.array(all_sc) reduced_sckpts, _, sc_kpts_map = reduce_kpoints(all_sc, time_reversal=self.time_reversal) sc_kpts_map = list(sc_kpts_map) @@ -632,26 +631,6 @@ def GaussianSmearing(x, x0, sigma=0.02): return 1. / (np.sqrt(2 * np.pi) * sigma) * np.exp(-(x - x0)**2 / (2 * sigma**2)) -def remove_duplicated_kpoints(kpoints: list, return_map=False, decimals=6): - """ - remove duplicate kpoints in the list. - - TODO: improve this implementation by clipping the range of the fractional coorindates - """ - kpoints = np.asarray(kpoints) - _, kid, inv_kid = np.unique( - np.round(kpoints, decimals), - axis=0, - return_index=True, - return_inverse=True, - ) - reducedK = kpoints[kid] - - if return_map: - return reducedK, inv_kid - return reducedK - - def make_kpath(kbound: List[float], nseg=40): """ Return a list of kpoints defining the path between the given kpoints. diff --git a/pyproject.toml b/pyproject.toml index 5d9d6a1..05d4889 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,3 +31,4 @@ doc = [ "sphinx-copybutton>=0.3,<0.4", "myst-parser[linkify]", "sphinx>=6,<7" ] test = ["pytest", "pytest-cov", "coverage"] +pre-commit = ["pre-commit", "pylint~=2.11"] diff --git a/tests/test_cli.py b/tests/test_cli.py index cf7c328..cc8cfb8 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -67,6 +67,12 @@ def test_unfold(si_project_dir, tag): assert output.exit_code == 0 assert 'Please run the supercell' in output.stdout + # matplotlib customisation check + args_calc = ['unfold', '--data-file', 'test.json', '--mpl-style-file', 'my.mplstyle', 'status'] + output = runner.invoke(easyunfold, args_calc) + assert output.exit_code == 0 + assert 'Using custom plotting style' in output.stdout + # Perform the unfold args_calc = ['unfold', '--data-file', 'test.json', 'calculate', f'Si_super_deformed{tag}/WAVECAR'] if 'soc' in tag: diff --git a/tests/test_data/Si-project/my.mplstyle b/tests/test_data/Si-project/my.mplstyle new file mode 100644 index 0000000..932415f --- /dev/null +++ b/tests/test_data/Si-project/my.mplstyle @@ -0,0 +1 @@ +figure.dpi : 120