@@ -45,7 +45,7 @@ def calculate_fr(
4545
4646 :param sq_pattern: Structure factor S(Q) with lim_inf S(Q) = 1 and unit(q)=A^-1
4747 :param r: numpy array giving the r-values for which F(r) will be calculated,
48- default is 0 to 10 with 0.01 as a step. units should be in Angstrom.
48+ default is 0.01 to 10 with 0.01 as a step. units should be in Angstrom.
4949 :param use_modification_fcn: boolean flag whether to use the Lorch modification function
5050 :param method: determines the method used for calculating fr, possible values are:
5151 - 'integral' solves the Fourier integral, by calculating the integral
@@ -54,7 +54,8 @@ def calculate_fr(
5454 :return: F(r) pattern
5555 """
5656 if r is None :
57- r = np .linspace (0.01 , 10 , 1000 )
57+ r = np .arange (0.0 , 10.005 , 0.01 )
58+ r [0 ] = 1e-10 # to avoid division by zero
5859
5960 q , sq = sq_pattern .data
6061 if use_modification_fcn :
@@ -75,12 +76,22 @@ def calculate_fr(
7576 r_step = r [1 ] - r [0 ]
7677
7778 n_out = np .max ([len (q ), int (np .pi / (r_step * q_step ))])
78- q_max_for_ifft = 2 * n_out * q_step
79- y_for_ifft = np .concatenate (
80- (modification * q * (sq - 1 ), np .zeros (2 * n_out - len (q )))
81- )
79+ n_out = 2 ** int (np .ceil (np .log2 (n_out )))
80+
81+ # find the number of q points needed to resolve the r-space
82+ q_max_target = 2 * np .pi / r_step
83+ n_target = int (np .ceil (q_max_target / q_step ))
84+
85+ # Round up to the next power of 2 for fastest possible fft
86+ n_out = 2 ** int (np .ceil (np .log2 (n_target )))
87+
88+ q_max_for_ifft = n_out * q_step
89+
90+ f_q = modification * q * (sq - 1 )
91+ y_for_ifft = np .zeros (n_out )
92+ y_for_ifft [: len (f_q )] = f_q
8293
83- ifft_result = np .fft .ifft (y_for_ifft ) * 2 / np .pi * q_max_for_ifft
94+ ifft_result = np .fft .ifft (y_for_ifft ) * 2 * q_max_for_ifft / np .pi
8495 ifft_imag = np .imag (ifft_result )[:n_out ]
8596 ifft_x_step = 2 * np .pi / q_max_for_ifft
8697 ifft_x = np .arange (n_out ) * ifft_x_step
0 commit comments