Example #1
0
int
gmx_parallel_3dfft(gmx_parallel_3dfft_t    pfft_setup,
                   enum gmx_fft_direction  dir,
                   void *                  in_data,
                   void *                  out_data)
{
    int          i,j,k;
    int          nx,ny,nz,nzc,nzr;
    int          local_x_start,local_nx;
    int          local_y_start,local_ny;    
    t_complex *  work;
    real *       rdata;
    t_complex *  cdata;
    t_complex *  ctmp;
    
    work    = pfft_setup->work;
    
    /* When we do in-place FFTs the data need to be embedded in the z-dimension,
     * so there is room for the complex data. This means the direct space
     * _grid_ (not data) dimensions will be nx*ny*(nzc*2), where nzc=nz/2+1.
     * If we do out-of-place transforms the direct space dimensions are simply
     * nx*ny*nz, and no embedding is used.
     * The complex dimensions are always ny*nx*nzc (note the transpose).
     *
     * The direct space _grid_ dimension is nzr.
     */
    
    nx  = pfft_setup->nx;
    ny  = pfft_setup->ny;
    nz  = pfft_setup->nz;
    nzc = pfft_setup->nzc;
    
    if(in_data == out_data)
    {
        nzr = 2*nzc;
    }
    else
    {
        nzr = nz;
    }

    gmx_parallel_3dfft_limits(pfft_setup,
                              &local_x_start,
                              &local_nx,
                              &local_y_start,
                              &local_ny);

    if(dir == GMX_FFT_REAL_TO_COMPLEX)
    {
        rdata =      (real *)in_data  + local_x_start*ny*nzr;
        cdata = (t_complex *)out_data + local_x_start*ny*nzc;
        
        /* Perform nx local 2D real-to-complex FFTs in the yz slices.
         * When the input data is "embedded" for 3D-in-place transforms, this
         * must also be done in-place to get the data embedding right.
         * 
         * Note that rdata==cdata when we work in-place. 
         */
        for(i=0;i<local_nx;i++)
        {
            gmx_fft_2d_real(pfft_setup->fft_yz,
                            GMX_FFT_REAL_TO_COMPLEX,
                            rdata + i*ny*nzr,
                            cdata + i*ny*nzc);
        }
        
        /* Transpose to temporary work array */
        gmx_parallel_transpose_xy(cdata,
                                  work,
                                  nx,
                                  ny,
                                  pfft_setup->local_slab,
                                  pfft_setup->slab2grid_x,
                                  pfft_setup->slab2grid_y,
                                  nzc,
                                  pfft_setup->nnodes,
                                  pfft_setup->node2slab,
                                  pfft_setup->aav,
                                  pfft_setup->comm);

        /* Transpose from temporary work array in order YXZ to
         * the output array in order YZX. 
         */ 
        /* output cdata changes when nx or ny not divisible by nnodes */
        cdata = (t_complex *)out_data + local_y_start*nx*nzc;
        for(j=0;j<local_ny;j++)
        {
            gmx_fft_transpose_2d(work  + j*nzc*nx,
                                 cdata + j*nzc*nx,
                                 nx,
                                 nzc);
        }

        /* Perform local_ny*nzc complex FFTs along the x dimension */
        for(i=0;i<local_ny*nzc;i++)
        {
            gmx_fft_1d(pfft_setup->fft_x,
                       GMX_FFT_FORWARD,
                       cdata + i*nx,
                       work  + i*nx);
        }    
    
        /* Transpose back from YZX to YXZ. */
        for(j=0;j<local_ny;j++)
        {
            gmx_fft_transpose_2d(work  + j*nzc*nx,
                                 cdata + j*nzc*nx,
                                 nzc,
                                 nx);
        }
    }
    else if(dir == GMX_FFT_COMPLEX_TO_REAL)
    {
        cdata = (t_complex *)in_data  + local_y_start*nx*nzc;
        rdata =      (real *)out_data + local_x_start*ny*nzr;
        
        /* If we are working in-place it doesn't matter that we destroy
         * input data. Otherwise we use an extra temporary workspace array.
         */
        if(in_data == out_data)
        {
            ctmp = cdata;
        }
        else
        {
            ctmp = pfft_setup->work2;
        }
                
        /* Transpose from YXZ to YZX. */
        for(j=0;j<local_ny;j++)
        {
            gmx_fft_transpose_2d(cdata + j*nzc*nx,
                                 work  + j*nzc*nx,
                                 nx,
                                 nzc);
        }
        
        /* Perform local_ny*nzc complex FFTs along the x dimension */
        for(i=0;i<local_ny*nzc;i++)
        {
            gmx_fft_1d(pfft_setup->fft_x,
                       GMX_FFT_BACKWARD,
                       work + i*nx,
                       ctmp + i*nx);
        }    
        
        /* Transpose from YZX to YXZ. */
        for(j=0;j<local_ny;j++)
        {
            gmx_fft_transpose_2d(ctmp + j*nzc*nx,
                                 work + j*nzc*nx,
                                 nzc,
                                 nx);
        }
        
        if(in_data == out_data)
        {
            /* output cdata changes when nx or ny not divisible by nnodes */
           ctmp = (t_complex *)in_data + local_x_start*ny*nzc;
        }
        gmx_parallel_transpose_xy(work,
                                  ctmp,
                                  ny,
                                  nx,
                                  pfft_setup->local_slab,
                                  pfft_setup->slab2grid_y,
                                  pfft_setup->slab2grid_x,
                                  nzc,
                                  pfft_setup->nnodes,
                                  pfft_setup->node2slab,
                                  pfft_setup->aav,
                                  pfft_setup->comm);
        
        
        /* Perform nx local 2D complex-to-real FFTs in the yz slices.
         * The 3D FFT is done in-place, so we need to do this in-place too in order
         * to get the data organization right.
         */
        for(i=0;i<local_nx;i++)
        {
            gmx_fft_2d_real(pfft_setup->fft_yz,
                            GMX_FFT_COMPLEX_TO_REAL,
                            ctmp  + i*ny*nzc,
                            rdata + i*ny*nzr);
        }
    }
    else
    {
        gmx_fatal(FARGS,"Incorrect FFT direction.");
    }
    
    /* Skip the YX backtranspose to save communication! Grid is now YXZ */
    return 0;
}
Example #2
0
void powerspectavg(real ***intftab, int tsteps, int xbins, int ybins, char **outfiles)
{
    /*Fourier plans and output;*/
    gmx_fft_t  fftp;
    t_complex *ftspect1;            /* Spatial FFT of interface for each time frame and interface ftint[time,xycoord][0], ftintf[time,xycoord][1] for interface 1 and 2                 respectively */
    t_complex *ftspect2;
    real      *pspectavg1;          /*power -spectrum 1st interface*/
    real      *pspectavg2;          /* -------------- 2nd interface*/
    real      *temp;
    FILE      *datfile1, *datfile2; /*data-files with interface data*/
    int        n;                   /*time index*/
    int        fy  = ybins/2+1;     /* number of (symmetric) fourier y elements; */
    int        rfl = xbins*fy;      /*length of real - DFT == Symmetric 2D matrix*/
    int        status;

/*Prepare data structures for FFT, with time averaging of power spectrum*/
    if ( (status = gmx_fft_init_2d_real(&fftp, xbins, ybins, GMX_FFT_FLAG_NONE) ) != 0)
    {
        free(fftp);
        gmx_fatal(status, __FILE__, __LINE__, "Error allocating FFT");
    }

/*Initialize arrays*/
    snew(ftspect1, rfl);
    snew(ftspect2, rfl);
    snew(temp, rfl);
    snew(pspectavg1, rfl);
    snew(pspectavg2, rfl);

/*Fouriertransform directly (no normalization or anything)*/
/*NB! Check carefully indexes here*/

    for (n = 0; n < tsteps; n++)
    {
        gmx_fft_2d_real(fftp, GMX_FFT_REAL_TO_COMPLEX, intftab[0][n], ftspect1);
        gmx_fft_2d_real(fftp, GMX_FFT_REAL_TO_COMPLEX, intftab[1][n], ftspect2);

        /*Add to average for interface 1 here*/
        addtoavgenergy(ftspect1, pspectavg1, rfl, tsteps);
        /*Add to average for interface 2 here*/
        addtoavgenergy(ftspect2, pspectavg2, rfl, tsteps);
    }
    /*Print out average energy-spectrum to outfiles[0] and outfiles[1];*/

    datfile1 = ffopen(outfiles[0], "w");
    datfile2 = ffopen(outfiles[1], "w");

/*Filling dat files with spectral data*/
    fprintf(datfile1, "%s\n", "kx\t ky\t\tPower(kx,ky)");
    fprintf(datfile2, "%s\n", "kx\t ky\t\tPower(kx,ky)");
    for (n = 0; n < rfl; n++)
    {
        fprintf(datfile1, "%d\t%d\t %8.6f\n", (n / fy), (n % fy), pspectavg1[n]);
        fprintf(datfile2, "%d\t%d\t %8.6f\n", (n /fy), (n % fy), pspectavg2[n]);
    }
    ffclose(datfile1);
    ffclose(datfile2);

    free(ftspect1);
    free(ftspect2);

}