This function rotates a set of three Bunge Euler angles into the standard Stereographic triangle, interpolates the RGB color value based on a user selected reference sample direction, and outputs an integer value representing the RGB tuplet usable for plotting inverse pole figure colored grain maps.
The program can accommodate any of the seven crystal systems.
Inputs: 1) Reference sample direction (sd) input as an integer between 1 and 3. Options are [100], [010], and [001] with [001] being the most common choice found in the literature. Input "1" to select [100], "2" to select [010], and "3" to select the [001] sample direction. 2) Set of three Euler angles (phi1, PHI, phi2) in the Bunge notation (must be in radians) 3) Phase number "phase" used to assign black color values to voids (phase = 0) 4) Integer value of crystal class as defined by OIM Software: "43" for cubic "62" for hexagonal "42" for tetragonal "32" for trigonal "22" for orthorhombic "2" for monoclinic "1" for triclinic "0" for unindexed points (bad data point)
47{
48
50 const Real pi_x2 = 2.0 *
pi;
51 const Real a = std::sqrt(3.0) / 2.0;
52
53
54 unsigned int index = 0;
55 unsigned int nsym = 1;
56
68
69 unsigned int ref_dir[3] = {0, 0, 0};
70 Real g[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
71 Real hkl[3] = {0.0, 0.0, 0.0};
72 Real S[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
73 const Real(*SymOps)[3][3];
74
75 Point RGB;
76
77
78 switch (sd)
79 {
80 case 1:
81 ref_dir[0] = 1;
82 ref_dir[1] = 0;
83 ref_dir[2] = 0;
84 break;
85
86 case 2:
87 ref_dir[0] = 0;
88 ref_dir[1] = 1;
89 ref_dir[2] = 0;
90 break;
91
92 case 3:
93 ref_dir[0] = 0;
94 ref_dir[1] = 0;
95 ref_dir[2] = 1;
96 break;
97 };
98
99
100 const Real SymOpsCubic[24][3][3] = {
101 {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}, {{0, 0, 1}, {1, 0, 0}, {0, 1, 0}},
102 {{0, 1, 0}, {0, 0, 1}, {1, 0, 0}}, {{0, -1, 0}, {0, 0, 1}, {-1, 0, 0}},
103 {{0, -1, 0}, {0, 0, -1}, {1, 0, 0}}, {{0, 1, 0}, {0, 0, -1}, {-1, 0, 0}},
104 {{0, 0, -1}, {1, 0, 0}, {0, -1, 0}}, {{0, 0, -1}, {-1, 0, 0}, {0, 1, 0}},
105 {{0, 0, 1}, {-1, 0, 0}, {0, -1, 0}}, {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
106 {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1}}, {{1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
107 {{0, 0, -1}, {0, -1, 0}, {-1, 0, 0}}, {{0, 0, 1}, {0, -1, 0}, {1, 0, 0}},
108 {{0, 0, 1}, {0, 1, 0}, {-1, 0, 0}}, {{0, 0, -1}, {0, 1, 0}, {1, 0, 0}},
109 {{-1, 0, 0}, {0, 0, -1}, {0, -1, 0}}, {{1, 0, 0}, {0, 0, -1}, {0, 1, 0}},
110 {{1, 0, 0}, {0, 0, 1}, {0, -1, 0}}, {{-1, 0, 0}, {0, 0, 1}, {0, 1, 0}},
111 {{0, -1, 0}, {-1, 0, 0}, {0, 0, -1}}, {{0, 1, 0}, {-1, 0, 0}, {0, 0, -1}},
112 {{0, 1, 0}, {1, 0, 0}, {0, 0, -1}}, {{0, -1, 0}, {1, 0, 0}, {0, 0, 1}}};
113
114 const Real SymOpsHexagonal[12][3][3] = {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
115 {{-0.5,
a, 0}, {-
a, -0.5, 0}, {0, 0, 1}},
116 {{-0.5, -
a, 0}, {
a, -0.5, 0}, {0, 0, 1}},
117 {{0.5,
a, 0}, {-
a, 0.5, 0}, {0, 0, 1}},
118 {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1}},
119 {{0.5, -
a, 0}, {
a, 0.5, 0}, {0, 0, 1}},
120 {{-0.5, -
a, 0}, {-
a, 0.5, 0}, {0, 0, -1}},
121 {{1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
122 {{-0.5,
a, 0}, {
a, 0.5, 0}, {0, 0, -1}},
123 {{0.5,
a, 0}, {
a, -0.5, 0}, {0, 0, -1}},
124 {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
125 {{0.5, -
a, 0}, {-
a, -0.5, 0}, {0, 0, -1}}};
126
127 const Real SymOpsTetragonal[8][3][3] = {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
128 {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
129 {{1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
130 {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1}},
131 {{0, 1, 0}, {-1, 0, 0}, {0, 0, 1}},
132 {{0, -1, 0}, {1, 0, 0}, {0, 0, 1}},
133 {{0, 1, 0}, {1, 0, 0}, {0, 0, -1}},
134 {{0, -1, 0}, {-1, 0, 0}, {0, 0, -1}}};
135
136 const Real SymOpsTrigonal[6][3][3] = {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
137 {{-0.5,
a, 0}, {-
a, -0.5, 0}, {0, 0, 1}},
138 {{-0.5, -
a, 0}, {
a, -0.5, 0}, {0, 0, 1}},
139 {{0.5,
a, 0}, {
a, -0.5, 0}, {0, 0, -1}},
140 {{-1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
141 {{0.5, -
a, 0}, {-
a, -0.5, 0}, {0, 0, -1}}};
142
143 const Real SymOpsOrthorhombic[4][3][3] = {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
144 {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
145 {{1, 0, 0}, {0, -1, 0}, {0, 0, 1}},
146 {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1}}};
147
148 const Real SymOpsMonoclinic[2][3][3] = {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
149 {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}}};
150
151 const Real SymOpsTriclinic[1][3][3] = {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}};
152
153
154
155 if (sym == 43)
156 {
157 nsym = 24;
158 SymOps = SymOpsCubic;
159 eta_min = 0 * (
pi / 180);
160 eta_max = 45 * (
pi / 180);
161 chi_min = 0 * (
pi / 180);
162 chi_max = std::acos(std::sqrt(1.0 / (2.0 + (Utility::pow<2>(std::tan(eta_max))))));
163 }
164
165
166 else if (sym == 62)
167 {
168 nsym = 12;
169 SymOps = SymOpsHexagonal;
170 eta_min = 0 * (
pi / 180);
171 eta_max = 30 * (
pi / 180);
172 chi_min = 0 * (
pi / 180);
174 }
175
176
177 else if (sym == 42)
178 {
179 nsym = 8;
180 SymOps = SymOpsTetragonal;
181 eta_min = 0 * (
pi / 180);
182 eta_max = 45 * (
pi / 180);
183 chi_min = 0 * (
pi / 180);
185 }
186
187
188 else if (sym == 32)
189 {
190 nsym = 6;
191 SymOps = SymOpsTrigonal;
192 eta_min = 0 * (
pi / 180);
193 eta_max = 60 * (
pi / 180);
194 chi_min = 0 * (
pi / 180);
196 }
197
198
199 else if (sym == 22)
200 {
201 nsym = 4;
202 SymOps = SymOpsOrthorhombic;
203 eta_min = 0 * (
pi / 180);
204 eta_max = 90 * (
pi / 180);
205 chi_min = 0 * (
pi / 180);
207 }
208
209
210 else if (sym == 2)
211 {
212 nsym = 2;
213 SymOps = SymOpsMonoclinic;
214 eta_min = 0 * (
pi / 180);
215 eta_max = 180 * (
pi / 180);
216 chi_min = 0 * (
pi / 180);
218 }
219
220
221 else if (sym == 1)
222 {
223 nsym = 1;
224 SymOps = SymOpsTriclinic;
225 eta_min = 0 * (
pi / 180);
226 eta_max = 360 * (
pi / 180);
227 chi_min = 0 * (
pi / 180);
229 }
230
231
232 else
233 {
234 nsym = 0;
235 }
236
237
238
239 if (nsym == 0 || phase == 0)
240 RGB = 0;
241
242
243 else if (phi1 > pi_x2 || PHI > pi || phi2 > pi_x2)
244 RGB = 0;
245
246
247 else
248 {
249
250 g[0][0] = std::cos(phi1) * std::cos(phi2) - std::sin(phi1) * std::cos(PHI) * std::sin(phi2);
251 g[0][1] = std::sin(phi1) * std::cos(phi2) + std::cos(phi1) * std::cos(PHI) * std::sin(phi2);
252 g[0][2] = std::sin(phi2) * std::sin(PHI);
253 g[1][0] = -std::cos(phi1) * std::sin(phi2) - std::sin(phi1) * std::cos(PHI) * std::cos(phi2);
254 g[1][1] = -std::sin(phi1) * std::sin(phi2) + std::cos(phi1) * std::cos(PHI) * std::cos(phi2);
255 g[1][2] = std::cos(phi2) * std::sin(PHI);
256 g[2][0] = std::sin(phi1) * std::sin(PHI);
257 g[2][1] = -std::cos(phi1) * std::sin(PHI);
258 g[2][2] = std::cos(PHI);
259
260
261 index = 0;
262 while (index < nsym)
263 {
264
265 for (unsigned int i = 0; i < 3; ++i)
266 for (unsigned int j = 0; j < 3; ++j)
267 {
268 S[i][j] = 0.0;
269 for (unsigned int k = 0; k < 3; ++k)
270 S[i][j] += SymOps[index][i][k] * g[k][j];
271 }
272
273
274 for (unsigned int i = 0; i < 3; ++i)
275 {
276 hkl[i] = 0;
277 for (unsigned int j = 0; j < 3; ++j)
278 hkl[i] += S[i][j] * ref_dir[j];
279 }
280
281
282 eta = std::abs(std::atan2(hkl[1], hkl[0]));
283 chi = std::acos(std::abs(hkl[2]));
284
285
286 if (eta >= eta_min && eta < eta_max && chi >= chi_min && chi < chi_max)
287 break;
288
289
290 else
291 index++;
292
293
294 mooseAssert(index != nsym, "Euler2RGB failed to map the supplied Euler angle into the SST!");
295 }
296
297
298 if (sym == 43)
299 chi_max2 = std::acos(std::sqrt(1.0 / (2.0 + (Utility::pow<2>(std::tan(eta))))));
300 else
302
303
304 red = std::abs(1.0 - (chi / chi_max2));
305 blue = std::abs((eta - eta_min) / (eta_max - eta_min));
306 green = 1.0 - blue;
307
308 blue = blue * (chi / chi_max2);
309 green = green * (chi / chi_max2);
310
311
312 mooseAssert(red >= 0 || green >= 0 || blue >= 0, "RGB component values must be positive!");
313
314 RGB(0) = std::sqrt(red);
315 RGB(1) = std::sqrt(green);
316 RGB(2) = std::sqrt(blue);
317
318
319 maxRGB = std::max({RGB(0), RGB(1), RGB(2)});
320
321
322 RGB /= maxRGB;
323 }
324
325 return RGB;
326}
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real