11from time import time
22import numpy as np
3- from typing import Tuple , List , Union
3+ from typing import Tuple , List , Union , Optional
44from scipy .fft import fftn , ifftn , fftfreq
5+ from scipy .spatial .transform import Rotation
56from MSUtils .general .MicrostructureImage import MicrostructureImage
67from MSUtils .general .h52xdmf import write_xdmf
78
@@ -14,31 +15,31 @@ def generate_spinodal_microstructure(
1415 exponent : float = 2.0 ,
1516 seed : int = 42 ,
1617 L : Union [Tuple [float , float , float ], List [float ]] = (1.0 , 1.0 , 1.0 ),
17- anisotropy_axes : Union [Tuple [np .ndarray , np .ndarray ], List [np .ndarray ]] = (
18- np .array ([1.0 , 0.0 , 0.0 ]),
19- np .array ([0.0 , 1.0 , 0.0 ]),
20- ),
18+ rotation_matrix : Optional [np .ndarray ] = np .eye (3 , dtype = np .float32 ),
2119):
2220 """Generate a binary spinodal microstructure via spectral filtering.
2321
2422 Parameters
2523 ----------
2624 shape : tuple or list
2725 Grid size (nz, ny, nx).
26+ volume_fraction : float, default 0.5
27+ Target volume fraction of the phase 1.
2828 k0 : array-like, default [6.0, 6.0, 6.0]
29- Center wavenumber in cycles per domain (not angular) for each axis [k0_v3, k0_v2, k0_v1 ].
29+ Center wavenumber in cycles per domain (not angular) for each axis [k0_1, k0_2, k0_3 ].
3030 bandwidth : array-like, default [0.6, 0.6, 0.6]
31- Relative Gaussian width (fraction of k0) for each axis [bw_v3, bw_v2, bw_v1].
32- Use same values for isotropic bandwidth, different values for anisotropic.
33- exponent : float
34- High-k rolloff exponent (larger -> stronger suppression)
35- seed : int, optional
36- RNG seed for reproducibility
31+ Relative Gaussian width (fraction of k0) for each axis [bw_1, bw_2, bw_3].
32+ exponent : float, default 2.0
33+ High-k rolloff exponent (larger -> stronger suppression of high frequencies).
34+ seed : int, default 42
35+ RNG seed for reproducibility.
3736 L : array-like, default [1.0, 1.0, 1.0]
38- Physical dimensions [Lz, Ly, Lx].
39- anisotropy_axes : 2-tuple or list of vectors, default [(1,0,0), (0,1,0)]
40- Define a preferred coordinate system (v1, v2) for oblique orientations.
41- v1, v2 should be orthogonal unit vectors defining preferred directions.
37+ rotation_matrix : ndarray (ndim x ndim), default identity
38+ Orthonormal rotation matrix to apply to k-space coordinates.
39+
40+ Returns
41+ -------
42+ image : ndarray (uint8) Binary microstructure.
4243 """
4344 np .random .seed (seed )
4445 ndim = len (shape )
@@ -47,10 +48,8 @@ def generate_spinodal_microstructure(
4748 k0_arr = np .array (k0 , dtype = np .float32 )
4849 bw_arr = np .array (bandwidth , dtype = np .float32 )
4950
50- np .random .seed (seed )
51- noise = np .random .randn (* shape ).astype (
52- np .float32 , copy = False
53- ) # Generate noise (resolution dependent)
51+ # Generate noise (resolution dependent)
52+ noise = np .random .randn (* shape ).astype (np .float32 , copy = False )
5453 noise_hat = fftn (noise , workers = - 1 , overwrite_x = True )
5554
5655 # Build k-space grids
@@ -60,14 +59,8 @@ def generate_spinodal_microstructure(
6059 ]
6160 grids = np .meshgrid (* grids , indexing = "ij" )
6261
63- # Build rotation matrix: R = [v1, v2, v3]^T
64- v1 , v2 = anisotropy_axes
65- v1 = np .array (v1 , dtype = np .float32 )
66- v2 = np .array (v2 , dtype = np .float32 )
67- v3 = np .cross (v1 , v2 )
68- R = np .array ([v1 , v2 , v3 ], dtype = np .float32 )
69-
7062 # Rotate k-space coordinates: k_rotated = R @ k_original
63+ R = np .array (rotation_matrix , dtype = np .float32 )
7164 grids = list (np .einsum ("ij,jklm->iklm" , R , np .array (grids )))
7265
7366 # Compute effective radial wavenumber using ellipsoidal normalization
@@ -116,13 +109,9 @@ def generate_spinodal_microstructure(
116109 exponent = 10.0
117110 seed = 42
118111 volume_fraction = 0.5
112+ euler_angles = [np .pi / 4 , np .pi / 4 , np .pi / 4 ]
119113
120- v1 = np .array ([1.0 , 1.0 , 1.0 ])
121- v1 /= np .linalg .norm (v1 )
122- v2 = np .array ([1.0 , - 1.0 , 0.0 ])
123- v2 /= np .linalg .norm (v2 )
124- anisotropy_axes = (v1 , v2 )
125-
114+ R = Rotation .from_euler ("xyz" , euler_angles ).as_matrix ()
126115 start_time = time ()
127116 img = generate_spinodal_microstructure (
128117 N ,
@@ -132,6 +121,7 @@ def generate_spinodal_microstructure(
132121 exponent = exponent ,
133122 seed = seed ,
134123 L = L ,
124+ rotation_matrix = R ,
135125 )
136126 end_time = time ()
137127 print (
@@ -140,12 +130,12 @@ def generate_spinodal_microstructure(
140130
141131 MS = MicrostructureImage (image = img , L = L )
142132 MS .write (
143- h5_filename = "data/spinodal_spectral .h5" ,
144- dset_name = "/spinodal_spectral " ,
133+ h5_filename = "data/spinodoids .h5" ,
134+ dset_name = "/dset_0 " ,
145135 order = "zyx" ,
146136 )
147137 write_xdmf (
148- h5_filepath = "data/spinodal_spectral .h5" ,
149- xdmf_filepath = "data/spinodal_spectral .xdmf" ,
138+ h5_filepath = "data/spinodoids .h5" ,
139+ xdmf_filepath = "data/spinodoids .xdmf" ,
150140 microstructure_length = L [::- 1 ],
151141 )
0 commit comments