Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/dev' into moire
Browse files Browse the repository at this point in the history
  • Loading branch information
sezelt committed Oct 16, 2023
2 parents c7ad07e + e8305e7 commit 4cf1e30
Show file tree
Hide file tree
Showing 34 changed files with 786 additions and 149 deletions.
1 change: 0 additions & 1 deletion .github/scripts/update_version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""
Script to update the patch version number of the py4DSTEM package.
Author: Tara Mishra (Quantumstud)
"""

version_file_path = "py4DSTEM/version.py"
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/check_install_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ jobs:
runs-on: [ubuntu-latest]
architecture: [x86_64]
python-version: ["3.9", "3.10", "3.11",]
# include:
# - python-version: "3.12.0-beta.4"
# runs-on: ubuntu-latest
# allow_failure: true
# Currently no public runners available for this but this or arm64 should work next time
# include:
# - python-version: "3.10"
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/check_install_main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ jobs:
runs-on: [ubuntu-latest, windows-latest, macos-latest]
architecture: [x86_64]
python-version: ["3.9", "3.10", "3.11",]
include:
- python-version: "3.12.0-beta.4"
runs-on: ubuntu-latest
allow_failure: true
#include:
# - python-version: "3.12.0-beta.4"
# runs-on: ubuntu-latest
# allow_failure: true
# Currently no public runners available for this but this or arm64 should work next time
# include:
# - python-version: "3.10"
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/pypi_upload.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Action to check the version of the package and upload it to PyPI
# if the version is higher than the one on PyPI
# Author: @quantumstud
name: PyPI Upload

on:
Expand All @@ -22,10 +21,15 @@ jobs:
token: ${{ secrets.GH_ACTION_VERSION_UPDATE }}
- name: Get changed files
id: changed-files-specific
uses: tj-actions/changed-files@v32
uses: tj-actions/changed-files@v39
with:
files: |
py4DSTEM/version.py
- name: Debug version file change checker
run: |
echo "Checking variable..."
echo ${{ steps.changed-files-specific.outputs.any_changed }}
echo "Done"
- name: Running if py4DSTEM/version.py file is not changed
if: steps.changed-files-specific.outputs.any_changed == 'false'
run: |
Expand Down
30 changes: 19 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,42 +46,50 @@ First, download and install Anaconda: www.anaconda.com/download.
If you prefer a more lightweight conda client, you can instead install Miniconda: https://docs.conda.io/en/latest/miniconda.html.
Then open a conda terminal and run one of the following sets of commands to ensure everything is up-to-date and create a new environment for your py4DSTEM installation:


```
conda update conda
conda create -n py4dstem
conda activate py4dstem
conda install -c conda-forge py4dstem pymatgen jupyterlab
```

Next, install py4DSTEM. To simultaneously install py4DSTEM with `pymatgen` (used in some crystal structure workflows) and `jupyterlab` (providing an interface for running Python notebooks like those provided in the [py4DSTEM tutorials repository](https://github.com/py4dstem/py4DSTEM_tutorials)) run:
In order, these commands
- ensure your installation of anaconda is up-to-date
- make a virtual environment (see below)
- enter the environment
- install py4DSTEM, as well as pymatgen (used for crystal structure calculations) and JupyterLab (an interface for running Python notebooks like those in the [py4DSTEM tutorials repository](https://github.com/py4dstem/py4DSTEM_tutorials))


We've had some recent reports install of `conda` getting stuck trying to solve the environment using the above installation. If you run into this problem, you can install py4DSTEM using `pip` instead of `conda` by running:

```
conda install -c conda-forge py4dstem pymatgen jupyterlab
conda update conda
conda create -n py4dstem python=3.10
conda activate py4dstem
pip install py4dstem pymatgen
```

Or if you would prefer to install only the base modules of **py4DSTEM**, you can instead run:
Both `conda` and `pip` are programs which manage package installations, i.e. make sure different codes you're installing which depend on one another are using mutually compatible versions. Each has advantages and disadvantages; `pip` is a little more bare-bones, and we've seen this install work when `conda` doesn't. If you also want to use Jupyterlab you can then use either `pip install jupyterlab` or `conda install jupyterlab`.

If you would prefer to install only the base modules of **py4DSTEM**, and skip pymategen and Jupterlab, you can instead run:

```
conda install -c conda-forge py4dstem
```

In Windows you should then also run:
Finally, regardless of which of the above approaches you used, in Windows you should then also run:

```
conda install pywin32
```

In order, these commands
- ensure your installation of anaconda is up-to-date
- make a virtual environment (see below)
- enter the environment
- install py4DSTEM, and optionally also pymatgen and JupyterLab
- on Windows, enable python to talk to the windows API
which enables Python to talk to the Windows API.

Please note that virtual environments are used in the instructions above in order to make sure packages that have different dependencies don't conflict with one another.
Because these directions install py4DSTEM to its own virtual environment, each time you want to use py4DSTEM you'll need to activate this environment.
You can do this in the command line by running `conda activate py4dstem`, or, if you're using the Anaconda Navigator, by clicking on the Environments tab and then clicking on `py4dstem`.

Last - as of the version 0.14.4 update, we've had a few reports of problems upgrading to the newest version. We're not sure what's causing the issue yet, but have found the new version can be installed successfully in these cases using a fresh Anaconda installation.


<a id='legacyinstall'></a>
Expand Down
3 changes: 2 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
emdfile
# py4dstem
sphinx_rtd_theme
# py4dstem
7 changes: 6 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon", "sphinx.ext.intersphinx"]
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
"sphinx.ext.intersphinx",
"sphinx_rtd_theme",
]

# Other useful extensions
# sphinx_copybutton
Expand Down
7 changes: 5 additions & 2 deletions py4DSTEM/braggvectors/braggvector_methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ def measure_origin(
return qx0, qy0, mask

def measure_origin_beamstop(
self, center_guess, radii, max_dist=2, max_iter=1, **kwargs
self, center_guess, radii, max_dist=None, max_iter=1, **kwargs
):
"""
Find the origin from a set of braggpeaks assuming there is a beamstop, by identifying
Expand All @@ -440,6 +440,9 @@ def measure_origin_beamstop(
R_Nx, R_Ny = self.Rshape
braggpeaks = self._v_uncal

if max_dist is None:
max_dist = radii[1]

# remove peaks outside the annulus
braggpeaks_masked = braggpeaks.copy()
for rx in range(R_Nx):
Expand Down Expand Up @@ -470,7 +473,7 @@ def measure_origin_beamstop(
x_r = -x + 2 * center_curr[0]
y_r = -y + 2 * center_curr[1]
dists = np.hypot(x_r - pl.data["qx"], y_r - pl.data["qy"])
dists[is_paired] = 2 * max_dist
dists[is_paired] = max_dist
matched = dists <= max_dist
if any(matched):
match = np.argmin(dists)
Expand Down
8 changes: 8 additions & 0 deletions py4DSTEM/braggvectors/diskdetection.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,8 @@ def _find_Bragg_disks_CUDA_unbatched(
# Populate a BraggVectors instance and return
braggvectors = BraggVectors(datacube.Rshape, datacube.Qshape)
braggvectors._v_uncal = peaks
braggvectors._set_raw_vector_getter()
braggvectors._set_cal_vector_getter()
return braggvectors


Expand Down Expand Up @@ -600,6 +602,8 @@ def _find_Bragg_disks_CUDA_batched(
# Populate a BraggVectors instance and return
braggvectors = BraggVectors(datacube.Rshape, datacube.Qshape)
braggvectors._v_uncal = peaks
braggvectors._set_raw_vector_getter()
braggvectors._set_cal_vector_getter()
return braggvectors


Expand Down Expand Up @@ -650,6 +654,8 @@ def _find_Bragg_disks_ipp(
# Populate a BraggVectors instance and return
braggvectors = BraggVectors(datacube.Rshape, datacube.Qshape)
braggvectors._v_uncal = peaks
braggvectors._set_raw_vector_getter()
braggvectors._set_cal_vector_getter()
return braggvectors


Expand Down Expand Up @@ -700,6 +706,8 @@ def _find_Bragg_disks_dask(
# Populate a BraggVectors instance and return
braggvectors = BraggVectors(datacube.Rshape, datacube.Qshape)
braggvectors._v_uncal = peaks
braggvectors._set_raw_vector_getter()
braggvectors._set_cal_vector_getter()
return braggvectors


Expand Down
4 changes: 2 additions & 2 deletions py4DSTEM/braggvectors/diskdetection_aiml_cuda.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@

try:
import cupy as cp
except:
raise ImportError("Import Error: Please install cupy before proceeding")
except ModuleNotFoundError:
raise ImportError("AIML CUDA Requires cupy")

try:
import tensorflow as tf
Expand Down
112 changes: 64 additions & 48 deletions py4DSTEM/datacube/virtualdiffraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
# * DataCubeVirtualDiffraction - methods inherited by DataCube for virt diffraction

import numpy as np
import dask.array as da
from typing import Optional
import inspect

from emdfile import tqdmnd, Metadata
from py4DSTEM.data import Calibration, DiffractionSlice, Data
from py4DSTEM.visualize.show import show
from py4DSTEM.data import DiffractionSlice, Data
from py4DSTEM.preprocess import get_shifted_ar

# Virtual diffraction container class

Expand Down Expand Up @@ -184,22 +183,33 @@ def get_virtual_diffraction(
qx_shift = x0_mean - x0
qy_shift = y0_mean - y0

# ...for integer shifts
if not subpixel:
if subpixel is False:
# round shifts -> int
qx_shift = qx_shift.round().astype(int)
qy_shift = qy_shift.round().astype(int)

# ...for boolean masks and unmasked
if mask is None or mask.dtype == bool:
# get scan points
mask = np.ones(self.Rshape, dtype=bool) if mask is None else mask
mask_indices = np.nonzero(mask)
# allocate space
virtual_diffraction = np.zeros(self.Qshape)
# loop
for rx, ry in zip(mask_indices[0], mask_indices[1]):
# get shifted DP
# ...for boolean masks and unmasked
if mask is None or mask.dtype == bool:
# get scan points
mask = np.ones(self.Rshape, dtype=bool) if mask is None else mask
mask_indices = np.nonzero(mask)
# allocate space
virtual_diffraction = np.zeros(self.Qshape)
# loop
for rx, ry in zip(mask_indices[0], mask_indices[1]):
# get shifted DP
if subpixel:
DP = get_shifted_ar(
self.data[
rx,
ry,
:,
:,
],
qx_shift[rx, ry],
qy_shift[rx, ry],
)
else:
DP = np.roll(
self.data[
rx,
Expand All @@ -210,29 +220,41 @@ def get_virtual_diffraction(
(qx_shift[rx, ry], qy_shift[rx, ry]),
axis=(0, 1),
)
# compute
if method == "mean":
virtual_diffraction += DP
elif method == "max":
virtual_diffraction = np.maximum(virtual_diffraction, DP)
# normalize means
# compute
if method == "mean":
virtual_diffraction /= len(mask_indices[0])
virtual_diffraction += DP
elif method == "max":
virtual_diffraction = np.maximum(virtual_diffraction, DP)
# normalize means
if method == "mean":
virtual_diffraction /= len(mask_indices[0])

# ...for floating point and complex masks
# ...for floating point and complex masks
else:
# allocate space
if mask.dtype == "complex":
virtual_diffraction = np.zeros(self.Qshape, dtype="complex")
else:
# allocate space
if mask.dtype == "complex":
virtual_diffraction = np.zeros(self.Qshape, dtype="complex")
virtual_diffraction = np.zeros(self.Qshape)
# loop
for rx, ry in tqdmnd(
self.R_Nx,
self.R_Ny,
disable=not verbose,
):
# get shifted DP
if subpixel:
DP = get_shifted_ar(
self.data[
rx,
ry,
:,
:,
],
qx_shift[rx, ry],
qy_shift[rx, ry],
)
else:
virtual_diffraction = np.zeros(self.Qshape)
# loop
for rx, ry in tqdmnd(
self.R_Nx,
self.R_Ny,
disable=not verbose,
):
# get shifted DP
DP = np.roll(
self.data[
rx,
Expand All @@ -243,21 +265,15 @@ def get_virtual_diffraction(
(qx_shift[rx, ry], qy_shift[rx, ry]),
axis=(0, 1),
)
# compute
w = mask[rx, ry]
if method == "mean":
virtual_diffraction += DP * w
elif method == "max":
virtual_diffraction = np.maximum(
virtual_diffraction, DP * w
)
if method == "mean":
virtual_diffraction /= np.sum(mask)

# TODO subpixel shifting
else:
raise Exception("subpixel shifting has not been implemented yet!")
pass
# compute
w = mask[rx, ry]
if method == "mean":
virtual_diffraction += DP * w
elif method == "max":
virtual_diffraction = np.maximum(virtual_diffraction, DP * w)
if method == "mean":
virtual_diffraction /= np.sum(mask)

# wrap, add to tree, and return

Expand Down
Loading

0 comments on commit 4cf1e30

Please sign in to comment.