@@ -47,19 +47,86 @@ void app_flux_surface(int n_theta, int n_zeta) {
47
47
return ;
48
48
}
49
49
50
+ // number of Fourier modes that can be represented with n_theta and n_zeta
51
+ // without violating Nyquist criterion
52
+ int nyq_pol = n_theta / 2 + 1 ;
53
+ int nyq_tor = n_zeta / 2 + 1 ;
50
54
55
+ if (nyq_pol < mpol ) {
56
+ printf ("n_theta too small\n" );
57
+ return ;
58
+ }
51
59
60
+ if (nyq_tor < ntor ) {
61
+ printf ("n_zeta too small\n" );
62
+ return ;
63
+ }
52
64
65
+ fftw_complex * in_R = fftw_alloc_complex (n_zeta * nyq_pol );
66
+ fftw_complex * in_Z = fftw_alloc_complex (n_zeta * nyq_pol );
67
+ double * out_R = fftw_alloc_real (n_zeta * n_theta );
68
+ double * out_Z = fftw_alloc_real (n_zeta * n_theta );
69
+
70
+ fftw_plan p_R = fftw_plan_dft_c2r_2d (n_zeta , n_theta , in_R , out_R , FFTW_ESTIMATE );
71
+ fftw_plan p_Z = fftw_plan_dft_c2r_2d (n_zeta , n_theta , in_Z , out_Z , FFTW_ESTIMATE );
72
+
73
+ fill_zero_2d_cplx (n_zeta , nyq_pol , in_R );
74
+ fill_zero_2d_cplx (n_zeta , nyq_pol , in_Z );
75
+
76
+ // copy LCFS Fourier coefficients into input array
77
+ int idx_vmec = 0 , idx_in ;
78
+ int m = 0 ;
79
+ for (int n = 0 ; n <= ntor ; ++ n ) {
80
+
81
+ // compute target index for input array
82
+ if (n <= 0 ) {
83
+ idx_in = - n * nyq_pol + m ;
84
+ } else {
85
+ idx_in = (n_zeta - n ) * nyq_pol + m ;
86
+ }
87
+
88
+ // VMEC: for m=0, only positive ntor --> summed up within VMEC definition with negative-n --> 2*0.5 = 1
89
+ // also for sin-parity quantities: m=0 would imply (m theta -n zeta) == (-n zeta), but VMEC uses (n zeta) for m=0
90
+ // --> does not matter for cos-parity since cos(-n zeta) = cos(n zeta), but sin(-n zeta) = -sin(n zeta)
91
+ // and hence the additional -1 cancels out by compensating the -1 from the complex multiply in the DFT definition
92
+ in_R [idx_in ] = rmnc [idx_vmec ];
93
+ in_Z [idx_in ] = I * zmns [idx_vmec ];
94
+
95
+ idx_vmec ++ ;
96
+ }
53
97
98
+ for (m = 1 ; m < mpol ; ++ m ) {
99
+ for (int n = - ntor ; n <= ntor ; ++ n ) {
54
100
101
+ // compute target index for input array
102
+ if (n <= 0 ) {
103
+ idx_in = - n * nyq_pol + m ;
104
+ } else {
105
+ idx_in = (n_zeta - n ) * nyq_pol + m ;
106
+ }
55
107
108
+ // scale coefficients by 0.5 since FFTW implies
109
+ // that coeffs for m<0 were present in the logically equivalent DFT input
110
+ // which is not the case for VMEC output
111
+ in_R [idx_in ] = 0.5 * rmnc [idx_vmec ];
112
+ in_Z [idx_in ] = -0.5 * I * zmns [idx_vmec ];
56
113
114
+ idx_vmec ++ ;
115
+ }
116
+ }
57
117
118
+ fftw_execute (p_R );
119
+ fftw_execute (p_Z );
58
120
121
+ dump_2d_real ("lcfs_R.dat" , n_zeta , n_theta , out_R );
122
+ dump_2d_real ("lcfs_Z.dat" , n_zeta , n_theta , out_Z );
59
123
60
-
61
-
62
-
124
+ fftw_destroy_plan (p_R );
125
+ fftw_destroy_plan (p_Z );
126
+ fftw_free (in_R );
127
+ fftw_free (in_Z );
128
+ fftw_free (out_R );
129
+ fftw_free (out_Z );
63
130
}
64
131
65
132
int main (int argc , char * * argv ) {
0 commit comments