upxo.xtalphy.texops module

class upxo.xtalphy.texops.tops[source]

Bases: object

fcc_tc_std = {'A1': (35.0, 45.0, 90.0), 'A2': (55.0, 90.0, 45.0), 'B': (45.0, 90.0, 45.0), 'C': (0.0, 90.0, 45.0), 'D': (59.0, 37.0, 26.0), 'P': (90.0, 45.0, 0.0), 'Q': (35.0, 55.0, 45.0), 'brass': (35.0, 45.0, 0.0), 'copper': (90.0, 35.0, 45.0), 'cube': (0.0, 0.0, 0.0), 'goss': (90.0, 90.0, 45.0), 'rotated_cube': (45.0, 0.0, 0.0), 's': (59.0, 37.0, 63.0)}
FCC_POLES = {'100': numpy.array, '110': numpy.array, '111': numpy.array}
sym_ops
classmethod synth_fcc(N=1000, tc_info={'brass': [0.3, [35.0, 45.0, 0.0]], 'copper': [0.45, [90.0, 35.0, 45.0]], 'goss': [0.1, [0.0, 45.0, 0.0]], 'rotated_cube': [0.15, [45.0, 0.0, 0.0]]}, n_tex_instances=2, n_sampling_instances=50)[source]

Examples

>>> from upxo.xtalphy.texops import tops
>>> tex = tops.synth_fcc(N=500,
>>> tc_info={"cube": [0.05, [0.0, 0.0, 0.0]],
>>> "rotated_cube": [0.05, [45.0, 0.0, 0.0]],
>>> "brass": [0.25, [35.0, 45.0, 0.0]],
>>> "goss": [0.10, [0.0, 45.0, 0.0]],
>>> "copper": [0.35, [90.0, 35.0, 45.0]],
>>> "s": [0.2, [59.0, 37.0, 63.0]]
>>> },
>>> n_tex_instances=1,
>>> n_sampling_instances=5)
>>> b = tex.tex['tex_instance.1']['sampling_instances']['ossi.1']['tc_ori_stacks']
>>> ea = np.vstack(list(b.values()))
>>> tex.plot_pole_figure(ea, pole_family='111', title="")
>>> b1 = [tex.tex['tex_instance.1']['sampling_instances'][k]['tc_ori_stacks']
>>> for k in tex.tex['tex_instance.1']['sampling_instances'].keys() if k[:5] == 'ossi.']
>>> b2 = [np.vstack(list(_b1_.values())) for _b1_ in b1]
>>> b3 = np.vstack(b2)
>>> b3.shape
>>> tex.plot_pole_figure(b3, pole_family='111')
classmethod synth_fcc_quats(N: int = 500, **tc_kwargs) numpy.ndarray[source]

Sample N FCC-consistent quaternions in [w, x, y, z] convention.

Calls synth_fcc() (single tex/sampling instance), extracts the Bunge Euler angles, and converts them to unit quaternions via scipy.spatial.transform.Rotation. Orientations are returned in the canonical positive-w hemisphere (w >= 0).

Parameters:
  • N (int) – Number of orientations to generate.

  • **tc_kwargs – Forwarded to synth_fcc() (e.g. custom tc_info dict).

Returns:

quats – Unit quaternions in [w, x, y, z] convention.

Return type:

ndarray, shape (N, 4), dtype float64

plot_pole_figure(euler_angles_deg, pole_family='100', title='')[source]

Creates a complete pole figure scatter plot for a specified pole family.

Parameters:
  • euler_angles_deg (np.ndarray) – An (N, 3) array of Bunge Euler angles.

  • pole_family (str) – The pole family to plot: ‘100’, ‘110’, or ‘111’.

  • title (str, optional) – Custom title for the plot.

cubic_Rz(a)[source]

Cubic rz.

cubic_Rx(a)[source]

Cubic rx.

cubic_euler_bunge_to_matrix(phi1, Phi, phi2, degrees=True)[source]

Bunge ZXZ rotation matrix: R = Rz(phi1) @ Rx(Phi) @ Rz(phi2).

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> import numpy as np
>>> ea = np.array([10, 20, 30])
>>> tex = TO()
>>> R = tex.cubic_euler_bunge_to_matrix(*ea)
>>> print(R)
cubic_euler_bunge_to_matrix_v1(phi1, Phi, phi2, degrees=True)[source]

Cubic euler bunge to matrix v1.

cubic_rotation_angle(R)[source]

Return angle (rad) of a proper rotation matrix R.

cubic_rotation_axis(R, angle)[source]

Return unit axis for rotation R given angle (rad). For very small angles, returns a default axis.

cubic_symmetry_operators()[source]

24 proper rotations for m-3m as signed permutation matrices with det=+1.

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> # ----------
>>> tex.cubic_symmetry_operators()
fcc_symmetrise_ori(ea_bunge, dtype=numpy.float32)[source]

Generate symmetric equivalents of an orientation.

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> # ----------
>>> ea_bunge = np.array([10, 20, 30])
>>> tex.fcc_symmetrise_ori(ea_bunge, dtype=np.float32)
fcc_symmetrise_ori_V1(ea_bunge, dtype=numpy.float32)[source]

Generate symmetric equivalents of an orientation inside Fund. Zone.

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> # ----------
>>> fcc_tc_std = {"copper": (90.0, 35.0, 45.0),  # {112}<111> Rolling
>>> "brass": (35.0, 45.0, 0.0),  # {110}<112> Rolling
>>> "s": (59.0, 37.0, 63.0),  # {123}<634> Rolling
>>> "goss": (0.0, 45.0, 0.0),  # {110}<001> Rolling
>>> "cube": (0.0, 0.0, 0.0),  # {001}<100> Annealing / RX
>>> "rotated_cube": (45.0, 0.0, 0.0),  # {001}<110> Annealing / RX
>>> "P": (90.0, 45.0, 0.0),   # {011}<122> Annealing / RX
>>> "A1": (35.0, 45.0, 90.0),  # {111}<110> Shear
>>> "A2": (55.0, 90.0, 45.0),  # {111}<112> Shear
>>> "B": (45.0, 90.0, 45.0),  # {112}<110> Shear
>>> "C": (0.0, 90.0, 45.0),  # {001}<110> Shear
>>> "Q": (35.0, 55.0, 45.0),  # {013}<231> transitional
>>> "D": (59.0, 37.0, 26.0),  # {4411}<1118> approx. transitional
>>> }
>>> EA_fund_zone = {}
>>> for tc, tcea in fcc_tc_std.items():
>>> ea_bunge = np.array(tcea)
>>> tex.fcc_symmetrise_ori(ea_bunge, dtype=np.float32)
>>> g = tex.cubic_euler_bunge_to_matrix(*ea_bunge, degrees=True)
>>> eq_mats = [tex._proj_to_so3(S @ g) for S in tex.sym_ops]
>>> eq_mats = tex._unique_rotations(eq_mats, tol=1E-8)
>>> symm_eq = np.array([list(tex._matrix_to_euler_bunge(R, degrees=True))
>>> for R in eq_mats], dtype=np.float32)
>>> EA_fund_zone[tc] = symm_eq[np.where(np.prod(symm_eq <= 90, axis=1))[0]]
normalize_euler_bunge(ea, degrees=True, eps=1e-06)[source]
Normalize Bunge ZXZ Euler angles (phi1, Phi, phi2) to canonical ranges.
  • phi1, phi2 in [0, 360) deg (or [0, 2π) rad)

  • Phi in [0, 180] deg (or [0, π] rad)

Handles BOTH Phi > 180 and Phi < 0 via ZXZ symmetry:

Phi’ = -Phi and (phi1’, phi2’) = (phi1+180, phi2+180) [mod 360] Phi’ = 360-Phi and same 180-shift for >180 case.

cubic_misorientation_V1(EA1, EA2, unique_tol_deg=0.0001, degrees=True)[source]

Vectorized fast misorientation (cubic, m-3m).

Accepts Euler triplet (phi1, Phi, phi2) or 3×3 rotation matrix.

Returns:

  • angle_deg_min (float)

  • axis_min (ndarray, shape (3,)) – Unit vector in sample frame.

  • top3_angles_deg (list of float) – Up to 3 smallest unique angles (deg), ascending.

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> tex.cubic_misorientation_V1([0, 0, 0], [35, 45, 90])
cubic_misorientation_V2(EA1, EA2, unique_tol_deg=0.0001, degrees=True)[source]

Vectorized fast misorientation (cubic, m-3m).

Accepts Euler triplet (phi1, Phi, phi2) or 3×3 rotation matrix.

Returns:

  • angle_deg_min (float)

  • axis_min (ndarray, shape (3,)) – Unit vector in sample frame.

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> tex.cubic_misorientation_V2([0, 0, 0], [35, 45, 90])
cubic_misorientation_V3(EA1, EA2, degrees=True)[source]

Vectorized fast misorientation (cubic, m-3m).

Accepts Euler triplet (phi1, Phi, phi2) or 3×3 rotation matrix.

Returns:

  • angle_deg_min (float)

  • axis_min (ndarray, shape (3,)) – Unit vector in sample frame.

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> tex.cubic_misorientation_V3([0, 0, 0], [35, 45, 90])
set_tc_info(tc_info, defaults={'hw_Phi': 5, 'hw_phi1': 5, 'hw_phi2': 5, 'perctol_Phi': 5, 'perctol_phi1': 5, 'perctol_phi2': 5, 'std_k_Phi': 3, 'std_k_phi1': 3, 'std_k_phi2': 3})[source]

Standardize a dictionary of texture component information to a consistent format.

Parameters:

tc_info (dict) – Texture components. Each value is a list whose first two elements are [percentage, [phi1, Phi, phi2]]; optional further elements are spread, std-k, and percentage-tolerance per Euler angle.

Returns:

Updates self.tc_info in place with all values normalised to [percentage, [ang1, ang2, ang3], [std1, std2, std3], [k1, k2, k3], [perctol]].

Return type:

None

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> # ----------
>>> # Possible input for gstslice.tc_info: 1
>>> tex.set_tc_info({"copper": [0.45, [90.0, 35.0, 45.0]],
>>> "brass": [0.30, [35.0, 45.0, 0.0]],
>>> "goss": [0.20, [90.0, 90.0, 45.0]],
>>> "rotated_cube": [0.01, [45.0, 0.0, 0.0]]
>>> })
>>> # Possible input for gstslice.tc_info: 2
>>> tex.set_tc_info({"copper": [0.45, [90.0, 35,.0 45.0], 8.0],
>>> "s": [0.15, [59.0, 37.0, 63.0], 7.0],
>>> "goss": [0.20, [90.0, 90.0, 45.0], 5.5],
>>> "rotated_cube": [0.01, [45.0, 0.0, 0.0], 9.8]
>>> })
>>> # Possible input for gstslice.tc_info: 3
>>> tex.set_tc_info({"copper": [0.45, [90.0, 35.0, 45.0], [8.0, 8.0, 8.0]],
>>> "goss": [0.05, [90.0, 90.0, 45.0], [6.0, 6.0, 6.0]],
>>> "brass": [0.30, [35.0, 45.0, 0.0], [6.0, 6.0, 6.0]],
>>> "rotated_cube": [0.01, [45.0, 0.0, 0.0], [8.0, 8.0, 8.0]]
>>> })
>>> # Possible input for gstslice.tc_info: 4
>>> tex.set_tc_info({"copper": [0.45, [90.0, 35.0, 45.0], [8.0, 8.0, 8.0], [3.0, 3.0, 3.0]],
>>> "brass": [0.30, [35.0, 45.0, 0.0], [10.0, 10.0, 10.0], [3.0, 3.0, 3.0]],
>>> "goss": [0.05, [90.0, 90.0, 45.0], [6.0, 6.0, 6.0], [3.0, 3.0, 3.0]],
>>> "rotated_cube": [0.01, [45.0, 0.0, 0.0], [8.0, 8.0, 8.0], [3.0, 3.0, 3.0]]
>>> })
>>> # Possible input for gstslice.tc_info: 5
>>> tex.set_tc_info({"copper": [0.45, [90.0, 35.0, 45.0], [8.0, 8.0, 8.0], [3.0, 3.0, 3.0], [5.0, 5.0, 5.0]],
>>> "s": [0.15, [59.0, 37.0, 63.0], [7.0, 7.0, 7.0], [3.0, 3.0, 3.0], [5.0, 5.0, 5.0]],
>>> "brass": [0.30, [35.0, 45.0, 0.0], [10.0, 10.0, 10.0], [3.0, 3.0, 3.0], [5.0, 5.0, 5.0]],
>>> "goss": [0.05, [90.0, 90.0, 45.0], [6.0, 6.0, 6.0], [3.0, 3.0, 3.0], [5.0, 5.0, 5.0]],
>>> "rotated_cube": [0.01, [45.0, 0.0, 0.0], [8.0, 8.0, 8.0], [3.0, 3.0, 3.0], [5.0, 5.0, 5.0]]
>>> })
>>> print(tex.tc_info)

Notes

Standard FCC texture-component reference orientations (Bunge Euler angles):

fcc_tc = {"copper": (90.0, 35.0, 45.0),  # {112}<111>  Rolling
          "brass":  (35.0, 45.0, 0.0),   # {110}<112>  Rolling
          "s":      (59.0, 37.0, 63.0),  # {123}<634>  Rolling
          "goss":   (90.0, 90.0, 45.0),  # {110}<001>  Rolling
          "cube":   (0.0,  0.0,  0.0),   # {001}<100>  Annealing/RX
          "rotated_cube": (45.0, 0.0, 0.0),  # {001}<110>  Annealing/RX
          "P":  (90.0, 45.0, 0.0),   # {011}<122>  Annealing/RX
          "A1": (35.0, 45.0, 90.0),  # {111}<110>  Shear
          "A2": (55.0, 90.0, 45.0),  # {111}<112>  Shear
          "B":  (45.0, 90.0, 45.0),  # {112}<110>  Shear
          "C":  (0.0,  90.0, 45.0),  # {001}<110>  Shear
          "Q":  (35.0, 55.0, 45.0),  # {013}<231>  transitional
          "D":  (59.0, 37.0, 26.0),  # {4411}<1118> transitional
          }
get_tcinfo()[source]

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> # ----------
>>> tex.set_tc_info({"copper": [0.45, [90.0, 35.0, 45.0]],
>>> "brass": [0.30, [35.0, 45.0, 0.0]],
>>> "goss": [0.20, [90.0, 90.0, 45.0]],
>>> "rotated_cube": [0.01, [45.0, 0.0, 0.0]]
>>> })
>>> VF, HW, SK, PT, ori_means = tex.get_tcinfo()
alloc_ori_counts_to_tc(N)[source]

Allocate orientation counts to texture components proportionally.

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> tex.set_tc_info({"copper": [0.45, [90.0, 35.0, 45.0]],
...                  "brass": [0.30, [35.0, 45.0, 0.0]],
...                  "goss": [0.20, [90.0, 90.0, 45.0]],
...                  "rotated_cube": [0.01, [45.0, 0.0, 0.0]]})
>>> ori_count = tex.alloc_ori_counts_to_tc(100)
>>> print(ori_count)
build_tex_dict_template()[source]

Build and return tex dict template.

gen_tex_fcc_synthetic(N=1000, distr='normal', n_tex_instances=1, n_sampling_instances=1, rand_ori_gen_rule='relaxed')[source]

Generate synthetic FCC texture for all texture and sampling instances.

Examples

>>> from upxo.xtalphy.texops import tops as TO
>>> tex = TO()
>>> tex.set_tc_info({"copper": [0.45, [90.0, 35.0, 45.0]],
...                  "brass": [0.30, [35.0, 45.0, 0.0]],
...                  "goss": [0.10, [90.0, 90.0, 45.0]],
...                  "rotated_cube": [0.15, [45.0, 0.0, 0.0]]})
>>> tex.gen_tex_fcc_synthetic(N=500, n_tex_instances=2,
...                           n_sampling_instances=500)
>>> tex.tex.keys()
>>> tex.n_texture_instances
>>> a = tex.tex['tex_instance.1']['sampling_instances']['ossi.1']['nsamples']
>>> b = tex.tex['tex_instance.1']['sampling_instances']['ossi.1']['tc_ori_stacks']
>>> sum([_b_.shape[0] for _b_ in b.values()])
gen_tex_fcc_synthetic_single_instance(VF, HW, SK, PT, ori_means, tiname)[source]

Gen tex fcc synthetic single instance.

gen_tex_fcc_sampling_instances(tiname, sampling_instances_ids, tc_comps, rand_ori_gen_rule='relaxed')[source]

Gen tex fcc sampling instances.

gen_symmetric_equivalents_fcc_ori(VF, HW, SK, PT, ori_means)[source]

BEA_SYMEQ_MO: Misorinetation angle of all orientations around each symmetric equivalent of the mean oreintation of every texcture component specified by user. Note; See descriptions for variable BEA_SYMEQ_MO_TC (in below codes) for more detauils.

BEA_SYMEQ_MO.keys() dict_keys([‘copper’, ‘brass’, ‘s’, ‘goss’, ‘cube’])

After processing, this shoudl have. * len(BEA_SYMEQ_MO[‘copper’]) –> 24 * len(BEA_SYMEQ_MO[‘copper’][0]) == ori_count[‘copper’] –> True

cubic_Ry(a)[source]

Cubic ry.

sheet_D2_sample_ops()[source]

Orthorhombic rolling-sheet sample symmetry (RD, TD, ND 180°).

fcc_variants_in_FZ_old(ea_bunge, *, degrees=True, tol=1e-08)[source]

Return ALL unique variants of an orientation inside the Bunge FZ for cubic (24) crystal + orthorhombic-sheet D2 (4) sample symmetry. Uniqueness is by rotation (not angles), and angles are canonicalized.

Parameters:
  • ea_bunge ((3,) iterable) – (phi1, Phi, phi2) in degrees by default.

  • degrees (bool)

  • tol (float) – Frobenius tolerance for rotation de-duplication.

Returns:

variants_FZ

Return type:

(k,3) float ndarray (degrees)

tc_variants_in_FZ()[source]

For every TC mean orientation in self.tc_info, compute the unique FZ variants (cubic + D2). Returns dict: name -> (k,3) array.

fcc_variants_in_FZ(ea_bunge, *, degrees=True, tol=1e-08)[source]

Unique FZ variants for cubic crystal (24 left ops). Sample symmetry (D2, 4 right ops) is used ONLY to fold into the FZ.

tc_info
ori_count
N
n_texture_instances
n_sampling_instances
tex