Skip to content

Commit

Permalink
Code clean-up, CI update and add custom matplotlib stylesheet (#24)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
zhubonan authored Jun 28, 2023
1 parent 93e8a8e commit e0c113b
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 102 deletions.
20 changes: 19 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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: |
Expand Down
24 changes: 12 additions & 12 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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_]*))$
Expand All @@ -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_]*)|(__.*__))$
Expand All @@ -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_]*))$
Expand All @@ -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]+))$
Expand All @@ -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_]*))$
Expand Down Expand Up @@ -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.
Expand Down
52 changes: 28 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
<!-- when JOSS submitted, add link to paper (discussion of theory) here! -->
<!--- When JOSS submitted, add 'License and Citation' section here, and `CITATION.cff` file --->
Expand Down Expand Up @@ -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:

Expand All @@ -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!
Expand All @@ -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)
18 changes: 16 additions & 2 deletions docs/examples/example_si222.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -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.
```
```

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.
:::
10 changes: 10 additions & 0 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,16 @@ BuPu `cmap` | viridis `cmap` |
:-------------------------:|:-------------------------------------------------------:|:-------------------------:
![](../examples/NaBiS2/NaBiS2_unfold-plot_BuPu.png) | ![](../examples/NaBiS2/NaBiS2_unfold-plot_viridis.png) | <img src="../examples/NaBiS2/NaBiS2_unfold-plot_proj.png" alt="atom-projected NaBiS2 band structure" width="1200"/>

:::{tip}
Figure can be further customised by passing a path to a matplotlib style sheet file, for example:

```
easyunfold unfold --mpl-style-file <path-to-mpl-style-sheet> 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
24 changes: 18 additions & 6 deletions easyunfold/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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')
Expand Down Expand Up @@ -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


Expand Down Expand Up @@ -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')
Expand All @@ -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.
"""
Expand Down Expand Up @@ -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:
Expand All @@ -415,6 +425,7 @@ def _unfold_plot(ctx,
title,
width,
height,
dpi,
ax=None):
"""
Routine for plotting the spectral function.
Expand Down Expand Up @@ -466,6 +477,7 @@ def _unfold_plot(ctx,
vscale=vscale,
cmap=cmap,
title=title,
dpi=dpi,
ax=ax)

if out_file:
Expand Down
Loading

0 comments on commit e0c113b

Please sign in to comment.