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