1 2 /* 3 Provides an interface to the FFTW package. 4 Testing examples can be found in ~src/mat/examples/tests 5 */ 6 7 #include <../src/mat/impls/fft/fft.h> /*I "petscmat.h" I*/ 8 EXTERN_C_BEGIN 9 #include <fftw3-mpi.h> 10 EXTERN_C_END 11 12 typedef struct { 13 fftw_plan p_forward,p_backward; 14 unsigned p_flag; /* planner flags, FFTW_ESTIMATE,FFTW_MEASURE, FFTW_PATIENT, FFTW_EXHAUSTIVE */ 15 PetscScalar *finarray,*foutarray,*binarray,*boutarray; /* keep track of arrays becaue fftw plan should be 16 executed for the arrays with which the plan was created */ 17 } Mat_FFTW; 18 19 extern PetscErrorCode MatMult_SeqFFTW(Mat,Vec,Vec); 20 extern PetscErrorCode MatMultTranspose_SeqFFTW(Mat,Vec,Vec); 21 extern PetscErrorCode MatMult_MPIFFTW(Mat,Vec,Vec); 22 extern PetscErrorCode MatMultTranspose_MPIFFTW(Mat,Vec,Vec); 23 extern PetscErrorCode MatDestroy_FFTW(Mat); 24 extern PetscErrorCode VecDestroy_MPIFFTW(Vec); 25 extern PetscErrorCode MatGetVecs_FFTW(Mat,Vec*,Vec*); 26 27 #undef __FUNCT__ 28 #define __FUNCT__ "MatMult_SeqFFTW" 29 PetscErrorCode MatMult_SeqFFTW(Mat A,Vec x,Vec y) 30 { 31 PetscErrorCode ierr; 32 Mat_FFT *fft = (Mat_FFT*)A->data; 33 Mat_FFTW *fftw = (Mat_FFTW*)fft->data; 34 PetscScalar *x_array,*y_array; 35 PetscInt ndim=fft->ndim,*dim=fft->dim; 36 37 PetscFunctionBegin; 38 #if !defined(PETSC_USE_COMPLEX) 39 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not support for real numbers"); 40 #endif 41 ierr = VecGetArray(x,&x_array);CHKERRQ(ierr); 42 ierr = VecGetArray(y,&y_array);CHKERRQ(ierr); 43 if (!fftw->p_forward){ /* create a plan, then excute it */ 44 switch (ndim){ 45 case 1: 46 fftw->p_forward = fftw_plan_dft_1d(dim[0],(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_FORWARD,fftw->p_flag); 47 break; 48 case 2: 49 fftw->p_forward = fftw_plan_dft_2d(dim[0],dim[1],(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_FORWARD,fftw->p_flag); 50 break; 51 case 3: 52 fftw->p_forward = fftw_plan_dft_3d(dim[0],dim[1],dim[2],(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_FORWARD,fftw->p_flag); 53 break; 54 default: 55 fftw->p_forward = fftw_plan_dft(ndim,dim,(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_FORWARD,fftw->p_flag); 56 break; 57 } 58 fftw->finarray = x_array; 59 fftw->foutarray = y_array; 60 /* Warning: if (fftw->p_flag!==FFTW_ESTIMATE) The data in the in/out arrays is overwritten! 61 planning should be done before x is initialized! See FFTW manual sec2.1 or sec4 */ 62 fftw_execute(fftw->p_forward); 63 } else { /* use existing plan */ 64 if (fftw->finarray != x_array || fftw->foutarray != y_array){ /* use existing plan on new arrays */ 65 fftw_execute_dft(fftw->p_forward,(fftw_complex*)x_array,(fftw_complex*)y_array); 66 } else { 67 fftw_execute(fftw->p_forward); 68 } 69 } 70 ierr = VecRestoreArray(y,&y_array);CHKERRQ(ierr); 71 ierr = VecRestoreArray(x,&x_array);CHKERRQ(ierr); 72 PetscFunctionReturn(0); 73 } 74 75 #undef __FUNCT__ 76 #define __FUNCT__ "MatMultTranspose_SeqFFTW" 77 PetscErrorCode MatMultTranspose_SeqFFTW(Mat A,Vec x,Vec y) 78 { 79 PetscErrorCode ierr; 80 Mat_FFT *fft = (Mat_FFT*)A->data; 81 Mat_FFTW *fftw = (Mat_FFTW*)fft->data; 82 PetscScalar *x_array,*y_array; 83 PetscInt ndim=fft->ndim,*dim=fft->dim; 84 85 PetscFunctionBegin; 86 #if !defined(PETSC_USE_COMPLEX) 87 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not support for real numbers"); 88 #endif 89 ierr = VecGetArray(x,&x_array);CHKERRQ(ierr); 90 ierr = VecGetArray(y,&y_array);CHKERRQ(ierr); 91 if (!fftw->p_backward){ /* create a plan, then excute it */ 92 switch (ndim){ 93 case 1: 94 fftw->p_backward = fftw_plan_dft_1d(dim[0],(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_BACKWARD,fftw->p_flag); 95 break; 96 case 2: 97 fftw->p_backward = fftw_plan_dft_2d(dim[0],dim[1],(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_BACKWARD,fftw->p_flag); 98 break; 99 case 3: 100 fftw->p_backward = fftw_plan_dft_3d(dim[0],dim[1],dim[2],(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_BACKWARD,fftw->p_flag); 101 break; 102 default: 103 fftw->p_backward = fftw_plan_dft(ndim,dim,(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_BACKWARD,fftw->p_flag); 104 break; 105 } 106 fftw->binarray = x_array; 107 fftw->boutarray = y_array; 108 fftw_execute(fftw->p_backward);CHKERRQ(ierr); 109 } else { /* use existing plan */ 110 if (fftw->binarray != x_array || fftw->boutarray != y_array){ /* use existing plan on new arrays */ 111 fftw_execute_dft(fftw->p_backward,(fftw_complex*)x_array,(fftw_complex*)y_array); 112 } else { 113 fftw_execute(fftw->p_backward);CHKERRQ(ierr); 114 } 115 } 116 ierr = VecRestoreArray(y,&y_array);CHKERRQ(ierr); 117 ierr = VecRestoreArray(x,&x_array);CHKERRQ(ierr); 118 PetscFunctionReturn(0); 119 } 120 121 #undef __FUNCT__ 122 #define __FUNCT__ "MatMult_MPIFFTW" 123 PetscErrorCode MatMult_MPIFFTW(Mat A,Vec x,Vec y) 124 { 125 PetscErrorCode ierr; 126 Mat_FFT *fft = (Mat_FFT*)A->data; 127 Mat_FFTW *fftw = (Mat_FFTW*)fft->data; 128 PetscScalar *x_array,*y_array; 129 PetscInt ndim=fft->ndim,*dim=fft->dim; 130 MPI_Comm comm=((PetscObject)A)->comm; 131 132 PetscFunctionBegin; 133 #if !defined(PETSC_USE_COMPLEX) 134 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not support for real numbers"); 135 #endif 136 ierr = VecGetArray(x,&x_array);CHKERRQ(ierr); 137 ierr = VecGetArray(y,&y_array);CHKERRQ(ierr); 138 if (!fftw->p_forward){ /* create a plan, then excute it */ 139 switch (ndim){ 140 case 1: 141 fftw->p_forward = fftw_mpi_plan_dft_1d(dim[0],(fftw_complex*)x_array,(fftw_complex*)y_array,comm,FFTW_FORWARD,fftw->p_flag); 142 break; 143 case 2: 144 fftw->p_forward = fftw_mpi_plan_dft_2d(dim[0],dim[1],(fftw_complex*)x_array,(fftw_complex*)y_array,comm,FFTW_FORWARD,fftw->p_flag); 145 break; 146 case 3: 147 fftw->p_forward = fftw_mpi_plan_dft_3d(dim[0],dim[1],dim[2],(fftw_complex*)x_array,(fftw_complex*)y_array,comm,FFTW_FORWARD,fftw->p_flag); 148 break; 149 default: 150 /* 151 fftw->p_forward = fftw_mpi_plan_dft(ndim,dim,(fftw_complex*)x_array,(fftw_complex*)y_array,comm,FFTW_FORWARD,fftw->p_flag); 152 */ 153 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not supported yet"); 154 break; 155 } 156 fftw->finarray = x_array; 157 fftw->foutarray = y_array; 158 /* Warning: if (fftw->p_flag!==FFTW_ESTIMATE) The data in the in/out arrays is overwritten! 159 planning should be done before x is initialized! See FFTW manual sec2.1 or sec4 */ 160 fftw_execute(fftw->p_forward); 161 } else { /* use existing plan */ 162 if (fftw->finarray != x_array || fftw->foutarray != y_array){ /* use existing plan on new arrays */ 163 fftw_execute_dft(fftw->p_forward,(fftw_complex*)x_array,(fftw_complex*)y_array); 164 } else { 165 fftw_execute(fftw->p_forward); 166 } 167 } 168 ierr = VecRestoreArray(y,&y_array);CHKERRQ(ierr); 169 ierr = VecRestoreArray(x,&x_array);CHKERRQ(ierr); 170 PetscFunctionReturn(0); 171 } 172 173 #undef __FUNCT__ 174 #define __FUNCT__ "MatMultTranspose_MPIFFTW" 175 PetscErrorCode MatMultTranspose_MPIFFTW(Mat A,Vec x,Vec y) 176 { 177 PetscErrorCode ierr; 178 Mat_FFT *fft = (Mat_FFT*)A->data; 179 Mat_FFTW *fftw = (Mat_FFTW*)fft->data; 180 PetscScalar *x_array,*y_array; 181 PetscInt ndim=fft->ndim,*dim=fft->dim; 182 MPI_Comm comm=((PetscObject)A)->comm; 183 184 PetscFunctionBegin; 185 #if !defined(PETSC_USE_COMPLEX) 186 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not support for real numbers"); 187 #endif 188 ierr = VecGetArray(x,&x_array);CHKERRQ(ierr); 189 ierr = VecGetArray(y,&y_array);CHKERRQ(ierr); 190 if (!fftw->p_backward){ /* create a plan, then excute it */ 191 switch (ndim){ 192 case 1: 193 fftw->p_backward = fftw_mpi_plan_dft_1d(dim[0],(fftw_complex*)x_array,(fftw_complex*)y_array,comm,FFTW_BACKWARD,fftw->p_flag); 194 break; 195 case 2: 196 fftw->p_backward = fftw_mpi_plan_dft_2d(dim[0],dim[1],(fftw_complex*)x_array,(fftw_complex*)y_array,comm,FFTW_BACKWARD,fftw->p_flag); 197 break; 198 case 3: 199 fftw->p_backward = fftw_mpi_plan_dft_3d(dim[0],dim[1],dim[2],(fftw_complex*)x_array,(fftw_complex*)y_array,comm,FFTW_BACKWARD,fftw->p_flag); 200 break; 201 default: 202 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"Not supported yet"); 203 /* fftw->p_backward = fftw_mpi_plan_dft(ndim,dim,(fftw_complex*)x_array,(fftw_complex*)y_array,FFTW_BACKWARD,fftw->p_flag); */ 204 break; 205 } 206 fftw->binarray = x_array; 207 fftw->boutarray = y_array; 208 fftw_execute(fftw->p_backward);CHKERRQ(ierr); 209 } else { /* use existing plan */ 210 if (fftw->binarray != x_array || fftw->boutarray != y_array){ /* use existing plan on new arrays */ 211 fftw_execute_dft(fftw->p_backward,(fftw_complex*)x_array,(fftw_complex*)y_array); 212 } else { 213 fftw_execute(fftw->p_backward);CHKERRQ(ierr); 214 } 215 } 216 ierr = VecRestoreArray(y,&y_array);CHKERRQ(ierr); 217 ierr = VecRestoreArray(x,&x_array);CHKERRQ(ierr); 218 PetscFunctionReturn(0); 219 } 220 221 #undef __FUNCT__ 222 #define __FUNCT__ "MatDestroy_FFTW" 223 PetscErrorCode MatDestroy_FFTW(Mat A) 224 { 225 Mat_FFT *fft = (Mat_FFT*)A->data; 226 Mat_FFTW *fftw = (Mat_FFTW*)fft->data; 227 PetscErrorCode ierr; 228 229 PetscFunctionBegin; 230 #if !defined(PETSC_USE_COMPLEX) 231 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not support for real numbers"); 232 #endif 233 fftw_destroy_plan(fftw->p_forward); 234 fftw_destroy_plan(fftw->p_backward); 235 ierr = PetscFree(fft->data);CHKERRQ(ierr); 236 PetscFunctionReturn(0); 237 } 238 239 #include <../src/vec/vec/impls/mpi/pvecimpl.h> /*I "petscvec.h" I*/ 240 #undef __FUNCT__ 241 #define __FUNCT__ "VecDestroy_MPIFFTW" 242 PetscErrorCode VecDestroy_MPIFFTW(Vec v) 243 { 244 PetscErrorCode ierr; 245 PetscScalar *array; 246 247 PetscFunctionBegin; 248 #if !defined(PETSC_USE_COMPLEX) 249 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not support for real numbers"); 250 #endif 251 ierr = VecGetArray(v,&array);CHKERRQ(ierr); 252 fftw_free((fftw_complex*)array);CHKERRQ(ierr); 253 ierr = VecRestoreArray(v,&array);CHKERRQ(ierr); 254 ierr = VecDestroy_MPI(v);CHKERRQ(ierr); 255 PetscFunctionReturn(0); 256 } 257 258 #undef __FUNCT__ 259 #define __FUNCT__ "MatGetVecs_FFTW" 260 /* 261 MatGetVecs_FFTW - Get vector(s) compatible with the matrix, i.e. with the 262 parallel layout determined by FFTW 263 264 Collective on Mat 265 266 Input Parameter: 267 . mat - the matrix 268 269 Output Parameter: 270 + fin - (optional) input vector of forward FFTW 271 - fout - (optional) output vector of forward FFTW 272 273 Level: advanced 274 275 .seealso: MatCreateFFTW() 276 */ 277 PetscErrorCode MatGetVecs_FFTW(Mat A,Vec *fin,Vec *fout) 278 { 279 PetscErrorCode ierr; 280 PetscMPIInt size,rank; 281 MPI_Comm comm=((PetscObject)A)->comm; 282 Mat_FFT *fft = (Mat_FFT*)A->data; 283 PetscInt N=fft->N; 284 285 PetscFunctionBegin; 286 #if !defined(PETSC_USE_COMPLEX) 287 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not support for real numbers"); 288 #endif 289 PetscValidHeaderSpecific(A,MAT_CLASSID,1); 290 PetscValidType(A,1); 291 292 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 293 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 294 if (size == 1){ /* sequential case */ 295 if (fin) {ierr = VecCreateSeq(PETSC_COMM_SELF,N,fin);CHKERRQ(ierr);} 296 if (fout){ierr = VecCreateSeq(PETSC_COMM_SELF,N,fout);CHKERRQ(ierr);} 297 } else { /* mpi case */ 298 ptrdiff_t alloc_local,local_n0,local_0_start; 299 PetscInt ndim=fft->ndim,*dim=fft->dim,n=fft->n; 300 fftw_complex *data_fin,*data_fout; 301 302 switch (ndim){ 303 case 1: 304 SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"Not supported yet"); 305 break; 306 case 2: 307 /* Get local size */ 308 alloc_local = fftw_mpi_local_size_2d(dim[0],dim[1],comm,&local_n0,&local_0_start); 309 if (fin) { 310 data_fin = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*alloc_local); 311 ierr = VecCreateMPIWithArray(comm,n,N,(const PetscScalar*)data_fin,fin);CHKERRQ(ierr); 312 (*fin)->ops->destroy = VecDestroy_MPIFFTW; 313 } 314 if (fout) { 315 data_fout = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*alloc_local); 316 ierr = VecCreateMPIWithArray(comm,n,N,(const PetscScalar*)data_fout,fout);CHKERRQ(ierr); 317 (*fout)->ops->destroy = VecDestroy_MPIFFTW; 318 } 319 break; 320 case 3: 321 SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"Not supported yet"); 322 break; 323 default: 324 SETERRQ(((PetscObject)A)->comm,PETSC_ERR_SUP,"Not supported yet"); 325 break; 326 } 327 } 328 if (fin){ 329 ierr = PetscLayoutReference(A->cmap,&(*fin)->map);CHKERRQ(ierr); 330 } 331 if (fout){ 332 ierr = PetscLayoutReference(A->rmap,&(*fout)->map);CHKERRQ(ierr); 333 } 334 PetscFunctionReturn(0); 335 } 336 337 EXTERN_C_BEGIN 338 #undef __FUNCT__ 339 #define __FUNCT__ "MatCreate_FFTW" 340 /* 341 MatCreate_FFTW - Creates a matrix object that provides FFT 342 via the external package FFTW 343 344 Options Database Keys: 345 + -mat_fftw_plannerflags - set FFTW planner flags 346 347 Level: intermediate 348 349 */ 350 PetscErrorCode MatCreate_FFTW(Mat A) 351 { 352 PetscErrorCode ierr; 353 MPI_Comm comm=((PetscObject)A)->comm; 354 Mat_FFT *fft=(Mat_FFT*)A->data; 355 Mat_FFTW *fftw; 356 PetscInt n=fft->n,N=fft->N,ndim=fft->ndim,*dim = fft->dim; 357 const char *p_flags[]={"FFTW_ESTIMATE","FFTW_MEASURE","FFTW_PATIENT","FFTW_EXHAUSTIVE"}; 358 PetscBool flg; 359 PetscInt p_flag; 360 PetscMPIInt size; 361 362 PetscFunctionBegin; 363 #if !defined(PETSC_USE_COMPLEX) 364 SETERRQ(comm,PETSC_ERR_SUP,"not support for real numbers"); 365 #endif 366 367 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 368 //ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 369 370 371 if (size == 1) { 372 ierr = MatSetSizes(A,N,N,N,N);CHKERRQ(ierr); 373 n = N; 374 } else { 375 ptrdiff_t alloc_local,local_n0,local_0_start; 376 switch (ndim){ 377 case 1: 378 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not implemented yet"); 379 break; 380 case 2: 381 alloc_local = fftw_mpi_local_size_2d(dim[0],dim[1],comm,&local_n0,&local_0_start); 382 /* 383 PetscMPIInt rank; 384 PetscSynchronizedPrintf(comm,"[%d] MatCreateSeqFFTW: local_n0, local_0_start %d %d, N %d,dim %d, %d\n",rank,(PetscInt)local_n0*dim[1],(PetscInt)local_0_start,m,dim[0],dim[1]); 385 PetscSynchronizedFlush(comm); 386 */ 387 n = (PetscInt)local_n0*dim[1]; 388 ierr = MatSetSizes(A,n,n,N,N);CHKERRQ(ierr); 389 break; 390 case 3: 391 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not implemented yet"); 392 break; 393 default: 394 SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"not implemented yet"); 395 break; 396 } 397 } 398 ierr = PetscObjectChangeTypeName((PetscObject)A,MATFFTW);CHKERRQ(ierr); 399 400 ierr = PetscNewLog(A,Mat_FFTW,&fftw);CHKERRQ(ierr); 401 fft->data = (void*)fftw; 402 403 fft->n = n; 404 fftw->p_forward = 0; 405 fftw->p_backward = 0; 406 fftw->p_flag = FFTW_ESTIMATE; 407 408 if (size == 1){ 409 A->ops->mult = MatMult_SeqFFTW; 410 A->ops->multtranspose = MatMultTranspose_SeqFFTW; 411 } else { 412 A->ops->mult = MatMult_MPIFFTW; 413 A->ops->multtranspose = MatMultTranspose_MPIFFTW; 414 } 415 fft->matdestroy = MatDestroy_FFTW; 416 A->ops->getvecs = MatGetVecs_FFTW; 417 A->assembled = PETSC_TRUE; 418 419 /* get runtime options */ 420 ierr = PetscOptionsBegin(((PetscObject)A)->comm,((PetscObject)A)->prefix,"FFTW Options","Mat");CHKERRQ(ierr); 421 ierr = PetscOptionsEList("-mat_fftw_plannerflags","Planner Flags","None",p_flags,4,p_flags[0],&p_flag,&flg);CHKERRQ(ierr); 422 if (flg) {fftw->p_flag = (unsigned)p_flag;} 423 PetscOptionsEnd(); 424 PetscFunctionReturn(0); 425 } 426 EXTERN_C_END 427