![]() |
ESPResSo 3.2.0-167-g2c9ead1-git
Extensible Simulation Package for Soft Matter Research
|
00001 /* 00002 Copyright (C) 2010,2011,2012,2013 The ESPResSo project 00003 Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 00004 Max-Planck-Institute for Polymer Research, Theory Group 00005 00006 This file is part of ESPResSo. 00007 00008 ESPResSo is free software: you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation, either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 ESPResSo is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program. If not, see <http://www.gnu.org/licenses/>. 00020 */ 00021 /** \file fft.c 00022 * 00023 * Routines, row decomposition, data structures and communication for the 3D-FFT. 00024 * 00025 */ 00026 00027 #include "fft.h" 00028 00029 #ifdef P3M 00030 00031 #include <fftw3.h> 00032 /* our remapping of malloc interferes with fftw3's name mangling. */ 00033 void *fftw_malloc(size_t n); 00034 00035 #include <mpi.h> 00036 #include "communication.h" 00037 #include "grid.h" 00038 #include "fft-common.h" 00039 00040 /************************************************ 00041 * variables 00042 ************************************************/ 00043 fft_data_struct fft; 00044 00045 /** communicate the grid data according to the given fft_forw_plan. 00046 * \param plan communication plan (see \ref fft_forw_plan). 00047 * \param in input mesh. 00048 * \param out output mesh. 00049 */ 00050 static void 00051 fft_forw_grid_comm(fft_forw_plan plan, double *in, double *out); 00052 00053 /** communicate the grid data according to the given fft_forw_plan/fft_bakc_plan. 00054 * \param plan_f communication plan (see \ref fft_forw_plan). 00055 * \param plan_b additional back plan (see \ref fft_back_plan). 00056 * \param in input mesh. 00057 * \param out output mesh. 00058 */ 00059 static void 00060 fft_back_grid_comm(fft_forw_plan plan_f, fft_back_plan plan_b, double *in, double *out); 00061 00062 void fft_pre_init() { 00063 fft_common_pre_init(&fft); 00064 } 00065 00066 int fft_init(double **data, int *ca_mesh_dim, int *ca_mesh_margin, 00067 int* global_mesh_dim, double *global_mesh_off, 00068 int *ks_pnum) 00069 { 00070 int i,j; 00071 /* helpers */ 00072 int mult[3]; 00073 00074 int n_grid[4][3]; /* The four node grids. */ 00075 int my_pos[4][3]; /* The position of this_node in the node grids. */ 00076 int *n_id[4]; /* linear node identity lists for the node grids. */ 00077 int *n_pos[4]; /* positions of nodes in the node grids. */ 00078 /* FFTW WISDOM stuff. */ 00079 char wisdom_file_name[255]; 00080 FILE *wisdom_file; 00081 int wisdom_status; 00082 00083 FFT_TRACE(fprintf(stderr,"%d: fft_init():\n",this_node)); 00084 00085 00086 fft.max_comm_size=0; fft.max_mesh_size=0; 00087 for(i=0;i<4;i++) { 00088 n_id[i] = malloc(1*n_nodes*sizeof(int)); 00089 n_pos[i] = malloc(3*n_nodes*sizeof(int)); 00090 } 00091 00092 /* === node grids === */ 00093 /* real space node grid (n_grid[0]) */ 00094 for(i=0;i<3;i++) { 00095 n_grid[0][i] = node_grid[i]; 00096 my_pos[0][i] = node_pos[i]; 00097 } 00098 for(i=0;i<n_nodes;i++) { 00099 int lin_ind; 00100 map_node_array(i, &(n_pos[0][3*i+0])); 00101 lin_ind = get_linear_index( n_pos[0][3*i+0],n_pos[0][3*i+1],n_pos[0][3*i+2], n_grid[0]); 00102 n_id[0][lin_ind] = i; 00103 } 00104 00105 /* FFT node grids (n_grid[1 - 3]) */ 00106 calc_2d_grid(n_nodes,n_grid[1]); 00107 /* resort n_grid[1] dimensions if necessary */ 00108 fft.plan[1].row_dir = map_3don2d_grid(n_grid[0], n_grid[1], mult); 00109 fft.plan[0].n_permute = 0; 00110 for(i=1;i<4;i++) fft.plan[i].n_permute = (fft.plan[1].row_dir+i)%3; 00111 for(i=0;i<3;i++) { 00112 n_grid[2][i] = n_grid[1][(i+1)%3]; 00113 n_grid[3][i] = n_grid[1][(i+2)%3]; 00114 } 00115 fft.plan[2].row_dir = (fft.plan[1].row_dir-1)%3; 00116 fft.plan[3].row_dir = (fft.plan[1].row_dir-2)%3; 00117 00118 00119 00120 /* === communication groups === */ 00121 /* copy local mesh off real space charge assignment grid */ 00122 for(i=0;i<3;i++) fft.plan[0].new_mesh[i] = ca_mesh_dim[i]; 00123 for(i=1; i<4;i++) { 00124 fft.plan[i].g_size=fft_find_comm_groups(n_grid[i-1], n_grid[i], n_id[i-1], n_id[i], 00125 fft.plan[i].group, n_pos[i], my_pos[i]); 00126 if(fft.plan[i].g_size==-1) { 00127 /* try permutation */ 00128 j = n_grid[i][(fft.plan[i].row_dir+1)%3]; 00129 n_grid[i][(fft.plan[i].row_dir+1)%3] = n_grid[i][(fft.plan[i].row_dir+2)%3]; 00130 n_grid[i][(fft.plan[i].row_dir+2)%3] = j; 00131 fft.plan[i].g_size=fft_find_comm_groups(n_grid[i-1], n_grid[i], n_id[i-1], n_id[i], 00132 fft.plan[i].group, n_pos[i], my_pos[i]); 00133 if(fft.plan[i].g_size==-1) { 00134 fprintf(stderr,"%d: INTERNAL ERROR: fft_find_comm_groups error\n", this_node); 00135 errexit(); 00136 } 00137 } 00138 00139 fft.plan[i].send_block = (int *)realloc(fft.plan[i].send_block, 6*fft.plan[i].g_size*sizeof(int)); 00140 fft.plan[i].send_size = (int *)realloc(fft.plan[i].send_size, 1*fft.plan[i].g_size*sizeof(int)); 00141 fft.plan[i].recv_block = (int *)realloc(fft.plan[i].recv_block, 6*fft.plan[i].g_size*sizeof(int)); 00142 fft.plan[i].recv_size = (int *)realloc(fft.plan[i].recv_size, 1*fft.plan[i].g_size*sizeof(int)); 00143 00144 fft.plan[i].new_size = fft_calc_local_mesh(my_pos[i], n_grid[i], global_mesh_dim, 00145 global_mesh_off, fft.plan[i].new_mesh, 00146 fft.plan[i].start); 00147 permute_ifield(fft.plan[i].new_mesh,3,-(fft.plan[i].n_permute)); 00148 permute_ifield(fft.plan[i].start,3,-(fft.plan[i].n_permute)); 00149 fft.plan[i].n_ffts = fft.plan[i].new_mesh[0]*fft.plan[i].new_mesh[1]; 00150 00151 /* FFT_TRACE( printf("%d: comm_group( ",this_node )); */ 00152 /* FFT_TRACE( for(j=0; j< fft.plan[i].g_size; j++) printf("%d ")); */ 00153 /* FFT_TRACE( printf(")\n")); */ 00154 00155 /* === send/recv block specifications === */ 00156 for(j=0; j<fft.plan[i].g_size; j++) { 00157 int k, node; 00158 /* send block: this_node to comm-group-node i (identity: node) */ 00159 node = fft.plan[i].group[j]; 00160 fft.plan[i].send_size[j] 00161 = fft_calc_send_block(my_pos[i-1], n_grid[i-1], &(n_pos[i][3*node]), n_grid[i], 00162 global_mesh_dim, global_mesh_off, &(fft.plan[i].send_block[6*j])); 00163 permute_ifield(&(fft.plan[i].send_block[6*j]),3,-(fft.plan[i-1].n_permute)); 00164 permute_ifield(&(fft.plan[i].send_block[6*j+3]),3,-(fft.plan[i-1].n_permute)); 00165 if(fft.plan[i].send_size[j] > fft.max_comm_size) 00166 fft.max_comm_size = fft.plan[i].send_size[j]; 00167 /* First plan send blocks have to be adjusted, since the CA grid 00168 may have an additional margin outside the actual domain of the 00169 node */ 00170 if(i==1) { 00171 for(k=0;k<3;k++) 00172 fft.plan[1].send_block[6*j+k ] += ca_mesh_margin[2*k]; 00173 } 00174 /* recv block: this_node from comm-group-node i (identity: node) */ 00175 fft.plan[i].recv_size[j] 00176 = fft_calc_send_block(my_pos[i], n_grid[i], &(n_pos[i-1][3*node]), n_grid[i-1], 00177 global_mesh_dim, global_mesh_off, &(fft.plan[i].recv_block[6*j])); 00178 permute_ifield(&(fft.plan[i].recv_block[6*j]),3,-(fft.plan[i].n_permute)); 00179 permute_ifield(&(fft.plan[i].recv_block[6*j+3]),3,-(fft.plan[i].n_permute)); 00180 if(fft.plan[i].recv_size[j] > fft.max_comm_size) 00181 fft.max_comm_size = fft.plan[i].recv_size[j]; 00182 } 00183 00184 for(j=0;j<3;j++) fft.plan[i].old_mesh[j] = fft.plan[i-1].new_mesh[j]; 00185 if(i==1) 00186 fft.plan[i].element = 1; 00187 else { 00188 fft.plan[i].element = 2; 00189 for(j=0; j<fft.plan[i].g_size; j++) { 00190 fft.plan[i].send_size[j] *= 2; 00191 fft.plan[i].recv_size[j] *= 2; 00192 } 00193 } 00194 /* DEBUG */ 00195 for(j=0;j<n_nodes;j++) { 00196 /* MPI_Barrier(comm_cart); */ 00197 if(j==this_node) FFT_TRACE(fft_print_fft_plan(fft.plan[i])); 00198 } 00199 } 00200 00201 /* Factor 2 for complex fields */ 00202 fft.max_comm_size *= 2; 00203 fft.max_mesh_size = (ca_mesh_dim[0]*ca_mesh_dim[1]*ca_mesh_dim[2]); 00204 for(i=1;i<4;i++) 00205 if(2*fft.plan[i].new_size > fft.max_mesh_size) fft.max_mesh_size = 2*fft.plan[i].new_size; 00206 00207 FFT_TRACE(fprintf(stderr,"%d: fft.max_comm_size = %d, fft.max_mesh_size = %d\n", 00208 this_node,fft.max_comm_size,fft.max_mesh_size)); 00209 00210 /* === pack function === */ 00211 for(i=1;i<4;i++) { 00212 fft.plan[i].pack_function = fft_pack_block_permute2; 00213 FFT_TRACE(fprintf(stderr,"%d: forw plan[%d] permute 2 \n",this_node,i)); 00214 } 00215 (*ks_pnum)=6; 00216 if(fft.plan[1].row_dir==2) { 00217 fft.plan[1].pack_function = fft_pack_block; 00218 FFT_TRACE(fprintf(stderr,"%d: forw plan[%d] permute 0 \n",this_node,1)); 00219 (*ks_pnum)=4; 00220 } 00221 else if(fft.plan[1].row_dir==1) { 00222 fft.plan[1].pack_function = fft_pack_block_permute1; 00223 FFT_TRACE(fprintf(stderr,"%d: forw plan[%d] permute 1 \n",this_node,1)); 00224 (*ks_pnum)=5; 00225 } 00226 00227 /* Factor 2 for complex numbers */ 00228 fft.send_buf = (double *)realloc(fft.send_buf, fft.max_comm_size*sizeof(double)); 00229 fft.recv_buf = (double *)realloc(fft.recv_buf, fft.max_comm_size*sizeof(double)); 00230 if (*data) fftw_free(*data); 00231 (*data) = (double *)fftw_malloc(fft.max_mesh_size*sizeof(double)); 00232 if (fft.data_buf) fftw_free(fft.data_buf); 00233 fft.data_buf = (double *)fftw_malloc(fft.max_mesh_size*sizeof(double)); 00234 if(!(*data) || !fft.data_buf || !fft.recv_buf || !fft.send_buf) { 00235 fprintf(stderr,"%d: Could not allocate FFT data arays\n",this_node); 00236 errexit(); 00237 } 00238 00239 fftw_complex *c_data = (fftw_complex *) (*data); 00240 00241 /* === FFT Routines (Using FFTW / RFFTW package)=== */ 00242 for(i=1;i<4;i++) { 00243 fft.plan[i].dir = FFTW_FORWARD; 00244 /* FFT plan creation. 00245 Attention: destroys contents of c_data/data and c_fft.data_buf/data_buf. */ 00246 wisdom_status = FFTW_FAILURE; 00247 sprintf(wisdom_file_name,"fftw3_1d_wisdom_forw_n%d.file", 00248 fft.plan[i].new_mesh[2]); 00249 if( (wisdom_file=fopen(wisdom_file_name,"r"))!=NULL ) { 00250 wisdom_status = fftw_import_wisdom_from_file(wisdom_file); 00251 fclose(wisdom_file); 00252 } 00253 if(fft.init_tag==1) fftw_destroy_plan(fft.plan[i].fftw_plan); 00254 //printf("fft.plan[%d].n_ffts=%d\n",i,fft.plan[i].n_ffts); 00255 fft.plan[i].fftw_plan = 00256 fftw_plan_many_dft(1,&fft.plan[i].new_mesh[2],fft.plan[i].n_ffts, 00257 c_data,NULL,1,fft.plan[i].new_mesh[2], 00258 c_data,NULL,1,fft.plan[i].new_mesh[2], 00259 fft.plan[i].dir,FFTW_PATIENT); 00260 if( wisdom_status == FFTW_FAILURE && 00261 (wisdom_file=fopen(wisdom_file_name,"w"))!=NULL ) { 00262 fftw_export_wisdom_to_file(wisdom_file); 00263 fclose(wisdom_file); 00264 } 00265 fft.plan[i].fft_function = fftw_execute; 00266 } 00267 00268 /* === The BACK Direction === */ 00269 /* this is needed because slightly different functions are used */ 00270 for(i=1;i<4;i++) { 00271 fft.back[i].dir = FFTW_BACKWARD; 00272 wisdom_status = FFTW_FAILURE; 00273 sprintf(wisdom_file_name,"fftw3_1d_wisdom_back_n%d.file", 00274 fft.plan[i].new_mesh[2]); 00275 if( (wisdom_file=fopen(wisdom_file_name,"r"))!=NULL ) { 00276 wisdom_status = fftw_import_wisdom_from_file(wisdom_file); 00277 fclose(wisdom_file); 00278 } 00279 if(fft.init_tag==1) fftw_destroy_plan(fft.back[i].fftw_plan); 00280 fft.back[i].fftw_plan = 00281 fftw_plan_many_dft(1,&fft.plan[i].new_mesh[2],fft.plan[i].n_ffts, 00282 c_data,NULL,1,fft.plan[i].new_mesh[2], 00283 c_data,NULL,1,fft.plan[i].new_mesh[2], 00284 fft.back[i].dir,FFTW_PATIENT); 00285 if( wisdom_status == FFTW_FAILURE && 00286 (wisdom_file=fopen(wisdom_file_name,"w"))!=NULL ) { 00287 fftw_export_wisdom_to_file(wisdom_file); 00288 fclose(wisdom_file); 00289 } 00290 fft.back[i].fft_function = fftw_execute; 00291 fft.back[i].pack_function = fft_pack_block_permute1; 00292 FFT_TRACE(fprintf(stderr,"%d: back plan[%d] permute 1 \n",this_node,i)); 00293 } 00294 if(fft.plan[1].row_dir==2) { 00295 fft.back[1].pack_function = fft_pack_block; 00296 FFT_TRACE(fprintf(stderr,"%d: back plan[%d] permute 0 \n",this_node,1)); 00297 } 00298 else if(fft.plan[1].row_dir==1) { 00299 fft.back[1].pack_function = fft_pack_block_permute2; 00300 FFT_TRACE(fprintf(stderr,"%d: back plan[%d] permute 2 \n",this_node,1)); 00301 } 00302 fft.init_tag=1; 00303 /* free(data); */ 00304 for(i=0;i<4;i++) { free(n_id[i]); free(n_pos[i]); } 00305 return fft.max_mesh_size; 00306 } 00307 00308 void fft_perform_forw(double *data) 00309 { 00310 int i; 00311 00312 /* int m,n,o; */ 00313 /* ===== first direction ===== */ 00314 FFT_TRACE(fprintf(stderr,"%d: fft_perform_forw: dir 1:\n",this_node)); 00315 00316 fftw_complex *c_data = (fftw_complex *) data; 00317 fftw_complex *c_data_buf = (fftw_complex *) fft.data_buf; 00318 00319 /* communication to current dir row format (in is data) */ 00320 fft_forw_grid_comm(fft.plan[1], data, fft.data_buf); 00321 00322 00323 /* 00324 fprintf(stderr,"%d: start grid \n",this_node); 00325 i=0; 00326 for(m=0;m<8;m++) { 00327 for(n=0;n<8;n++) { 00328 for(o=0;o<8;o++) { 00329 fprintf(stderr,"%.3f ",fft.data_buf[i++]); 00330 } 00331 fprintf(stderr,"\n"); 00332 } 00333 fprintf(stderr,"\n"); 00334 } 00335 */ 00336 00337 /* complexify the real data array (in is fft.data_buf) */ 00338 for(i=0;i<fft.plan[1].new_size;i++) { 00339 data[2*i] = fft.data_buf[i]; /* real value */ 00340 data[(2*i)+1] = 0; /* complex value */ 00341 } 00342 /* perform FFT (in/out is data)*/ 00343 fftw_execute_dft(fft.plan[1].fftw_plan,c_data,c_data); 00344 /* ===== second direction ===== */ 00345 FFT_TRACE(fprintf(stderr,"%d: fft_perform_forw: dir 2:\n",this_node)); 00346 /* communication to current dir row format (in is data) */ 00347 fft_forw_grid_comm(fft.plan[2], data, fft.data_buf); 00348 /* perform FFT (in/out is fft.data_buf)*/ 00349 fftw_execute_dft(fft.plan[2].fftw_plan,c_data_buf,c_data_buf); 00350 /* ===== third direction ===== */ 00351 FFT_TRACE(fprintf(stderr,"%d: fft_perform_forw: dir 3:\n",this_node)); 00352 /* communication to current dir row format (in is fft.data_buf) */ 00353 fft_forw_grid_comm(fft.plan[3], fft.data_buf, data); 00354 /* perform FFT (in/out is data)*/ 00355 fftw_execute_dft(fft.plan[3].fftw_plan,c_data,c_data); 00356 //fft_print_global_fft_mesh(fft.plan[3],data,1,0); 00357 00358 /* REMARK: Result has to be in data. */ 00359 } 00360 00361 void fft_perform_back(double *data) 00362 { 00363 int i; 00364 00365 fftw_complex *c_data = (fftw_complex *) data; 00366 fftw_complex *c_data_buf = (fftw_complex *) fft.data_buf; 00367 00368 /* ===== third direction ===== */ 00369 FFT_TRACE(fprintf(stderr,"%d: fft_perform_back: dir 3:\n",this_node)); 00370 00371 00372 /* perform FFT (in is data) */ 00373 fftw_execute_dft(fft.back[3].fftw_plan,c_data,c_data); 00374 /* communicate (in is data)*/ 00375 fft_back_grid_comm(fft.plan[3],fft.back[3],data,fft.data_buf); 00376 00377 /* ===== second direction ===== */ 00378 FFT_TRACE(fprintf(stderr,"%d: fft_perform_back: dir 2:\n",this_node)); 00379 /* perform FFT (in is fft.data_buf) */ 00380 fftw_execute_dft(fft.back[2].fftw_plan,c_data_buf,c_data_buf); 00381 /* communicate (in is fft.data_buf) */ 00382 fft_back_grid_comm(fft.plan[2],fft.back[2],fft.data_buf,data); 00383 00384 /* ===== first direction ===== */ 00385 FFT_TRACE(fprintf(stderr,"%d: fft_perform_back: dir 1:\n",this_node)); 00386 /* perform FFT (in is data) */ 00387 fftw_execute_dft(fft.back[1].fftw_plan,c_data,c_data); 00388 /* throw away the (hopefully) empty complex component (in is data)*/ 00389 for(i=0;i<fft.plan[1].new_size;i++) { 00390 fft.data_buf[i] = data[2*i]; /* real value */ 00391 //Vincent: 00392 if (data[2*i+1]>1e-5) { 00393 printf("Complex value is not zero (i=%d,data=%g)!!!\n",i,data[2*i+1]); 00394 if (i>100) exit(-1); 00395 } 00396 } 00397 /* communicate (in is fft.data_buf) */ 00398 fft_back_grid_comm(fft.plan[1],fft.back[1],fft.data_buf,data); 00399 00400 00401 /* REMARK: Result has to be in data. */ 00402 } 00403 00404 void fft_forw_grid_comm(fft_forw_plan plan, double *in, double *out) 00405 { 00406 int i; 00407 MPI_Status status; 00408 double *tmp_ptr; 00409 00410 for(i=0;i<plan.g_size;i++) { 00411 plan.pack_function(in, fft.send_buf, &(plan.send_block[6*i]), 00412 &(plan.send_block[6*i+3]), plan.old_mesh, plan.element); 00413 00414 if(plan.group[i]<this_node) { /* send first, receive second */ 00415 MPI_Send(fft.send_buf, plan.send_size[i], MPI_DOUBLE, 00416 plan.group[i], REQ_FFT_FORW, comm_cart); 00417 MPI_Recv(fft.recv_buf, plan.recv_size[i], MPI_DOUBLE, 00418 plan.group[i], REQ_FFT_FORW, comm_cart, &status); 00419 } 00420 else if(plan.group[i]>this_node) { /* receive first, send second */ 00421 MPI_Recv(fft.recv_buf, plan.recv_size[i], MPI_DOUBLE, 00422 plan.group[i], REQ_FFT_FORW, comm_cart, &status); 00423 MPI_Send(fft.send_buf, plan.send_size[i], MPI_DOUBLE, 00424 plan.group[i], REQ_FFT_FORW, comm_cart); 00425 } 00426 else { /* Self communication... */ 00427 tmp_ptr = fft.send_buf; 00428 fft.send_buf = fft.recv_buf; 00429 fft.recv_buf = tmp_ptr; 00430 } 00431 fft_unpack_block(fft.recv_buf, out, &(plan.recv_block[6*i]), 00432 &(plan.recv_block[6*i+3]), plan.new_mesh, plan.element); 00433 } 00434 } 00435 00436 void fft_back_grid_comm(fft_forw_plan plan_f, fft_back_plan plan_b, double *in, double *out) 00437 { 00438 int i; 00439 MPI_Status status; 00440 double *tmp_ptr; 00441 00442 /* Back means: Use the send/recieve stuff from the forward plan but 00443 replace the recieve blocks by the send blocks and vice 00444 versa. Attention then also new_mesh and old_mesh are exchanged */ 00445 00446 for(i=0;i<plan_f.g_size;i++) { 00447 00448 plan_b.pack_function(in, fft.send_buf, &(plan_f.recv_block[6*i]), 00449 &(plan_f.recv_block[6*i+3]), plan_f.new_mesh, plan_f.element); 00450 00451 if(plan_f.group[i]<this_node) { /* send first, receive second */ 00452 MPI_Send(fft.send_buf, plan_f.recv_size[i], MPI_DOUBLE, 00453 plan_f.group[i], REQ_FFT_BACK, comm_cart); 00454 MPI_Recv(fft.recv_buf, plan_f.send_size[i], MPI_DOUBLE, 00455 plan_f.group[i], REQ_FFT_BACK, comm_cart, &status); 00456 } 00457 else if(plan_f.group[i]>this_node) { /* receive first, send second */ 00458 MPI_Recv(fft.recv_buf, plan_f.send_size[i], MPI_DOUBLE, 00459 plan_f.group[i], REQ_FFT_BACK, comm_cart, &status); 00460 MPI_Send(fft.send_buf, plan_f.recv_size[i], MPI_DOUBLE, 00461 plan_f.group[i], REQ_FFT_BACK, comm_cart); 00462 } 00463 else { /* Self communication... */ 00464 tmp_ptr = fft.send_buf; 00465 fft.send_buf = fft.recv_buf; 00466 fft.recv_buf = tmp_ptr; 00467 } 00468 fft_unpack_block(fft.recv_buf, out, &(plan_f.send_block[6*i]), 00469 &(plan_f.send_block[6*i+3]), plan_f.old_mesh, plan_f.element); 00470 } 00471 } 00472 00473 #endif
1.7.5.1