1010def generate_spinodal_microstructure (
1111 shape : Union [Tuple [int , int , int ], List [int ]],
1212 volume_fraction : float = 0.5 ,
13- k0 : Union [Tuple [float , float , float ], List [float ]] = (6.0 , 6.0 , 6.0 ),
14- bandwidth : Union [Tuple [float , float , float ], List [float ]] = (0.6 , 0.6 , 0.6 ),
15- exponent : float = 2.0 ,
13+ wavenumber : Union [Tuple [float , float , float ], List [float ]] = (6.0 , 6.0 , 6.0 ),
14+ sigma : float = 0.5 ,
1615 seed : int = 42 ,
1716 L : Union [Tuple [float , float , float ], List [float ]] = (1.0 , 1.0 , 1.0 ),
18- rotation_matrix : Optional [np .ndarray ] = np . eye ( 3 , dtype = np . float32 ) ,
17+ rotation_matrix : Optional [np .ndarray ] = None ,
1918):
2019 """Generate a binary spinodal microstructure via spectral filtering.
2120
@@ -24,29 +23,31 @@ def generate_spinodal_microstructure(
2423 shape : tuple or list
2524 Grid size (nz, ny, nx).
2625 volume_fraction : float, default 0.5
27- Target volume fraction of the phase 1.
28- k0 : array-like, default [6.0, 6.0, 6.0]
29- Center wavenumber in cycles per domain (not angular) for each axis [k0_1, k0_2, k0_3].
30- bandwidth : array-like, default [0.6, 0.6, 0.6]
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).
26+ Target volume fraction of phase 1.
27+ wavenumber : array-like, default [6.0, 6.0, 6.0]
28+ Center wavenumber in cycles per domain for each axis [k1, k2, k3].
29+ sigma : float, default 0.5
30+ Standard deviation of Gaussian bandpass filter (in normalized k-space).
3431 seed : int, default 42
35- RNG seed for reproducibility.
32+ Random seed for reproducibility.
3633 L : array-like, default [1.0, 1.0, 1.0]
37- rotation_matrix : ndarray (ndim x ndim), default identity
38- Orthonormal rotation matrix to apply to k-space coordinates.
34+ Physical domain dimensions [Lx, Ly, Lz].
35+ rotation_matrix : ndarray (3x3), optional
36+ Orthonormal rotation matrix for orienting anisotropic features.
37+ If None, uses identity (no rotation).
3938
4039 Returns
4140 -------
42- image : ndarray (uint8) Binary microstructure.
41+ image : ndarray (uint8)
42+ Binary microstructure with values 0 and 1.
4343 """
4444 np .random .seed (seed )
4545 ndim = len (shape )
4646 L = np .array (L , dtype = np .float32 )
4747 dx_arr = L / np .array (shape , dtype = np .float32 )
48- k0_arr = np .array (k0 , dtype = np .float32 )
49- bw_arr = np .array (bandwidth , dtype = np .float32 )
48+ wavenumber_arr = np .array (wavenumber , dtype = np .float32 )
49+ if rotation_matrix is None :
50+ rotation_matrix = np .eye (ndim , dtype = np .float32 )
5051
5152 # Generate noise (resolution dependent)
5253 noise = np .random .randn (* shape ).astype (np .float32 , copy = False )
@@ -65,25 +66,18 @@ def generate_spinodal_microstructure(
6566
6667 # Compute effective radial wavenumber using ellipsoidal normalization
6768 k2_normalized = sum (
68- (grids [i ] / ((np .float32 (2.0 * np .pi ) * k0_arr [i ]) / L [i ])) ** 2
69+ (grids [i ] / ((np .float32 (2.0 * np .pi ) * wavenumber_arr [i ]) / L [i ])) ** 2
6970 for i in range (ndim )
7071 )
7172 k = np .sqrt (k2_normalized )
72- k0_ref = np .float32 (1.0 ) # Reference wavenumber is 1 after normalization
7373
7474 del grids
7575
76- # Bandpass filter
77- # Use mean bandwidth for the Gaussian envelope
78- sigma = np .float32 (np .mean (bw_arr ) * k0_ref )
79- k_diff = k - k0_ref
80- filter_amp = np .exp (- 0.5 * (k_diff / sigma ) ** 2 )
76+ # Gaussian bandpass filter centered at k=1 (in normalized space)
77+ k_diff = k - np .float32 (1.0 )
78+ filter_amp = np .exp (- 0.5 * (k_diff / np .float32 (sigma )) ** 2 )
8179
82- # High-k rolloff (in-place multiplication)
83- k_ratio = k / k0_ref
84- filter_amp *= 1.0 / (1.0 + k_ratio ** exponent )
85-
86- del k , k_diff , k_ratio
80+ del k , k_diff
8781
8882 # Apply filter in-place
8983 noise_hat *= filter_amp
@@ -104,21 +98,19 @@ def generate_spinodal_microstructure(
10498
10599 N = [256 , 256 , 256 ]
106100 L = [1.0 , 1.0 , 1.0 ]
107- k0 = [5.0 , 20.0 , 20.0 ]
108- bandwidth = [0.1 , 0.1 , 0.1 ]
109- exponent = 10.0
101+ wavenumber = [20.0 , 20.0 , 20.0 ]
102+ sigma = 0.01
110103 seed = 42
111104 volume_fraction = 0.5
112- euler_angles = [np . pi / 4 , np . pi / 4 , np . pi / 4 ]
105+ euler_angles = [0 , 0 , 0 ]
113106
114107 R = Rotation .from_euler ("xyz" , euler_angles ).as_matrix ()
115108 start_time = time ()
116109 img = generate_spinodal_microstructure (
117110 N ,
118111 volume_fraction = volume_fraction ,
119- k0 = k0 ,
120- bandwidth = bandwidth ,
121- exponent = exponent ,
112+ wavenumber = wavenumber ,
113+ sigma = sigma ,
122114 seed = seed ,
123115 L = L ,
124116 rotation_matrix = R ,
0 commit comments