Skip to content

Commit 9b32541

Browse files
authored
Geometry comparison scripts
2025-02-18 update This update includes: 1. Assorted scripts used for the manuscript "Comparison of Kikuchi Diffraction Geometries in Scanning Electron Microscope" (https://arxiv.org/abs/2411.13018). They can be found `modules/ded_geometry_comparison` with a more detailed `readme`. [^1] 2. Nomenclature change for dynamic templates: - The folder `phases/masterpattern` is renamed `dynamic_templates`. Example scripts are changed accordingly. - Dynamic patterns simulated from a few different software packages [^2] are now supported. A few examples (using Si) were provided. You may refer to the example .pha files to build phase files on your own, or check out the short guide under `tutorial_docs`. [^1]: Reconstructed reference spheres with experimental data are uploaded separately to Zenodo. See: 10.5281/zenodo.14111773 . [^2]: Espirit DynamicS, EMsoft, and the package by Winkelmann et al. (hereby called "bwkd", outlined in doi:10.1111/jmi.13051).
2 parents de72951 + feac3e1 commit 9b32541

File tree

223 files changed

+14369
-695
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

223 files changed

+14369
-695
lines changed

.gitignore

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
/utils/gmail.m
22
/testing/*
33
/outputs/*
4-
/phases/cifs/*
5-
/phases/masterpatterns/*
6-
/phases/phasefiles/*
4+
75

86
# Logs and databases #
97
######################
@@ -29,3 +27,15 @@ Thumbs.db
2927
#Matlab Files
3028
*.asv
3129
*.fig
30+
31+
# Phase folders
32+
/phases/cifs
33+
/phases/cifs/*
34+
/phases/dynamic_templates
35+
/phases/dynamic_templates/*
36+
/phases/phasefiles
37+
/phases/phasefiles/*
38+
39+
# Phase folders - deprecated
40+
/phases/masterpatterns
41+
/phases/masterpatterns/*

decks/AstroEBSD_PatternMatch_2021.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252

5353
%% Low level setting up stuff - you shouldn't need to change this
5454
RTM.Phase_Folder = fullfile(InputUser.Astro_loc,'phases'); %location of the AstroEBSD phases super-folder
55-
RTM.Bin_loc = fullfile(RTM.Phase_Folder,'masterpatterns'); %location of the binary files used for RTM
55+
RTM.Bin_loc = fullfile(RTM.Phase_Folder,'dynamic_templates'); %location of the binary files used for RTM
5656

5757
[ SettingsXCF, correction, SettingsXCF2 ] = FFT_Filter_settings( RTM.screensize, RTM.LPTsize );
5858

decks/PCA/PCA_deck.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747

4848
%These need to be the names of '.pha' files in the '\phases\phasefiles'
4949
%folder. There need to be corresponding '.cif' and '.BIN' files in 'cifs'
50-
%and 'masterpatterns' folders. - Only relevant to RTM analyses.
50+
%and 'dynamic_templates' folders. - Only relevant to RTM analyses.
5151
InputUser.Phases={'Ni','ZrC','M6C'};
5252

5353
% Run PCA on EBSD, EDX, or both

decks/RTM/RTM_multiphase_deck.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262

6363
%% now run the code
6464
RTM.Phase_Folder = fullfile(InputUser.Astro_loc,'phases'); %location of the AstroEBSD phases super-folder
65-
RTM.Bin_loc = fullfile(RTM.Phase_Folder,'masterpatterns'); %location of the binary files used for RTM
65+
RTM.Bin_loc = fullfile(RTM.Phase_Folder,'dynamic_templates'); %location of the binary files used for RTM
6666
RTM.parsearch=2;
6767

6868
[MapInfo.MapData,MicroscopeData,PhaseData,MapInfo.EBSPData ]=bReadHDF5( InputUser );

gen/loading/EBSP_BGCor.m

Lines changed: 82 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,22 @@
1111
% %background correction
1212
% Settings_Cor.gfilt=1; %use a low pass filter
1313
% Settings_Cor.gfilt_s=5; %low pass filter sigma
14-
%
14+
%
1515
% %radius mask
1616
% Settings_Cor.radius=1; %use a radius mask
1717
% Settings_Cor.radius_frac=0.9; %fraction of the pattern width to use as the mask
18-
%
18+
%
1919
% %hold pixel
2020
% Settings_Cor.hotpixel=1; %hot pixel correction
2121
% Settings_Cor.hot_thresh=1000; %hot pixel threshold
22-
%
22+
%
2323
% %resize
2424
% Settings_Cor.resize=1; %resize correction
2525
% Settings_Cor.size=150; %image width
26-
%
26+
%
2727
% Settings_Cor.RealBG=0; %use a real BG
2828
% Settings_Cor.EBSP_bgnum=30; %number of real pattern to use for BG
29-
%
29+
%
3030
% Settings_Cor.SquareCrop=1; %crop to a square
3131
%
3232
%Settings_Cor
@@ -45,13 +45,12 @@
4545
EBSP2=EBSP;
4646

4747
%check fields exist & create if needed - this is ordered in the order of
48-
%operations to aid with debugging & adding new correction routines
48+
%operations to aid with debugging & adding new correction routines
4949
%as needed
5050

51-
if ~isfield(Settings_Cor,'tkd_onaxis')
52-
Settings_Cor.tkd_onaxis = [0 0 0 0 0]; %[1/0, xc,yc,ro,ri]
51+
if ~isfield(Settings_Cor,'NaNClean')
52+
Settings_Cor.NaNClean=0;
5353
end
54-
5554
if ~isfield(Settings_Cor,'MeanCentre')
5655
Settings_Cor.MeanCentre=0;
5756
end
@@ -117,63 +116,88 @@
117116
end
118117

119118
if ~isfield(Settings_Cor,'LineError')
120-
Settings_Cor.LineError=0;
119+
Settings_Cor.LineError=0;
121120
end
122121

123122
if ~isfield(Settings_Cor,'MeanCentre')
124-
Settings_Cor.LineError=0;
123+
Settings_Cor.LineError=0;
125124
end
126125

127-
%% Start the corrections
128-
if Settings_Cor.RealBG == 1
129-
if size(EBSP2) == size(Settings_Cor.EBSP_bg) %this if statement helps if the debug isn't working properly
130-
EBSP2=EBSP2./Settings_Cor.EBSP_bg;
131-
end
126+
if ~isfield(Settings_Cor,'rkd')
127+
Settings_Cor.rkd=0;
132128
end
133129

134-
if Settings_Cor.tkd_onaxis(1) == 1 %blank the central beam and crop the edge
135-
[xgrid,ygrid]=meshgrid(1:size(EBSP2,2),1:size(EBSP2,1));
136-
137-
tkd_set=Settings_Cor.tkd_onaxis(2:5);%[3,3,30,80];
138-
139-
xc=floor(mean(xgrid(:)))+tkd_set(1);
140-
yc=floor(mean(ygrid(:)))+tkd_set(2);
141-
ri=tkd_set(3);
142-
ro=tkd_set(4);
143-
pgrid=sqrt((xgrid-xc).^2+(ygrid-yc).^2);
144-
grid_ok=false(size(xgrid));
145-
grid_ok(pgrid > ri & pgrid < ro) = true;
146-
pat_filtered = zeros(size(EBSP2));
147-
pat_filtered(grid_ok)=EBSP2(grid_ok);
148-
% EBSP2=pat_filtered;
149-
150-
x_new=xc+(-ro:ro);
151-
y_new=yc+(-ro:ro);
152-
EBSP2=pat_filtered(y_new,x_new);
153-
mean_tkd=mean(EBSP2(EBSP2~=0));
154-
std_tkd=std(EBSP2(EBSP2~=0));
155-
156-
EBSP2(EBSP2~=0)=(EBSP2(EBSP2~=0)-mean_tkd)/std_tkd;
157-
130+
%% Start the corrections
131+
132+
if Settings_Cor.rkd == 1 %RKD
133+
134+
pat2=EBSP2(2:end-1,2:end-1);
135+
136+
pat2_q1=pat2(1:253,1:218);
137+
pat2_q2=pat2(1:218,225:end);
138+
pat2_q3=pat2(260:end,1:253);
139+
pat2_q4=pat2(225:end,260:end);
140+
141+
pat_std=std([pat2_q1(:);pat2_q2(:);pat2_q3(:);pat2_q4(:)]);
142+
pat_mean=mean([pat2_q1(:);pat2_q2(:);pat2_q3(:);pat2_q4(:)]);
143+
EBSP2=randn(size(pat2))*pat_std+pat_mean;
144+
EBSP2(1:253,1:218)=pat2_q1;
145+
EBSP2(1:218,225:end)=pat2_q2;
146+
EBSP2(260:end,1:253)=pat2_q3;
147+
EBSP2(225:end,260:end)=pat2_q4;
148+
158149
end
159150

160151
if Settings_Cor.SquareCrop == 1 %crop the image to a square
161152
EBSP_size=min(size(EBSP2));
162153
crop.centre = [size(EBSP2, 2)/2 size(EBSP2, 1)/2];
163-
s=1:EBSP_size; s=s-mean(s);
164-
sy=s+crop.centre(2)+0.5;
154+
s=1:EBSP_size; s=s-nanmean(s);
155+
156+
sy=s+crop.centre(2)+0.5;
165157
sx=s+crop.centre(1)+0.5;
158+
159+
%helps deal with issue with when the patterns are not even in size to start
160+
sx=floor(sx);
161+
sy=floor(sy);
166162
EBSP2=EBSP2(sy,sx);
167163
end
168164

165+
if Settings_Cor.NaNClean == 1 %NaN correction
166+
[y,x]=find(isnan(EBSP2)==1);
167+
168+
[threexthreey,threexthreex]=meshgrid(-1:1,-1:1);
169+
170+
if numel(y) > 0
171+
for s=1:numel(y)
172+
y_v=y(s)+threexthreey;
173+
x_v=x(s)+threexthreex;
174+
175+
y_v(y_v<0)=[];
176+
x_v(x_v<0)=[];
177+
178+
y_v(y_v<0)=[];
179+
x_v(x_v<0)=[];
180+
181+
y_v(y_v>size(EBSP2,1))=[];
182+
x_v(x_v>size(EBSP2,2))=[];
183+
184+
sv=sub2ind(size(EBSP2),y_v(:),x_v(:));
185+
EBSP2(y,x)=median(EBSP2(sv),'omitnan');
186+
end
187+
end
188+
189+
end
190+
169191
if Settings_Cor.SatCor == 1 %saturation correction
170192
I_noise= imnoise(zeros(size(EBSP2)),'gaussian');
171-
I_noise=mean(EBSP2(:))+std(EBSP2(:))*I_noise;
193+
I_noise=nanmean(EBSP2(:))+nanstd(EBSP2(:))*I_noise;
172194
mvals=find(EBSP2 == max(EBSP2(:)));
173195
EBSP2(mvals)=I_noise(mvals);
174196
end
175197

176-
198+
if Settings_Cor.RealBG == 1
199+
EBSP2=EBSP2./Settings_Cor.EBSP_bg;
200+
end
177201

178202
if Settings_Cor.SplitBG == 1
179203
EBSPw=size(EBSP2,2);
@@ -186,7 +210,7 @@
186210
EBSP2b_g = imgaussfilt(EBSP2b,gf);
187211

188212
EBSP2=[EBSP2a./EBSP2a_g EBSP2b./EBSP2b_g];
189-
213+
190214
end
191215

192216
%cor the pattern for hot pixels
@@ -197,8 +221,8 @@
197221

198222
if Settings_Cor.LineError==1
199223

200-
meanval=mean(EBSP2(:));
201-
patstd=std(EBSP2(:));
224+
meanval=nanmean(EBSP2(:));
225+
patstd=nanstd(EBSP2(:));
202226

203227
loc1=floor(0.9667*size(EBSP,1));
204228
loc2=ceil(0.98*size(EBSP,1));
@@ -209,7 +233,7 @@
209233
end
210234
end
211235

212-
%fix the mean and std
236+
%fix the mean and nanstd
213237
EBSP2=fix_mean(EBSP2);
214238

215239
%resize the image
@@ -259,9 +283,13 @@
259283
r_thresh=Settings_Cor.radius_frac*4/3*cs(1)/2;
260284

261285
[xgrid,ygrid]=meshgrid(1:cs(2),1:cs(1));
262-
r_grid=sqrt((xgrid-size(EBSP2,2)/2).^2+(ygrid-size(EBSP2,1)/2).^2);
263-
EBSP2(r_grid>=r_thresh) = 0;
264-
EBSP2(r_grid<r_thresh)= EBSP2(r_grid<r_thresh)-mean(EBSP2(r_grid<r_thresh));
286+
xgrid=int32(xgrid);
287+
ygrid=int32(ygrid);
288+
root_values=(xgrid-size(EBSP2,2)/2).^2+(ygrid-size(EBSP2,1)/2).^2;
289+
r_grid=sqrt(double(root_values));
290+
%%
291+
EBSP2(r_grid>=double(r_thresh)) = 0;
292+
EBSP2(r_grid<double(r_thresh))= EBSP2(r_grid<double(r_thresh))-nanmean(EBSP2(r_grid<double(r_thresh)));
265293
else
266294
EBSP2=fix_mean(EBSP2);
267295
end
@@ -275,12 +303,12 @@
275303
hpix=find(abs(EBSP_med-EBSP2) > 0.8);
276304
EBSP2(hpix)=EBSP_med(hpix);
277305
end
278-
% EBSP2=fix_mean(EBSP2);
306+
% EBSP2=fix_mean(EBSP2);
279307
end
280308

281309
if Settings_Cor.MeanCentre==1
282310
%taken from fix fixmean function, without the make positive part
283-
EBSP2=(EBSP2-mean(EBSP2(:)))/std(EBSP2(:));
311+
EBSP2=(EBSP2-nanmean(EBSP2(:)))/nanstd(EBSP2(:));
284312
end
285313

286314
Settings_Cor_out=Settings_Cor;
@@ -304,7 +332,7 @@
304332

305333
function EBSP2=fix_mean(EBSP)
306334
%zero mean & fix stdev
307-
EBSP2=(EBSP-mean(EBSP(:)))/std(EBSP(:));
335+
EBSP2=(EBSP-nanmean(EBSP(:)))/nanstd(EBSP(:));
308336
%make positive
309337
EBSP2=EBSP2-min(EBSP2(:))+1;
310338
end

gen/loading/H5OINA_Convert.m

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
function [ebsdtemp] = H5OINA_Convert(ebsd_data,header_data,file_dset,phase_names,phase_colors,ebsd_nonpm)
2+
%H5OINA_CONVERT Convert the output from the HFOINA_Read function into a
3+
%MTEX EBSD container
4+
%
5+
% Ben Britton - Feb 2024
6+
%
7+
% Adapted from load_h5oina
8+
9+
10+
slice_name=['s' file_dset];
11+
12+
CS{1}='notIndexed';
13+
num_phases=numel(header_data.(slice_name).phase);
14+
15+
for n=1:num_phases
16+
phaseN=1+n;
17+
Space_Group=double(header_data.(['s' file_dset]).phase{n}.Space_Group);
18+
Lattice_Dimensions=double(header_data.(['s' file_dset]).phase{n}.Lattice_Dimensions);
19+
Lattice_Angles=double(header_data.(['s' file_dset]).phase{n}.Lattice_Angles);
20+
21+
if nargin > 5 && ~isempty(phase_names)
22+
Mineral=phase_names{n};
23+
CS{phaseN} = crystalSymmetry('SpaceId',Space_Group, ...
24+
Lattice_Dimensions,...
25+
Lattice_Angles,...
26+
'Mineral',Mineral,'Color',phase_colors{n});
27+
else
28+
Mineral=char(header_data.(['s' file_dset]).phase{1}.Phase_Name);
29+
30+
CS{phaseN} = crystalSymmetry('SpaceId',Space_Group, ...
31+
Lattice_Dimensions,...
32+
Lattice_Angles,...
33+
'Mineral',Mineral);
34+
end
35+
end
36+
37+
rc = rotation.byEuler(double(header_data.(slice_name).Specimen_Orientation_Euler(:)')*degree); % what definition? Bunge?
38+
39+
% set up EBSD data
40+
rot = rc*rotation.byEuler(ebsd_data.(slice_name).Euler');
41+
phase = ebsd_data.(slice_name).Phase;
42+
opt=struct;
43+
44+
% read some fields
45+
EBSD_fieldnames=fieldnames(ebsd_data.(slice_name));
46+
47+
num_fields=size(EBSD_fieldnames,1);
48+
for n = 1: num_fields
49+
s=ebsd_data.(slice_name).(EBSD_fieldnames{n});
50+
if size(s,2) == 1 && size(s,1) == numel(phase)
51+
try
52+
opt.(EBSD_fieldnames{n})=double(s);
53+
catch
54+
try
55+
opt.(EBSD_fieldnames{n})=s;
56+
catch
57+
end
58+
end
59+
60+
end
61+
end
62+
63+
%not put the Euler angles in the options too
64+
if isfield(ebsd_data.(slice_name),'Euler')
65+
opt.euler1=double(ebsd_data.(slice_name).Euler(1,:)');
66+
opt.euler2=double(ebsd_data.(slice_name).Euler(2,:)');
67+
opt.euler3=double(ebsd_data.(slice_name).Euler(3,:)');
68+
end
69+
70+
try
71+
opt.x=opt.Beam_Position_X;
72+
opt.y=opt.Beam_Position_Y;
73+
catch
74+
try
75+
opt.x=ebsd_nonpm.prop.x;
76+
opt.y=ebsd_nonpm.prop.y;
77+
catch
78+
error('Beam Positions Not Loaded - was this a pattern match file?')
79+
end
80+
end
81+
82+
ebsdtemp = EBSD(rot,phase,CS,opt,'unitCell',calcUnitCell([opt.x,opt.y]));
83+
ebsdtemp.opt.Header = header_data.(slice_name);
84+
85+
end
86+

0 commit comments

Comments
 (0)