https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Functions
Euler2RGB.C File Reference

Go to the source code of this file.

Functions

Point euler2RGB (unsigned int sd, Real phi1, Real PHI, Real phi2, unsigned int phase, unsigned int sym)
 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.
 

Function Documentation

◆ euler2RGB()

Point euler2RGB ( unsigned int  sd,
Real  phi1,
Real  PHI,
Real  phi2,
unsigned int  phase,
unsigned int  sym 
)

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)

Output: Integer value of RGB calculated from: RGB = red*256^2 + green*256 + blue (where red, green, and blue are integer values between 0 and 255)

Definition at line 46 of file Euler2RGB.C.

47{
48 // Define Constants
49 const Real pi = libMesh::pi;
50 const Real pi_x2 = 2.0 * pi;
51 const Real a = std::sqrt(3.0) / 2.0;
52
53 // Preallocate and zero variables
54 unsigned int index = 0;
55 unsigned int nsym = 1;
56
57 Real blue = 0.0;
58 Real chi = 0.0;
59 Real chi_min = 0.0;
60 Real chi_max = 0.0;
61 Real chi_max2 = 0.0;
62 Real eta = 0.0;
63 Real eta_min = 0.0;
64 Real eta_max = 0.0;
65 Real green = 0.0;
66 Real maxRGB = 0.0;
67 Real red = 0.0;
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 // Assign reference sample direction
78 switch (sd)
79 {
80 case 1: // 100
81 ref_dir[0] = 1;
82 ref_dir[1] = 0;
83 ref_dir[2] = 0;
84 break;
85
86 case 2: // 010
87 ref_dir[0] = 0;
88 ref_dir[1] = 1;
89 ref_dir[2] = 0;
90 break;
91
92 case 3: // 001
93 ref_dir[0] = 0;
94 ref_dir[1] = 0;
95 ref_dir[2] = 1;
96 break;
97 };
98
99 // Define symmetry operators for each of the seven crystal systems
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 // Assign parameters based on crystal class (sym)
154 // Load cubic parameters (class 432)
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 // Load hexagonal parameters (class 622)
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);
173 chi_max = pi / 2;
174 }
175
176 // Load tetragonal parameters (class 422)
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);
184 chi_max = pi / 2;
185 }
186
187 // Load trigonal parameters (class 32)
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);
195 chi_max = pi / 2;
196 }
197
198 // Load orthorhombic parameters (class 22)
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);
206 chi_max = pi / 2;
207 }
208
209 // Load monoclinic parameters (class 2)
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);
217 chi_max = pi / 2;
218 }
219
220 // Load triclinic parameters (class 1)
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);
228 chi_max = pi / 2;
229 }
230
231 // Accomodate non-conforming (bad) data points
232 else
233 {
234 nsym = 0;
235 }
236
237 // Start of main routine //
238 // Assign black RGB values for bad data points (nsym = 0) or voids (phase = 0)
239 if (nsym == 0 || phase == 0)
240 RGB = 0;
241
242 // Assign black RGB value for Euler angles outside of allowable range
243 else if (phi1 > pi_x2 || PHI > pi || phi2 > pi_x2)
244 RGB = 0;
245
246 // Routine for valid set of Euler angles
247 else
248 {
249 // Construct 3X3 orientation matrix
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 // Loop to sort Euler angles into standard stereographic triangle (SST)
261 index = 0;
262 while (index < nsym)
263 {
264 // Form orientation matrix
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 // Multiple orientation matrix by reference sample direction
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 // Convert to spherical coordinates (ignore "r" variable since r=1)
282 eta = std::abs(std::atan2(hkl[1], hkl[0]));
283 chi = std::acos(std::abs(hkl[2]));
284
285 // Continue if eta and chi values are within the SST
286 if (eta >= eta_min && eta < eta_max && chi >= chi_min && chi < chi_max)
287 break;
288
289 // Increment to next symmetry operator if not in SST
290 else
291 index++;
292
293 // Check for solution
294 mooseAssert(index != nsym, "Euler2RGB failed to map the supplied Euler angle into the SST!");
295 }
296
297 // Adjust maximum chi value to ensure it falls within the SST (cubic materials only)
298 if (sym == 43)
299 chi_max2 = std::acos(std::sqrt(1.0 / (2.0 + (Utility::pow<2>(std::tan(eta))))));
300 else
301 chi_max2 = pi / 2;
302
303 // Calculate the RGB color values and make adjustments to maximize colorspace
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 // Check for negative RGB values before taking square root
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 // Find maximum value of red, green, or blue
319 maxRGB = std::max({RGB(0), RGB(1), RGB(2)});
320
321 // Normalize position of SST center point
322 RGB /= maxRGB;
323 }
324
325 return RGB;
326}
Point eta
const Real pi
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

Referenced by EulerAngleVariables2RGBAux::computeValue(), EulerAngleProvider2RGBAux::precalculateValue(), and TEST().