Beispiel #1
0
/******************************************
** Enforce the real mask ******************
*******************************************/
void enforce_real_mask(struct Field fldi) {
	int i;
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		w1[i] =  fldi.vx[i];
		w2[i] =  fldi.vy[i];
		w3[i] =  fldi.vz[i];
	}
	gfft_c2r_t(w1);
	gfft_c2r_t(w2);
	gfft_c2r_t(w3);
	
	for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
		wr1[i] = wr1[i] * mask_real[i] / ((double) NTOTAL);
		wr2[i] = wr2[i] * mask_real[i] / ((double) NTOTAL);
		wr3[i] = wr3[i] * mask_real[i] / ((double) NTOTAL);
	}
	
	gfft_r2c_t(wr1);
	gfft_r2c_t(wr2);
	gfft_r2c_t(wr3);
	
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		fldi.vx[i] = w1[i] * mask[i];
		fldi.vy[i] = w2[i] * mask[i];
		fldi.vz[i] = w3[i] * mask[i];
	}
	
	return;
}
Beispiel #2
0
void gfft_r2c(double *wrin) {
	fft_timer = fft_timer - get_c_time();
	transpose_real(NX, NY, NZ+2, NPROC, wrin, wrin);
	gfft_r2c_t(wrin);
	fft_timer = fft_timer + get_c_time();
	return;
}
Beispiel #3
0
void timestep( struct Field dfldo,
			   struct Field fldi,
			   const double t,
			   const double tremap,
			   const double dt) {
			   
	int i;
	double complex q0,q1;
	double qr0;
	double S, gamma, epsilon,w;
	double costheta,sintheta;
	int j,k; //AJB

	// This is the timesteping algorithm, solving the physics.

	// Find the shear at time t
#ifdef WITH_SHEAR
#ifdef TIME_DEPENDANT_SHEAR
	S = param.shear * cos(param.omega_shear * t);	// This is the real shear: -dvy/dx
#else
	S = param.shear;
#endif
#endif
#ifdef WITH_ELLIPTICAL_VORTEX //AJB
	gamma = param.gamma;
	epsilon = param.epsilon;
	w = sqrt(gamma*gamma-epsilon*epsilon);
#endif
#ifdef WITH_ROTATION //AJB
	if(param.theta==0.0) {
	  costheta=1.0;
	  sintheta=0.0; //just in case not exact below...
	} else {
	  costheta=cos(param.theta*M_PI/180.0);
	  sintheta=sin(param.theta*M_PI/180.0);
	}
#endif

/* #ifdef ELSASSER_FORMULATION */
/* /\****************************************** */
/* ** ELSASSER variable formulation ********** */
/* ** To be used  */
/* *******************************************\/ */

/* // Solve the MHD equations using Elsasser fields */
/* #ifdef _OPENMP */
/* 	#pragma omp parallel for private(i) schedule(static)	 */
/* #endif */
/* 	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) { */
/* 		w1[i] =  fldi.vx[i]+fldi.bx[i]; */
/* 		w2[i] =  fldi.vy[i]+fldi.by[i]; */
/* 		w3[i] =  fldi.vz[i]+fldi.bz[i]; */
		
/* 		w4[i] =  fldi.vx[i]-fldi.bx[i]; */
/* 		w5[i] =  fldi.vy[i]-fldi.by[i]; */
/* 		w6[i] =  fldi.vz[i]-fldi.bz[i]; */
/* 	} */
	
/* 	// These fields should have no divergence. */
/* 	// When shear is on, however, divergence is conserved up to the timeintegrator precision. */
/* 	// Let's clean it. */
/* 	projector(w1,w2,w3); */
/* 	projector(w4,w5,w6); */

/* 	gfft_c2r_t(w1); */
/* 	gfft_c2r_t(w2); */
/* 	gfft_c2r_t(w3); */
	
/* 	gfft_c2r_t(w4); */
/* 	gfft_c2r_t(w5); */
/* 	gfft_c2r_t(w6); */
	
/* // Compute the Elsasser tensor */

/* #ifdef _OPENMP */
/* 	#pragma omp parallel for private(i) schedule(static)	 */
/* #endif */
/* 	for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) { */
/* 		wr7[i]  = wr1[i] * wr4[i] / ((double) NTOTAL*NTOTAL); */
/* 		wr8[i]  = wr1[i] * wr5[i] / ((double) NTOTAL*NTOTAL); */
/* 		wr9[i]  = wr1[i] * wr6[i] / ((double) NTOTAL*NTOTAL); */
/* 		wr10[i] = wr2[i] * wr4[i] / ((double) NTOTAL*NTOTAL); */
/* 		wr11[i] = wr2[i] * wr5[i] / ((double) NTOTAL*NTOTAL); */
/* 		wr12[i] = wr2[i] * wr6[i] / ((double) NTOTAL*NTOTAL); */
/* 		wr13[i] = wr3[i] * wr4[i] / ((double) NTOTAL*NTOTAL); */
/* 		wr14[i] = wr3[i] * wr5[i] / ((double) NTOTAL*NTOTAL); */
/* 		wr15[i] = wr3[i] * wr6[i] / ((double) NTOTAL*NTOTAL); */
/* 	} */
	
/* 	gfft_r2c_t(wr7); */
/* 	gfft_r2c_t(wr8); */
/* 	gfft_r2c_t(wr9); */
/* 	gfft_r2c_t(wr10); */
/* 	gfft_r2c_t(wr11); */
/* 	gfft_r2c_t(wr12); */
/* 	gfft_r2c_t(wr13); */
/* 	gfft_r2c_t(wr14); */
/* 	gfft_r2c_t(wr15); */
	
/* // Compute the volution of the Elssaser fields (u= ik. */
/* #ifdef _OPENMP */
/* 	#pragma omp parallel for private(i) schedule(static)	 */
/* #endif */
/* 	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) { */
/* 		dfldo.vx[i] = - I * 0.5 * mask[i] * ( */
/* 						kxt[i] * ( 2.0 * w7[i]  ) + kyt[i] * ( w8[i] + w10[i]) + kzt[i] * (w9[i]  + w13[i]) ); */
/* 		dfldo.vy[i] = - I * 0.5 * mask[i] * ( */
/* 						kxt[i] * (w10[i] + w8[i]) + kyt[i] * ( 2.0   * w11[i]) + kzt[i] * (w12[i] + w14[i]) ); */
/* 		dfldo.vz[i] = - I * 0.5 * mask[i] * ( */
/* 						kxt[i] * (w13[i] + w9[i]) + kyt[i] * (w14[i] + w12[i]) + kzt[i] * ( 2.0 * w15[i]  ) ); */
		
										
/* 		dfldo.bx[i] = - I * 0.5 * mask[i] * ( */
/* 						                            kyt[i] * ( w8[i] - w10[i]) + kzt[i] * (w9[i]  - w13[i]) ); */
/* 		dfldo.by[i] = - I * 0.5 * mask[i] * ( */
/* 						kxt[i] * (w10[i] - w8[i])                             + kzt[i] * (w12[i] - w14[i]) ); */
/* 		dfldo.bz[i] = - I * 0.5 * mask[i] * ( */
/* 						kxt[i] * (w13[i] - w9[i]) + kyt[i] * (w14[i] - w12[i])  ); */
		

/* 	} */
		
/* // Compute real(U) in case it is used later. */
/* 	for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) { */
/* 		wr1[i] = 0.5 * (wr1[i] + wr4[i]); */
/* 		wr2[i] = 0.5 * (wr2[i] + wr5[i]); */
/* 		wr3[i] = 0.5 * (wr3[i] + wr6[i]); */
/* 	} */

/* #else */
/******************************************
** Velocity Self Advection ****************
*******************************************/

		/* Compute the convolution */
#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)	
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		w1[i] =  fldi.vx[i];
		w2[i] =  fldi.vy[i];
		w3[i] =  fldi.vz[i];
	}

	// These fields should have no divergence.
	// When shear is on, however, divergence is conserved up to the timeintegrator precision.
	// Let's clean it.
	projector(w1,w2,w3);
	
	gfft_c2r_t(w1);
	gfft_c2r_t(w2);
	gfft_c2r_t(w3);
	
	/* Compute the convolution for the advection process */
	
#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)	
#endif
	for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
		wr4[i] = wr1[i] * wr1[i] / ((double) NTOTAL*NTOTAL);
		wr5[i] = wr2[i] * wr2[i] / ((double) NTOTAL*NTOTAL);
#ifndef WITH_2D
		wr6[i] = wr3[i] * wr3[i] / ((double) NTOTAL*NTOTAL);
#endif
		wr7[i] = wr1[i] * wr2[i] / ((double) NTOTAL*NTOTAL);
		wr8[i] = wr1[i] * wr3[i] / ((double) NTOTAL*NTOTAL);
		wr9[i] = wr2[i] * wr3[i] / ((double) NTOTAL*NTOTAL);
	}
	
	gfft_r2c_t(wr4);
	gfft_r2c_t(wr5);
#ifndef WITH_2D
	gfft_r2c_t(wr6);
#endif
	gfft_r2c_t(wr7);
	gfft_r2c_t(wr8);
	gfft_r2c_t(wr9);

#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)	
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
	  dfldo.vx[i] = - I * mask[i] * ( kxt[i] * w4[i] + kyt[i] * w7[i] + kzt[i] * w8[i] );
	  dfldo.vy[i] = - I * mask[i] * ( kxt[i] * w7[i] + kyt[i] * w5[i] + kzt[i] * w9[i] );
	  dfldo.vz[i] = - I * mask[i] * ( kxt[i] * w8[i] + kyt[i] * w9[i] + kzt[i] * w6[i] );	// since kz=0 in 2D, kz*w6 gives 0, even if w6 is some random array

	} 

	if(param.nonlinearoff) { //AJB turn off nonlinearities
	  for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
	    dfldo.vx[i] = 0.0;
	    dfldo.vy[i] = 0.0;
	    dfldo.vz[i] = 0.0;
	  }
	}
	
/* #endif */

/**********************************************
** BOUSSINESQ TERMS (if needed) ***************
***********************************************/

#ifdef BOUSSINESQ
#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		w4[i] = fldi.th[i];
	}
	
	gfft_c2r_t(w4);
		
#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
		wr5[i] = wr1[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
		wr6[i] = wr2[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
#ifndef WITH_2D
		wr7[i] = wr3[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
#endif
#ifdef N2PROFILE
		wr8[i] = N2_profile[i] * wr4[i] / ((double) NTOTAL);
#endif
	}
	gfft_r2c_t(wr5);
	gfft_r2c_t(wr6);
#ifndef WITH_2D
	gfft_r2c_t(wr7);
#endif
#ifdef N2PROFILE
	gfft_r2c_t(wr8);
#endif

#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
#ifdef VERTSTRAT
#ifdef N2PROFILE
		dfldo.vz[i] -= w8[i] * mask[i];
#else
		//dfldo.vz[i] -= param.N2 * fldi.th[i];
                dfldo.vz[i] += fldi.th[i];
#endif
		dfldo.th[i] = - I*mask[i]*(
			kxt[i]*w5[i]+kyt[i]*w6[i]+kzt[i]*w7[i])
			- param.N2*fldi.vz[i];		
		/* dfldo.th[i] = - I * mask[i] * ( */
		/* 	kxt[i] * w5[i] + kyt[i] * w6[i] + kzt[i] * w7[i]) */
		/* 	+ fldi.vz[i]; */
#else //not vertstrat
#ifdef N2PROFILE
		dfldo.vx[i] -= w8[i] * mask[i];
#else
		//	dfldo.vx[i] -= param.N2 * fldi.th[i];
		dfldo.vx[i] += fldi.th[i];
#endif
		dfldo.th[i] = -I*mask[i]*(
		   kxt[i]*w5[i]+kyt[i]*w6[i]+kzt[i]*w7[i])
			- param.N2*fldi.vx[i];		
/* 		dfldo.th[i] = - I*mask[i]*( */
/* 			kxt[i]*w5[i]+kyt[i]*w6[i]+kzt[i]*w7[i]) */
/* 			+ fldi.vx[i]; */
#endif //vertstrat
	}
	
	
#endif

/*********************************************
**** MHD Terms (if needed)   *****************
*********************************************/
#ifdef MHD
#ifndef ELSASSER_FORMULATION		// If Elssaser is on, MHD are already computed...

// Start with the induction equation
#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		w4[i] =  fldi.bx[i];
		w5[i] =  fldi.by[i];
		w6[i] =  fldi.bz[i];
	}

	// These fields should have no divergence.
	// When shear is on, however, divergence is conserved up to the timeintegrator precision.
	// Let's clean it.
	projector(w4,w5,w6);
	
	gfft_c2r_t(w4);
	gfft_c2r_t(w5);
	gfft_c2r_t(w6);
	
	// (vx,vy,vz) is in w1-w3 and (bx,by,bz) is in (w4-w6). It is now time to compute the emfs in w7-w9...
#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
		wr7[i] = (wr2[i] * wr6[i] - wr3[i] * wr5[i]) / ((double) NTOTAL*NTOTAL);
		wr8[i] = (wr3[i] * wr4[i] - wr1[i] * wr6[i]) / ((double) NTOTAL*NTOTAL);
		wr9[i] = (wr1[i] * wr5[i] - wr2[i] * wr4[i]) / ((double) NTOTAL*NTOTAL);
	}

	// Compute the curl of the emf to add in the induction equation.
	
	gfft_r2c_t(wr7);
	gfft_r2c_t(wr8);
	gfft_r2c_t(wr9);

#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		dfldo.bx[i] = I * mask[i] * (kyt[i] * w9[i] - kzt[i] * w8[i]);
		dfldo.by[i] = I * mask[i] * (kzt[i] * w7[i] - kxt[i]* w9[i]);
		dfldo.bz[i] = I * mask[i] * (kxt[i]* w8[i] - kyt[i] * w7[i]);

#ifdef WITH_ELLIPTICAL_VORTEX //AJB 02/02/12
		dfldo.bx[i] -= (gamma+epsilon)*fldi.by[i];
		dfldo.by[i] -= -(gamma-epsilon)*fldi.bx[i];
#endif

	}


// Let's do the Lorentz Force
// We already have (bx,by,bz) in w4-w6. No need to compute them again...

#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
		wr1[i] = wr4[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
		wr2[i] = wr5[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
		wr3[i] = wr6[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
		wr7[i] = wr4[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
		wr8[i] = wr4[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
		wr9[i] = wr5[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
	}


	gfft_r2c_t(wr1);
	gfft_r2c_t(wr2);
	gfft_r2c_t(wr3);
	gfft_r2c_t(wr7);
	gfft_r2c_t(wr8);
	gfft_r2c_t(wr9);

#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		dfldo.vx[i] += I * mask[i] * (kxt[i] * w1[i] + kyt[i] * w7[i] + kzt[i] * w8[i]);
		dfldo.vy[i] += I * mask[i] * (kxt[i] * w7[i] + kyt[i] * w2[i] + kzt[i] * w9[i]);
		dfldo.vz[i] += I * mask[i] * (kxt[i] * w8[i] + kyt[i] * w9[i] + kzt[i] * w3[i]);
	}
	
#endif
#endif

/************************************
** SOURCE TERMS  ********************
************************************/

#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
#ifdef WITH_ROTATION //AJB modified for tilted rotation in xz-plane
	  dfldo.vx[i]+=2.0*param.omega*fldi.vy[i]*costheta;
	  dfldo.vy[i]-=2.0*param.omega*(fldi.vx[i]*costheta-fldi.vz[i]*sintheta);
	  dfldo.vz[i]-=2.0*param.omega*fldi.vy[i]*sintheta;
#endif
#ifdef WITH_SHEAR
		dfldo.vy[i] += S  * fldi.vx[i];
#ifdef MHD
		dfldo.by[i] -= S * fldi.bx[i];
#endif
#endif
#ifdef WITH_ELLIPTICAL_VORTEX //AJB
		dfldo.vx[i] += (gamma+epsilon)*fldi.vy[i];
		dfldo.vy[i] += -(gamma-epsilon)*fldi.vx[i];
#endif
	}
	
/************************************
** EXPLICIT LINEAR DISSIPATION ******
*************************************/

/* #ifdef WITH_EXPLICIT_DISSIPATION */
/* #ifdef _OPENMP */
/* 	#pragma omp parallel for private(i) schedule(static) */
/* #endif */
/* 	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) { */
/* 		dfldo.vx[i] += - nu * k2t[i] * fldi.vx[i]; */
/* 		dfldo.vy[i] += - nu * k2t[i] * fldi.vy[i]; */
/* 		dfldo.vz[i] += - nu * k2t[i] * fldi.vz[i]; */
		
/* #ifdef MHD */
/* 		dfldo.bx[i] += - eta * k2t[i] * fldi.bx[i]; */
/* 		dfldo.by[i] += - eta * k2t[i] * fldi.by[i]; */
/* 		dfldo.bz[i] += - eta * k2t[i] * fldi.bz[i]; */
/* #endif	// MHD */

/* #ifdef BOUSSINESQ */
/* 		dfldo.th[i] += - nu_th * k2t[i] * fldi.th[i]; */
/* #endif	// BOUSSINESQ */
/* 	} */

/* #endif	// WITH_EXPLICIT_DISSIPATION */
	
/************************************
** PRESSURE TERMS *******************
************************************/

#ifdef _OPENMP
	#pragma omp parallel for private(i,q0,q1) schedule(static)
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
			
#ifdef WITH_SHEAR
	  q0= S * ky[i] * fldi.vx[i] + kxt[i] * dfldo.vx[i] + ky[i] * dfldo.vy[i] + kzt[i] * dfldo.vz[i];
#ifdef WITH_ELLIPTICAL_VORTEX //AJB
	    q0 = (gamma+epsilon)*kxt[i]*fldi.vy[i]-(gamma-epsilon)*kyt[i]*fldi.vx[i] + kxt[i]*dfldo.vx[i] + kyt[i]*dfldo.vy[i] + kzt[i]*dfldo.vz[i];	  
#endif
#else
	  q0= kxt[i] * dfldo.vx[i] + kyt[i] * dfldo.vy[i] + kzt[i] * dfldo.vz[i];
#endif
/* po would contain the pressure field
		if(po != NULL) {
			po[i] = - I * ik2t[i] * q0;	// Save the pressure field (if needed)
		}
*/
		dfldo.vx[i] += -kxt[i]* q0 * ik2t[i];
		dfldo.vy[i] += -kyt[i]* q0 * ik2t[i];
		dfldo.vz[i] += -kzt[i]* q0 * ik2t[i];
	}

	return;
}
void u_iii_forcing(struct Field fldi, double dt) {
	double *x, *y, *z;		 	
	int i,j,k;

	x = (double *) fftw_malloc( sizeof(double complex) * NTOTAL_COMPLEX);
	if (x == NULL) ERROR_HANDLER( ERROR_CRITICAL, "No memory for x allocation");
	
	y = (double *) fftw_malloc( sizeof(double complex) * NTOTAL_COMPLEX);
	if (y == NULL) ERROR_HANDLER( ERROR_CRITICAL, "No memory for y allocation");
	
	z = (double *) fftw_malloc( sizeof(double complex) * NTOTAL_COMPLEX);
	if (z == NULL) ERROR_HANDLER( ERROR_CRITICAL, "No memory for z allocation");

	// Initialize the arrays
	
	for(i = 0 ; i < NX/NPROC ; i++) {
		for(j = 0 ; j < NY ; j++) {
			for(k = 0 ; k < NZ ; k++) {
				x[k + (NZ + 2) * j + (NZ + 2) * NY * i] = - param.lx / 2 + (param.lx * (i + rank * NX / NPROC)) / NX;
				y[k + (NZ + 2) * j + (NZ + 2) * NY * i] = - param.ly / 2 + (param.ly * j ) / NY;
				z[k + (NZ + 2) * j + (NZ + 2) * NY * i] = - param.lz / 2 + (param.lz * k ) / NZ;
			}
		}
	}
	
	// Initialize the extra points (k=NZ and k=NZ+1) to zero to prevent stupid things from happening...
	for(i = 0 ; i < NX/NPROC ; i++) {
		for(j = 0 ; j < NY ; j++) {
			for(k = NZ ; k < NZ + 2 ; k++) {
				x[k + (NZ + 2) * j + (NZ + 2) * NY * i] = 0.0;
				y[k + (NZ + 2) * j + (NZ + 2) * NY * i] = 0.0;
				z[k + (NZ + 2) * j + (NZ + 2) * NY * i] = 0.0;

			}
		}
	}
	
	// Init work array to zero
	for(i = 0 ; i < NX/NPROC ; i++) {
		for(j = 0 ; j < NY ; j++) {
			for(k = 0 ; k < NZ + 2 ; k++) {
				wr4[k + (NZ + 2) * j + (NZ + 2) * NY * i] = 0.0;
				wr5[k + (NZ + 2) * j + (NZ + 2) * NY * i] = 0.0;
				wr6[k + (NZ + 2) * j + (NZ + 2) * NY * i] = 0.0;
   			}
		}
   }

    /*******************************************************************
	** This part can be modified              **************************
	********************************************************************/
	
	// The velocity field vx,vy,vz is stored in wr1,wr2,wr3
   	for(i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
     
        wr4[i] = param.modified_ABC_flow_D*(
                    cos(x[i]/param.modified_ABC_flow_m)*(
                        param.modified_ABC_flow_A*param.modified_ABC_flow_kz*sin(z[i] /(double) param.modified_ABC_flow_kz ) +
                        param.modified_ABC_flow_C*param.modified_ABC_flow_ky*cos(y[i] /(double) param.modified_ABC_flow_ky)
                    ) + 
                    sin(x[i]/param.modified_ABC_flow_m)/param.modified_ABC_flow_m*(
                        0
                    )                                         
                ); 
        wr5[i] = param.modified_ABC_flow_D*(
                    cos(x[i]/param.modified_ABC_flow_m)*(
                        param.modified_ABC_flow_B*param.modified_ABC_flow_kx*sin(x[i] /(double) param.modified_ABC_flow_kx ) +
                        param.modified_ABC_flow_A*param.modified_ABC_flow_kz*cos(z[i] /(double) param.modified_ABC_flow_kz)
                    ) + 
                    sin(x[i]/param.modified_ABC_flow_m)/param.modified_ABC_flow_m*(
                        param.modified_ABC_flow_B*cos(x[i] /(double) param.modified_ABC_flow_kx) + 
                        param.modified_ABC_flow_C*sin(y[i] /(double) param.modified_ABC_flow_ky)
                    )                                         
                );
        wr6[i] = param.modified_ABC_flow_D*(
                    cos(x[i]/param.modified_ABC_flow_m)*(
                        param.modified_ABC_flow_C*param.modified_ABC_flow_ky*sin(y[i] /(double) param.modified_ABC_flow_ky ) +
                        param.modified_ABC_flow_B*param.modified_ABC_flow_kx*cos(x[i] /(double) param.modified_ABC_flow_kx)
                    ) + 
                    sin(x[i]/param.modified_ABC_flow_m)/param.modified_ABC_flow_m*(
                        -param.modified_ABC_flow_A*cos(z[i] /(double) param.modified_ABC_flow_kz) + 
                        -param.modified_ABC_flow_B*sin(x[i] /(double) param.modified_ABC_flow_kx)
                    )                                         
                );
    }
    gfft_r2c(wr4);
	gfft_r2c(wr5);
    gfft_r2c(wr6);
	
    for(i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		w4[i] = w4[i] * mask[i];
		w5[i] = w5[i] * mask[i];
		w6[i] = w6[i] * mask[i];
    }   

	for( i = 0; i < NX_COMPLEX/NPROC; i++) {
		for( j = 0; j < NY_COMPLEX; j++) {
			for( k = 0; k < NZ_COMPLEX; k++) {
				fldi.vx[ IDX3D ] +=  w4[ IDX3D ] * (1 - exp(-nu*k2t[IDX3D]*dt)) ;
				fldi.vy[ IDX3D ] +=  w5[ IDX3D ] * (1 - exp(-nu*k2t[IDX3D]*dt)) ;
				fldi.vz[ IDX3D ] +=  w6[ IDX3D ] * (1 - exp(-nu*k2t[IDX3D]*dt)) ;
			}
		}
	}

#ifdef U_III_FORCING_EXTRA
    gfft_c2r_t(w4);
	gfft_c2r_t(w5);
	gfft_c2r_t(w6);

#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)	
#endif
	for( i = 0 ; i < 2*NTOTAL_COMPLEX ; i++) {
		wr10[i] = wr4[i] * wr4[i] / ((double) NTOTAL*NTOTAL);
		wr11[i] = wr5[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
#ifndef WITH_2D
		wr12[i] = wr6[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
#endif
		wr7[i] = wr4[i] * wr5[i] / ((double) NTOTAL*NTOTAL);
		wr8[i] = wr4[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
		wr9[i] = wr5[i] * wr6[i] / ((double) NTOTAL*NTOTAL);
	}
	
	gfft_r2c_t(wr10);
	gfft_r2c_t(wr11);
#ifndef WITH_2D
	gfft_r2c_t(wr12);
#endif
	gfft_r2c_t(wr7);
	gfft_r2c_t(wr8);
	gfft_r2c_t(wr9);

#ifdef _OPENMP
	#pragma omp parallel for private(i) schedule(static)	
#endif
	for( i = 0 ; i < NTOTAL_COMPLEX ; i++) {
		fldi.vx[i] +=  I * mask[i] / (nu * k2t) * (1 - exp(-nu*k2t[IDX3D]*dt)) * (
					kxt[i] * w10[i] + ky[i] * w7[i] + kz[i] * w8[i] );
		fldi.vy[i] +=  I * mask[i] / (nu * k2t) * (1 - exp(-nu*k2t[IDX3D]*dt)) * (
					kxt[i] * w7[i] + ky[i] * w11[i] + kz[i] * w9[i] );
		fldi.vz[i] +=  I * mask[i] / (nu * k2t) * (1 - exp(-nu*k2t[IDX3D]*dt)) * (
					kxt[i] * w8[i] + ky[i] * w9[i] + kz[i] * w12[i] );	// since kz=0 in 2D, kz*w6 gives 0, even if w6 is some random array
	}

#endif

	projector(fldi.vx,fldi.vy,fldi.vz);	
	return;
}