Skip to content
Snippets Groups Projects
Commit dcdc6242 authored by Jan Caron's avatar Jan Caron
Browse files

Added demo!

parent 256579f1
No related branches found
No related tags found
No related merge requests found
Showing
with 1101 additions and 0 deletions
......@@ -11,3 +11,5 @@ desktop.ini
.DS_Store
.DS
.ipynb_checkpoints*
%% Cell type:markdown id: tags:
# Installation:
%% Cell type:markdown id: tags:
**1) Install [Anaconda](https://www.anaconda.com/download/)**!
And (optional) an IDE of your choice (recommended: [PyCharm](https://www.jetbrains.com/pycharm/download/#section=windows) Community Edition)
%% Cell type:markdown id: tags:
**2) Clone or download the `pyramid` package!**
<img src="images/pyramid-gitlab.png">
Can be found [here](https://iffgit.fz-juelich.de/caron/pyramid), if you have access (ask me!).
%% Cell type:markdown id: tags:
**3) Clone or download the `jutil` package!**
<img src="images/jutil-gitlab.png">
Can be found [here](https://iffgit.fz-juelich.de/unger/jutil), if you have access (ask me or Jörn!).
%% Cell type:markdown id: tags:
**4) Create an environment for pyramid to work in, using the `environment.yml` file in the `pyramid` package by using:**
`conda env create`
in a terminal in the folder containing `pyramid`. Tested on Windows, but should also work on Mac/Linux.
<img src="images/environment.png">
%% Cell type:markdown id: tags:
**5) Activate environment by using:**
Windows: `activate pyramid`
Mac/Linux: `source activate pyramid`
Test if the correct environment is active!
<img src="images/activate.png">
Deactivate by using:
Windows: `deactivate`
Mac/Linux: `source deactivate`
%% Cell type:markdown id: tags:
**6) Install `jutil` into environment by using **
`python setup.py install`
in the folder containing `jutil`.
Make sure to use the correct python distribution (you can check the currently used one with `which python`). If this does not show the one in your newly created environment, you have to use the absolute path to the correct executable, e.g.:
`C:\Users\Jan\Anaconda3\envs\pyramid\python setup.py install`
%% Cell type:markdown id: tags:
**7) EITHER install `pyramid` OR create a PyCharm project containing the `pyramid` package!**
The former is simpler, but static.
The latter makes it easier to update, but requires you to add it to your `PYTHONPATH`, either manually (depends on OS) or through PyCharm directly:
<img src="images/addsource.png">
%% Cell type:markdown id: tags:
# Imports:
%% Cell type:code id: tags:
``` python
%matplotlib inline
```
%% Cell type:markdown id: tags:
Matplotlib magic, which causes plots to be part of the notebook (and not to cause pop ups).
%% Cell type:code id: tags:
``` python
import matplotlib.pyplot as plt
import numpy as np
```
%% Cell type:markdown id: tags:
Standard imports for plotting and array handling.
%% Cell type:code id: tags:
``` python
import pyramid as pr
```
%% Cell type:markdown id: tags:
Import of the `pyramid` package.
%% Cell type:code id: tags:
``` python
import hyperspy.api as hs
```
%% Output
WARNING:hyperspy.api:The traitsui GUI elements are not available, probably because the hyperspy_gui_traitui package is not installed.
%% Cell type:markdown id: tags:
(Optional) import of `hyperspy` (which is implicitly imported by pyramid! This line is used so that you can use it too!).
%% Cell type:markdown id: tags:
# `PhaseMap` objects:
%% Cell type:markdown id: tags:
The `PhaseMap` class is the main container for phase image information! It has four main properties:
<img src='images/phasemap-attributes.png'>
You can access the class by:
%% Cell type:code id: tags:
``` python
pr.PhaseMap
```
%% Output
pyramid.phasemap.PhaseMap
%% Cell type:markdown id: tags:
You can either create it from scratch from an array for the `phase` (optionally add more arrays for `mask` and `confidence`):
%% Cell type:code id: tags:
``` python
pr.PhaseMap(a=1., phase=np.random.rand(3, 3))
```
%% Output
<class 'pyramid.phasemap.PhaseMap'>(a=1.0, phase=array([[ 0.98147649, 0.46252942, 0.41486019],
[ 0.79813403, 0.57133853, 0.03047334],
[ 0.99620402, 0.28197351, 0.05998559]], dtype=float32), mask=array([[ True, True, True],
[ True, True, True],
[ True, True, True]], dtype=bool), confidence=array([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]], dtype=float32))
%% Cell type:markdown id: tags:
Or you can use a function to load your `PhaseMap` from files:
%% Cell type:code id: tags:
``` python
pr.load_phasemap(filename='files/phase.unf',
mask='files/mask.png',
confidence='files/confidence.png')
```
%% Output
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-7-e6d1be353b2f> in <module>()
1 pr.load_phasemap(filename='files/phase.unf',
2 mask='files/mask.png',
----> 3 confidence='files/confidence.png')
c:\users\caron\work\projects\pyramid\pyramid\file_io\io_phasemap.py in load_phasemap(filename, mask, confidence, a, threshold, print_mask_limits, **kwargs)
61 if mask is not None:
62 filemask, kwargs_mask = _parse_add_param(mask)
---> 63 mask_raw = _load(filemask, **kwargs_mask)
64 if print_mask_limits:
65 print('[Mask] min:', mask_raw.min(), 'max:', mask_raw.max(), 'threshold:', threshold)
c:\users\caron\work\projects\pyramid\pyramid\file_io\io_phasemap.py in _load(filename, as_phasemap, a, **kwargs)
81 return _load_from_npy(filename, as_phasemap, a, **kwargs)
82 elif extension in ['.jpeg', '.jpg', '.png', '.bmp', '.tif']:
---> 83 return _load_from_img(filename, as_phasemap, a, **kwargs)
84 # Load with HyperSpy:
85 else:
c:\users\caron\work\projects\pyramid\pyramid\file_io\io_phasemap.py in _load_from_img(filename, as_phasemap, a, **kwargs)
135 def _load_from_img(filename, as_phasemap, a, **kwargs):
136
--> 137 result = np.asarray(Image.open(filename, **kwargs).convert('L'))
138 if as_phasemap:
139 if a is None:
C:\Users\caron\AppData\Local\Continuum\anaconda3\envs\pyramid-legacy\lib\site-packages\PIL\Image.py in open(fp, mode)
2408
2409 if filename:
-> 2410 fp = builtins.open(filename, "rb")
2411 exclusive_fp = True
2412
FileNotFoundError: [Errno 2] No such file or directory: 'files/mask.png'
%% Cell type:markdown id: tags:
The package tries to load the grid spacing `a` from the phase file determined by `filename` and defaults to `1` [nm], if it can not be determined. You can overwrite the grid spacing by adding `a` as a keyword argument to the loading function.
`mask` and `confidence` are optional parameters and can be skipped (like in the "by-hand" example above).
`pyramid` uses mainly `hyperspy` functionality to load files (and `PIL` for images of all kinds) and thus has the same flexibility concerning different formats.
After constructing or loading a `PhaseMap`, it can be saved to a file:
%% Cell type:code id: tags:
``` python
phasemap = pr.load_phasemap(filename='phase.unf', mask='mask.png', confidence='confidence.png')
phasemap.save('phasemap.hdf5', overwrite=True)
```
%% Cell type:markdown id: tags:
# Plot `PhaseMap`:
%% Cell type:markdown id: tags:
First, load or create a `PhaseMap`:
%% Cell type:code id: tags:
``` python
phasemap = pr.load_phasemap(filename='phase.unf', mask='mask.png', confidence='confidence.png')
```
%% Cell type:markdown id: tags:
To plot the `PhaseMap` (including possibly the mask and the confidence), use:
%% Cell type:code id: tags:
``` python
phasemap.plot_phase()
```
%% Cell type:markdown id: tags:
You can use the following (optional) parameters to change the plot to your liking:
<img src='images/plot-phase-params.png'>
Furthermore, you can plot the holographic contour map by using:
%% Cell type:code id: tags:
``` python
phasemap.plot_holo()
```
%% Cell type:markdown id: tags:
You can use the following (optional) parameters to change the plot to your liking:
<img src='images/plot-holo-params.png'>
%% Cell type:markdown id: tags:
# `VectorData` objects:
%% Cell type:markdown id: tags:
The `VectorData` class is a container for 3D vector fields. It has two
<img src='images/vectordata-attributes.png'>
The class can be accessed by:
%% Cell type:code id: tags:
``` python
pr.VectorData
```
%% Cell type:markdown id: tags:
You can either create it from scratch from an array for the `field`:
%% Cell type:code id: tags:
``` python
pr.VectorData(a=1., field=np.random.rand(3, 2, 2, 2))
```
%% Cell type:markdown id: tags:
Or you can use a function to load your `VectorData` from file:
%% Cell type:code id: tags:
``` python
pr.load_vectordata(filename='magdata.hdf5')
```
%% Cell type:markdown id: tags:
The package tries to load the grid spacing `a` from the vector field file determined by `filename` and defaults to `1` [nm], if it can not be determined. You can overwrite the grid spacing by adding `a` as a keyword argument to the loading function.
After constructing or loading a `VectorData`, it can be saved to a file:
%% Cell type:code id: tags:
``` python
magdata = pr.load_vectordata(filename='magdata.hdf5')
magdata.save('magdata.hdf5', overwrite=True)
```
%% Cell type:markdown id: tags:
Furthermore, the `pr.magcreator` subpackage contains a lot of functions to create custom vector fields. It has a module `examples` with a lot of interesting shapes and geometries.
A vortex disc with a smooth core can e.g. be created by using (see next section for the plot):
%% Cell type:code id: tags:
``` python
magdata = pr.magcreator.examples.smooth_vortex_disc()
magdata.plot_quiver_field()
```
%% Cell type:markdown id: tags:
Or a Halbach disc:
%% Cell type:code id: tags:
``` python
magdata = pr.magcreator.examples.source_disc()
magdata.plot_quiver_field()
```
%% Cell type:markdown id: tags:
Each example has a lot of attributes which can be used to adapt them to the users needs.
For more fine control, the following functions can be used:
%% Cell type:code id: tags:
``` python
pr.magcreator.create_mag_dist_homog
```
%% Cell type:code id: tags:
``` python
pr.magcreator.create_mag_dist_vortex
```
%% Cell type:code id: tags:
``` python
pr.magcreator.create_mag_dist_smooth_vortex
```
%% Cell type:code id: tags:
``` python
pr.magcreator.create_mag_dist_source
```
%% Cell type:markdown id: tags:
The first parameter for these functions is always a boolean array `mag_shape`, which determines the magnetised volume in 3D. See the docstrings for more information.
%% Cell type:markdown id: tags:
# Plot VectorData objects:
%% Cell type:markdown id: tags:
There are several methods to plot slices of a 3D magnetisation distribution, e.g. the color coded field can be plotted with:
%% Cell type:code id: tags:
``` python
magdata = pr.load_vectordata(filename='magdata.hdf5')
magdata.plot_field(figsize=(10, 10), colorwheel=True)
```
%% Cell type:markdown id: tags:
You can use the following (optional) parameters to change the plot to your liking (in 3D, take care that you plot the correct slice along the correct axis!):
<img src='images/plot-field-params.png'>
Another plot is the quiver plot which plots arrows, whose density can be controlled with the parameter `ar_dens`:
%% Cell type:code id: tags:
``` python
magdata.plot_quiver(ar_dens=8, figsize=(10, 10), b_0=1, colorwheel=True)
```
%% Cell type:markdown id: tags:
You can use the following (optional) parameters to change the plot to your liking:
<img src='images/plot-quiver-params.png'>
By setting the parameter `coloring='amplitude'`, the amplitude of the arrows can be encoded:
%% Cell type:code id: tags:
``` python
magdata.plot_quiver(ar_dens=8, figsize=(10, 10), b_0=1, coloring='amplitude')
```
%% Cell type:markdown id: tags:
It is recommended to combine field and quiver plots by using:
%% Cell type:code id: tags:
``` python
magdata.plot_quiver_field(ar_dens=8, figsize=(10, 10), b_0=1, colorwheel=True)
```
%% Cell type:markdown id: tags:
For 2D reconstructions, sometimes a thickness correction has to be done. This is achieved by using the `b_0` parameter:
%% Cell type:code id: tags:
``` python
t = 36 # nm
b_0 = magdata.a / t
magdata.plot_quiver_field(ar_dens=8, figsize=(10, 10), b_0=b_0, colorwheel=True)
```
%% Cell type:markdown id: tags:
3D plots are also possible, but are not discussed here, due to problems with displaying them in a notebook!
%% Cell type:markdown id: tags:
# Forward Model:
%% Cell type:markdown id: tags:
A fast way to apply the forward model to a given magnetisation distribution is the convenience function:
%% Cell type:code id: tags:
``` python
phasemap = pr.utils.pm(magdata)
phasemap.plot_combined()
```
%% Cell type:markdown id: tags:
The function accepts optional parameters:
<img src='images/pm-params.png'>
%% Cell type:markdown id: tags:
# Reconstruction:
%% Cell type:markdown id: tags:
For a fast reconstruction of the projected in-plane moments from a single `PhaseMap`, you can use a convenient one-liner:
%% Cell type:code id: tags:
``` python
phasemap = pr.load_phasemap(filename='phase.unf', mask='mask.png', confidence='confidence.png')
magdata_rec, cost = pr.utils.reconstruction_2d_from_phasemap(phasemap, lam=0.01, plot_results=True)
```
%% Cell type:markdown id: tags:
These are the parameters that can be changed to influence the reconstruction:
<img src='images/rec2d-params.png'>
%% Cell type:markdown id: tags:
The one-liner does a lot of stuff under the hood, which can also be done manually to have granular control over the reconstruction process.
First, a `DataSet` instance has to be constructed, which holds one (like in this exampl) or more `PhaseMap` instances and the according `Projector` instances that determine the projection direction (a simple `z`-projection in this case).
The `DataSet` needs the grid spacing, the dimension of your 3D distribution and a scaling factor for the saturation induction (just use `b_0=1` if no further scaling is needed):
%% Cell type:code id: tags:
``` python
dim = (1,) + phasemap.dim_uv
data = pr.DataSet(phasemap.a, dim, b_0=1)
```
%% Cell type:markdown id: tags:
Now the phase images and projectors have to be added to the `DataSet`. In this example, only one pair is added and the projector (a simple `z`-projection) is created on the fly (it needs the dimensions of the 3D magnetisation volume):
%% Cell type:code id: tags:
``` python
data.append(phasemap, pr.SimpleProjector(dim))
```
%% Cell type:markdown id: tags:
If the mask, which determines the position of the magnetised volume in 3D space is known, it can be set by using (the mask is `True` everywhere in this example):
%% Cell type:code id: tags:
``` python
mask = np.ones(dim)
data.mask = mask
```
%% Cell type:markdown id: tags:
If the mask is not known, it can be calculated. If the `DataSet` contains only one `PhaseMap`, the 2D mask (if available) is used. For tilt series, a simple discrete back-projection algorithm is used. The command is:
%% Cell type:code id: tags:
``` python
data.set_3d_mask()
```
%% Cell type:markdown id: tags:
A forward model is constructed which uses the `DataSet` and a parameter `ramp_order` as input:
%% Cell type:code id: tags:
``` python
fwd_model = pr.ForwardModel(data, ramp_order=1)
```
%% Cell type:markdown id: tags:
The `ramp_order` determines the additional fit of phase polynoms:
* `ramp_order` = None : No additional polynom is fitted.
* `ramp_order` = 0 : A global phase offset is fitted.
* `ramp_order` = 1 : An offset and ramps are fitted.
Next, a `Regularisator` has to be constructed, which constrains the solution of the reconstruction:
%% Cell type:code id: tags:
``` python
reg = pr.FirstOrderRegularisator(data.mask, lam=0.01, add_params=fwd_model.ramp.n)
```
%% Cell type:markdown id: tags:
The `FirstOrderRegularisator` constrains the smoothness of the solution (Thikonov 1. order).
It uses the 3D `mask`, a regularisation parameter `lam` and `add_params`, which has to be set to the number of degrees of freedom of the ramp via `fwd_model.ramp.n`, as input.
`ForwardModel` and `Regularisator` are then combined in a `Costfunction`:
%% Cell type:code id: tags:
``` python
cost = pr.Costfunction(fwd_model, reg)
```
%% Cell type:markdown id: tags:
This `Costfunction` is then minimised using the `optimize_linear` function in the `reconstruction` module (all of this is done implicitely by the convenience function `pr.utils.reconstruction_2d_from_phasemap`):
%% Cell type:code id: tags:
``` python
magdata_rec = pr.reconstruction.optimize_linear(cost, max_iter=100, verbose=True)
magdata_rec.plot_quiver_field(ar_dens=8, colorwheel=True)
```
%% Cell type:markdown id: tags:
To find a good estimate for $\lambda$, an L-Curve analysis should be done. A dedicated class implementing this feature is currently under development!
%% Cell type:markdown id: tags:
3D reconstructions are not shown here, as they take a long time and plotting in a notebook is not very intuitive at the moment!
%% Cell type:markdown id: tags:
After reconstruction, several diagnostic measures can be calculated. They can be found in the `pr.diagnostics` module and are not further discussed here!
File added
File added
File added
demos/images/activate.png

32.4 KiB

demos/images/addsource.png

56 KiB

demos/images/confidence.png

1.56 KiB

demos/images/environment.png

57.1 KiB

demos/images/jutil-gitlab.png

63.1 KiB

demos/images/mask.png

2.37 KiB

demos/images/phasemap-attributes.png

34.6 KiB

demos/images/plot-field-params.png

34.8 KiB

demos/images/plot-holo-params.png

34.2 KiB

demos/images/plot-phase-params.png

88.8 KiB

demos/images/plot-quiver-params.png

96.5 KiB

demos/images/pm-params.png

31.3 KiB

demos/images/pyramid-gitlab.png

63.1 KiB

demos/images/rec2d-params.png

54.7 KiB

demos/images/vectordata-attributes.png

14.4 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment