Skip to content

Commit

Permalink
merges with dev
Browse files Browse the repository at this point in the history
  • Loading branch information
bsavitzky committed Nov 9, 2023
2 parents eb0232d + ea1e7ed commit dc1773a
Show file tree
Hide file tree
Showing 51 changed files with 11,304 additions and 2,883 deletions.
2 changes: 1 addition & 1 deletion .github/scripts/update_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
lines = f.readlines()

line_split = lines[0].split(".")
patch_number = line_split[2].split("'")[0]
patch_number = line_split[2].split("'")[0].split('"')[0]

# Increment patch number
patch_number = str(int(patch_number) + 1) + "'"
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/check_install_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +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
# 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*.swp
*.ipynb_checkpoints*
.vscode/
pyrightconfig.json

# Folders #
.idea/
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
2 changes: 1 addition & 1 deletion py4DSTEM/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
)

# strain
from py4DSTEM.process import StrainMap
from py4DSTEM.process.strain.strain import StrainMap

# TODO - crystal
# TODO - ptycho
Expand Down
170 changes: 111 additions & 59 deletions py4DSTEM/braggvectors/braggvector_methods.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# BraggVectors methods

import numpy as np
from scipy.ndimage import gaussian_filter
from warnings import warn
import inspect
from warnings import warn

from emdfile import Array, Metadata, tqdmnd, _read_metadata
import matplotlib.pyplot as plt
import numpy as np
from emdfile import Array, Metadata, _read_metadata, tqdmnd
from py4DSTEM import show
from py4DSTEM.datacube import VirtualImage
from scipy.ndimage import gaussian_filter


class BraggVectorMethods:
Expand Down Expand Up @@ -517,6 +519,7 @@ def fit_origin(
robust_thresh=2,
plot=True,
plot_range=None,
cmap="RdBu_r",
returncalc=True,
**kwargs,
):
Expand All @@ -541,6 +544,8 @@ def fit_origin(
Plot the results
plot_range : float
Min and max color range for plot (pixels)
cmap : colormap
plotting colormap
returncalc : bool
Toggles returning the answer
Expand Down Expand Up @@ -571,75 +576,107 @@ def fit_origin(
tuple(q_meas)
)

# try to add to calibration
qx0_fit, qy0_fit, qx0_residuals, qy0_residuals = fit_origin(
tuple(q_meas),
mask=mask,
fitfunction=fitfunction,
robust=robust,
robust_steps=robust_steps,
robust_thresh=robust_thresh,
)

# try to add update calibration metadata
try:
self.calibration.set_origin([qx0_fit, qy0_fit])
self.calibration.set_origin((qx0_fit, qy0_fit))
self.setcal()
except AttributeError:
warn(
"No calibration found on this datacube - fit values are not being stored"
)
pass
if plot:
from py4DSTEM.visualize import show_image_grid

if mask is None:
qx0_meas, qy0_meas = q_meas
qx0_res_plot = qx0_residuals
qy0_res_plot = qy0_residuals
else:
qx0_meas = np.ma.masked_array(q_meas[0], mask=np.logical_not(mask))
qy0_meas = np.ma.masked_array(q_meas[1], mask=np.logical_not(mask))
qx0_res_plot = np.ma.masked_array(
qx0_residuals, mask=np.logical_not(mask)
)
qy0_res_plot = np.ma.masked_array(
qy0_residuals, mask=np.logical_not(mask)
)
qx0_mean = np.mean(qx0_fit)
qy0_mean = np.mean(qy0_fit)

if plot_range is None:
plot_range = 2 * np.max(qx0_fit - qx0_mean)

cmap = kwargs.get("cmap", "RdBu_r")
kwargs.pop("cmap", None)
axsize = kwargs.get("axsize", (6, 2))
kwargs.pop("axsize", None)

show_image_grid(
lambda i: [
qx0_meas - qx0_mean,
qx0_fit - qx0_mean,
qx0_res_plot,
qy0_meas - qy0_mean,
qy0_fit - qy0_mean,
qy0_res_plot,
][i],
H=2,
W=3,
# show
if plot:
self.show_origin_fit(
q_meas[0],
q_meas[1],
qx0_fit,
qy0_fit,
qx0_residuals,
qy0_residuals,
mask=mask,
plot_range=plot_range,
cmap=cmap,
axsize=axsize,
title=[
"measured origin, x",
"fitorigin, x",
"residuals, x",
"measured origin, y",
"fitorigin, y",
"residuals, y",
],
vmin=-1 * plot_range,
vmax=1 * plot_range,
intensity_range="absolute",
**kwargs,
)

# update calibration metadata
self.calibration.set_origin((qx0_fit, qy0_fit))
self.setcal()

# return
if returncalc:
return qx0_fit, qy0_fit, qx0_residuals, qy0_residuals

def show_origin_fit(
self,
qx0_meas,
qy0_meas,
qx0_fit,
qy0_fit,
qx0_residuals,
qy0_residuals,
mask=None,
plot_range=None,
cmap="RdBu_r",
**kwargs,
):
# apply mask
if mask is not None:
qx0_meas = np.ma.masked_array(qx0_meas, mask=np.logical_not(mask))
qy0_meas = np.ma.masked_array(qy0_meas, mask=np.logical_not(mask))
qx0_residuals = np.ma.masked_array(qx0_residuals, mask=np.logical_not(mask))
qy0_residuals = np.ma.masked_array(qy0_residuals, mask=np.logical_not(mask))
qx0_mean = np.mean(qx0_fit)
qy0_mean = np.mean(qy0_fit)

# set range
if plot_range is None:
plot_range = max(
(
1.5 * np.max(np.abs(qx0_fit - qx0_mean)),
1.5 * np.max(np.abs(qy0_fit - qy0_mean)),
)
)

# set figsize
imsize_ratio = np.sqrt(qx0_meas.shape[1] / qx0_meas.shape[0])
axsize = (3 * imsize_ratio, 3 / imsize_ratio)
axsize = kwargs.pop("axsize", axsize)

# plot
fig, ax = show(
[
[qx0_meas - qx0_mean, qx0_fit - qx0_mean, qx0_residuals],
[qy0_meas - qy0_mean, qy0_fit - qy0_mean, qy0_residuals],
],
cmap=cmap,
axsize=axsize,
title=[
"measured origin, x",
"fitorigin, x",
"residuals, x",
"measured origin, y",
"fitorigin, y",
"residuals, y",
],
vmin=-1 * plot_range,
vmax=1 * plot_range,
intensity_range="absolute",
show_cbar=True,
returnfig=True,
**kwargs,
)
plt.tight_layout()

return

def fit_p_ellipse(
self, bvm, center, fitradii, mask=None, returncalc=False, **kwargs
):
Expand Down Expand Up @@ -775,6 +812,21 @@ def mask_in_R(self, mask, update_inplace=False, returncalc=True):
else:
return

def to_strainmap(self, name: str = None):
"""
Generate a StrainMap object from the BraggVectors
equivalent to py4DSTEM.StrainMap(braggvectors=braggvectors)
Args:
name (str, optional): The name of the strainmap. Defaults to None which reverts to default name 'strainmap'.
Returns:
py4DSTEM.StrainMap: A py4DSTEM StrainMap object generated from the BraggVectors
"""
from py4DSTEM.process.strain import StrainMap

return StrainMap(self, name) if name else StrainMap(self)


######### END BraggVectorMethods CLASS ########

Expand Down
11 changes: 7 additions & 4 deletions py4DSTEM/braggvectors/braggvectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def setcal(
if pixel is None:
pixel = False if c.get_Q_pixel_size() == 1 else True
if rotate is None:
rotate = False if c.get_QR_rotflip() is None else True
rotate = False if c.get_QR_rotation() is None else True

# validate requested state
if center:
Expand All @@ -210,7 +210,7 @@ def setcal(
if pixel:
assert c.get_Q_pixel_size() is not None, "Requested calibration not found"
if rotate:
assert c.get_QR_rotflip() is not None, "Requested calibration not found"
assert c.get_QR_rotation() is not None, "Requested calibration not found"

# set the calibrations
self._calstate = {
Expand Down Expand Up @@ -272,6 +272,7 @@ def copy(self, name=None):
braggvector_copy.set_raw_vectors(self._v_uncal.copy())
for k in self.metadata.keys():
braggvector_copy.metadata = self.metadata[k].copy()
braggvector_copy.setcal()
return braggvector_copy

# write
Expand Down Expand Up @@ -479,14 +480,16 @@ def _transform(
# Q/R rotation
if rotate:
flip = cal.get_QR_flip()
theta = np.radians(cal.get_QR_rotation_degrees())
theta = cal.get_QR_rotation()
assert flip is not None, "Requested calibration was not found!"
assert theta is not None, "Requested calibration was not found!"
flip = cal.get_QR_flip()
flip = False if flip is None else flip
# rotation matrix
R = np.array(
[[np.cos(theta), np.sin(theta)], [-np.sin(theta), np.cos(theta)]]
)
# apply
# rotate and flip
if flip:
positions = R @ np.vstack((ans["qy"], ans["qx"]))
else:
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
Loading

0 comments on commit dc1773a

Please sign in to comment.