precond.c

Go to the documentation of this file.
00001 /*
00002     This file is part of magpar.
00003 
00004     Copyright (C) 2002-2009 Werner Scholz
00005 
00006     www:   http://www.magpar.net/
00007     email: magpar(at)magpar.net
00008 
00009     magpar is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     magpar is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017     GNU General Public License for more details.
00018 
00019     You should have received a copy of the GNU General Public License
00020     along with magpar; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 static char const Id[] = "$Id: precond.c 2699 2009-08-07 18:16:34Z scholz $\n\n";
00025 static char const Td[] = "$Today: " __FILE__ "  " __DATE__ "  "  __TIME__  " $\n\n";
00026 
00027 #include "llg.h"
00028 #include "field/field.h"
00029 #include "util/util.h"
00030 
00031 static KSP  ksp_Jac; 
00032 static Mat  vode_Jac; 
00033 static Vec  vode_w1,vode_w2; 
00034 static Mat  vode_pmat; 
00036 int Precond_Init(GridData *gdata)
00037 {
00038   MagparFunctionLogBegin;
00039 
00040   int rank,size;
00041   ierr = MPI_Comm_size(PETSC_COMM_WORLD,&size);CHKERRQ(ierr);
00042   ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);
00043 
00044   PetscPrintf(PETSC_COMM_WORLD,"Calculating sparsity pattern for matrix preallocation\n");
00045 
00046   /* get ownership range */
00047   int low,high;
00048   ierr = VecGetOwnershipRange(gdata->elevol,&low,&high);CHKERRQ(ierr);
00049 
00050   int *elevertall;
00051 
00052 #ifdef HAVE_ELEVERTALL
00053   elevertall=gdata->elevertall;
00054 #else
00055   if (size>1) {
00056     ierr = PetscMalloc(NV*gdata->n_ele*sizeof(int),&elevertall);CHKERRQ(ierr);
00057     ierr = PetscMemcpy(elevertall+NV*low,gdata->elevert,NV*gdata->ln_ele*sizeof(int));CHKERRQ(ierr);
00058 
00059     int *p;
00060     p=elevertall;
00061 
00062     int recvcount[size];
00063     recvcount[rank]=NV*gdata->ln_ele;
00064     for (int i=0;i<size;i++) {
00065       ierr = MPI_Bcast(recvcount+i,1,MPI_INT,i,PETSC_COMM_WORLD);CHKERRQ(ierr);
00066       /* we could also use MPI_Send/Recv to get everything just to the first processor */
00067       ierr = MPI_Bcast(p,recvcount[i],MPI_INT,i,PETSC_COMM_WORLD);CHKERRQ(ierr);
00068       p+=recvcount[i];
00069     }
00070     assert(p==elevertall+NV*gdata->n_ele);
00071   }
00072   else {
00073     elevertall=gdata->elevert;
00074   }
00075 #endif
00076 
00077   int *ia,*ja;
00078 #ifdef HAVE_M2IJ
00079   ia=gdata->mesh2nodal_ia;
00080   ja=gdata->mesh2nodal_ja;
00081 #else
00082   ierr = Mesh2Nodal(gdata->n_ele,gdata->n_vert,elevertall,&ia,&ja);CHKERRQ(ierr);
00083 #endif
00084 
00085 #ifndef HAVE_ELEVERTALL
00086   if (size>1) {
00087     ierr = PetscFree(elevertall);CHKERRQ(ierr);
00088   }
00089 #endif
00090 
00091   /* get ownership range */
00092   ierr = VecGetOwnershipRange(gdata->M,&low,&high);CHKERRQ(ierr);
00093   low/=ND;
00094   high/=ND;
00095 
00096   int *d_nnz;
00097   int *o_nnz;
00098   ierr = PetscMalloc(ND*(high-low)*sizeof(int),&d_nnz);CHKERRQ(ierr);
00099   ierr = PetscMalloc(ND*(high-low)*sizeof(int),&o_nnz);CHKERRQ(ierr);
00100   /* calculate number of nonzeroes for each line */
00101   for (int i=low;i<high;i++) {
00102     for (int j=0;j<ND;j++) {
00103       d_nnz[ND*(i-low)+j]=ND;
00104       o_nnz[ND*(i-low)+j]=0;
00105       for (int l=ia[i];l<ia[i+1];l++) {
00106         if (ja[l]>=low && ja[l]<high) {
00107           d_nnz[ND*(i-low)+j]+=ND;
00108         }
00109         else {
00110           o_nnz[ND*(i-low)+j]+=ND;
00111         }
00112       }
00113     }
00114   }
00115 
00116 #if 0
00117 #define PREALLOC_DG 25
00118 #define PREALLOC_OD 15
00119   PetscPrintf(PETSC_COMM_WORLD,"Creating matrix with fixed preallocation\n");
00120 
00121   ierr = MatCreateMPIAIJ(
00122     PETSC_COMM_WORLD,
00123     ND*gdata->ln_vert,ND*gdata->ln_vert,
00124     ND*gdata->n_vert,ND*gdata->n_vert,
00125     PREALLOC_DG,0,PREALLOC_OD,0,
00126     &vode_Jac
00127   );CHKERRQ(ierr);
00128 #else
00129   PetscPrintf(PETSC_COMM_WORLD,"Creating matrix with calculated preallocation\n");
00130   ierr = MatCreateMPIAIJ(
00131     PETSC_COMM_WORLD,
00132     ND*gdata->ln_vert,ND*gdata->ln_vert,
00133     ND*gdata->n_vert,ND*gdata->n_vert,
00134     0,d_nnz,0,o_nnz,
00135     &vode_Jac
00136   );CHKERRQ(ierr);
00137 #endif
00138   ierr = MatSetFromOptions(vode_Jac);CHKERRQ(ierr);
00139 
00140 #ifndef HAVE_M2IJ
00141   ierr = PetscFree(ia);CHKERRQ(ierr);
00142   ierr = PetscFree(ja);CHKERRQ(ierr);
00143 #endif
00144   ierr = PetscFree(d_nnz);CHKERRQ(ierr);
00145   ierr = PetscFree(o_nnz);CHKERRQ(ierr);
00146 
00147   ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,ND*gdata->ln_vert,ND*gdata->n_vert,PETSC_NULL,&vode_w1);CHKERRQ(ierr);
00148   ierr = VecCreateMPIWithArray(PETSC_COMM_WORLD,ND*gdata->ln_vert,ND*gdata->n_vert,PETSC_NULL,&vode_w2);CHKERRQ(ierr);
00149 
00150   PetscPrintf(PETSC_COMM_WORLD,"Calculating matrix elements...\n");
00151 
00152   for (int i=0;i<gdata->ln_vert;i++) {
00153     /* add 0 to diagonal matrix elements to enforce their allocation
00154        otherwise there might occur problems with MatScale/MatShift in Precond
00155        due to DIFFERENT_NONZERO_PATTERN
00156     */
00157 
00158     int rows[ND];
00159     rows[0]=gdata->vertl2g[i]*ND;
00160     rows[1]=rows[0]+1;
00161     rows[2]=rows[0]+2;
00162 
00163     ierr = MatSetValue(vode_Jac,rows[0],rows[0],0.0,ADD_VALUES);CHKERRQ(ierr);
00164     ierr = MatSetValue(vode_Jac,rows[1],rows[1],0.0,ADD_VALUES);CHKERRQ(ierr);
00165     ierr = MatSetValue(vode_Jac,rows[2],rows[2],0.0,ADD_VALUES);CHKERRQ(ierr);
00166   }
00167 
00168   /* compute the Jacobian */
00169   MatStructure str2 = DIFFERENT_NONZERO_PATTERN;
00170   ierr = myLLGJacobian(PETSC_NULL,gdata->time,gdata->M,&vode_Jac,&vode_Jac,&str2,gdata);CHKERRQ(ierr);
00171 
00172   ierr = MatDuplicate(vode_Jac,MAT_DO_NOT_COPY_VALUES,&vode_pmat);CHKERRQ(ierr);
00173 #ifdef SUPERLUX
00174   ierr = MatConvert(vode_Jac,MATSUPERLU_DIST,&vode_Jac);CHKERRQ(ierr);
00175   ierr = MatConvert(vode_pmat,MATSUPERLU_DIST,&vode_pmat);CHKERRQ(ierr);
00176   ierr = MatDestroy(vode_Jac);CHKERRQ(ierr);
00177 #elif defined(BLOCKSOLVEX) /* takes forever to set up PC */
00178   ierr = MatConvert(vode_Jac,MATMPIROWBS,&vode_Jac);CHKERRQ(ierr);
00179   ierr = MatConvert(vode_pmat,MATMPIROWBS,&vode_pmat);CHKERRQ(ierr);
00180   ierr = MatDestroy(vode_Jac);CHKERRQ(ierr);
00181 #endif
00182 
00183   PetscPrintf(PETSC_COMM_WORLD,"Initializing linear solver...\n");
00184 
00185   ierr = KSPCreate(PETSC_COMM_WORLD,&ksp_Jac);CHKERRQ(ierr);
00186   ierr = KSPSetOperators(ksp_Jac,vode_Jac,vode_Jac,SAME_PRECONDITIONER);CHKERRQ(ierr);
00187 
00188   /* set default options */
00189 
00190   /* evaluates
00191       PetscOptions "-psolve_ksp_type"
00192       PetscOptions "-psolve_ksp_atol"
00193       PetscOptions "-psolve_ksp_divtol"
00194       PetscOptions "-psolve_ksp_rtol"
00195                    "-psolve_pc_type"
00196                    "-psolve_sub_pc_type"
00197                    "-psolve_sub_pc_factor_shift_positive_definite"
00198                    "-psolve_pc_type"
00199                    "-psolve_pc_factor_shift_positive_definite"
00200   */
00201 
00202   PetscTruth flg;
00203   char str[256];
00204   /* by default use conjugate gradient solver */
00205 #undef ostr
00206 #define ostr "-psolve_ksp_type"
00207   ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00208   if (flg!=PETSC_TRUE) {
00209     sprintf(str,"gmres");
00210     PetscOptionsSetValue(ostr,str);
00211     PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00212   }
00213 
00214 #undef ostr
00215 #define ostr "-psolve_ksp_atol"
00216   ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00217   if (flg!=PETSC_TRUE) {
00218     sprintf(str,"1e-7");
00219     PetscOptionsSetValue(ostr,str);
00220     PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00221   }
00222 
00223 #undef ostr
00224 #define ostr "-psolve_ksp_rtol"
00225   ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00226   if (flg!=PETSC_TRUE) {
00227     sprintf(str,"0.01");
00228     PetscOptionsSetValue(ostr,str);
00229     PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00230   }
00231 
00232 #undef ostr
00233 #define ostr "-psolve_ksp_divtol"
00234   ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00235   if (flg!=PETSC_TRUE) {
00236     sprintf(str,"100");
00237     PetscOptionsSetValue(ostr,str);
00238     PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00239   }
00240 
00241   if (size>1) {
00242     /* by default use BlockJacobi preconditioner */
00243 #undef ostr
00244 #define ostr "-psolve_pc_type"
00245     ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00246     if (flg!=PETSC_TRUE) {
00247       sprintf(str,"bjacobi");
00248       PetscOptionsSetValue(ostr,str);
00249       PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00250     }
00251 
00252     /* by default use ILU preconditioner on subblocks */
00253 #undef ostr
00254 #define ostr "-psolve_sub_pc_type"
00255     ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00256     if (flg!=PETSC_TRUE) {
00257       sprintf(str,"ilu");
00258       PetscOptionsSetValue(ostr,str);
00259       PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00260     }
00261 
00262     /* by default use Manteuffel shift */
00263 /*
00264 #undef ostr
00265 #define ostr "-psolve_sub_pc_factor_shift_positive_definite"
00266     ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00267     if (flg!=PETSC_TRUE) {
00268       sprintf(str,"1");
00269       PetscOptionsSetValue(ostr,str);
00270       PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00271     }
00272 */
00273   }
00274   else {
00275     /* by default use ILU preconditioner */
00276 #undef ostr
00277 #define ostr "-psolve_pc_type"
00278     ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00279     if (flg!=PETSC_TRUE) {
00280       sprintf(str,"ilu");
00281       PetscOptionsSetValue(ostr,str);
00282       PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00283     }
00284 
00285     /* by default use Manteuffel shift */
00286 /*
00287 #undef ostr
00288 #define ostr "-psolve_pc_factor_shift_positive_definite"
00289     ierr = PetscOptionsGetString(PETSC_NULL,ostr,str,256,&flg);CHKERRQ(ierr);
00290     if (flg!=PETSC_TRUE) {
00291       sprintf(str,"1");
00292       PetscOptionsSetValue(ostr,str);
00293       PetscPrintf(PETSC_COMM_WORLD,"Option %s not found, using default value %s!\n",ostr,str);
00294     }
00295 */
00296   }
00297 
00298   /* use prefix for options */
00299   ierr = KSPSetOptionsPrefix(ksp_Jac,"psolve_");CHKERRQ(ierr);
00300 
00301   /* possibly override defaults with settings from user defined options */
00302   ierr = KSPSetFromOptions(ksp_Jac);CHKERRQ(ierr);
00303 
00304 /*
00305   ierr = KSPSetInitialGuessKnoll(ksp_Jac,PETSC_TRUE);CHKERRQ(ierr);
00306   ierr = KSPSetInitialGuessNonzero(ksp_Jac,PETSC_TRUE);CHKERRQ(ierr);
00307 */
00308 
00309   /* KSPSetUp only necessary to get more useful output from KSPView */
00310   /* FIXME: bug(?) in PETSc 2.2.1: for size==1 leads to error "Zero pivot row 0" */
00311   if (size>1) {
00312     ierr = KSPSetUp(ksp_Jac);CHKERRQ(ierr);
00313   }
00314 
00315   PetscPrintf(PETSC_COMM_WORLD,"KSP for preconditioning: P*z=r:\n");
00316 #if defined(SUPERLU) || defined(BLOCKSOLVE)
00317   PetscReal rtol,atol,divtol;
00318   int maxits;
00319   ierr = KSPGetTolerances(ksp_Jac,&rtol,&atol,&divtol,&maxits);CHKERRQ(ierr);
00320   PetscPrintf(PETSC_COMM_WORLD,"rtol: %g atol: %g divtol: %g maxits: %i\n",
00321     rtol,atol,divtol,maxits
00322   );
00323 #else
00324   ierr = KSPView(ksp_Jac,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
00325 #endif
00326 
00327   MagparFunctionLogReturn(0);
00328 }
00329 
00330 
00331 int Precond(realtype t,N_Vector y,N_Vector fy,booleantype jok,booleantype *jcurPtr,realtype gamma,void *P_data,N_Vector vtemp1,N_Vector vtemp2,N_Vector vtemp3)
00332 {
00333   GridData     *gdata = (GridData*)P_data;
00334   MatStructure str = DIFFERENT_NONZERO_PATTERN;
00335 
00336   MagparFunctionInfoBegin;
00337 
00338   /* jok - TRUE means reuse current Jacobian else recompute Jacobian */
00339   if (jok) {
00340     ierr     = MatCopy(vode_pmat,vode_Jac,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
00341     str      = SAME_NONZERO_PATTERN;
00342     *jcurPtr = FALSE;
00343   } else {
00344     /* make PETSc vector tmpy point to PVODE vector y */
00345 #ifdef UNIPROC
00346     ierr = VecPlaceArray(gdata->M,NV_DATA_S(y));CHKERRQ(ierr);
00347 #else
00348     ierr = VecPlaceArray(gdata->M,NV_DATA_P(y));CHKERRQ(ierr);
00349 #endif
00350 
00351     /* TODO: make Htot not calculate demag - we don't use it for Jacobian, could save (a little) time */
00352     ierr = Htot(gdata);CHKERRQ(ierr);
00353 
00354     /* compute the Jacobian */
00355     ierr = myLLGJacobian(PETSC_NULL,gdata->time,gdata->M,&vode_Jac,&vode_Jac,&str,gdata);CHKERRQ(ierr);
00356 
00357     ierr = VecResetArray(gdata->M);CHKERRQ(ierr);
00358 
00359     /* copy the Jacobian matrix */
00360     ierr = MatCopy(vode_Jac,vode_pmat,SAME_NONZERO_PATTERN);CHKERRQ(ierr);
00361 
00362     *jcurPtr = TRUE;
00363   }
00364 
00365   /* construct I-gamma*Jac  */
00366 
00367   ierr = MatScale(vode_Jac,-gamma);CHKERRQ(ierr);
00368   ierr = MatShift(vode_Jac,1.0);CHKERRQ(ierr);
00369 
00370   ierr = KSPSetOperators(ksp_Jac,vode_Jac,vode_Jac,str);CHKERRQ(ierr);
00371 
00372   MagparFunctionProfReturn(0);
00373 }
00374 
00375 
00376 /* adapted from $PETSC_DIR/src/ts/impls/implicit/pvode/petscpvode.c */
00377 
00378 int PSolve(realtype t,N_Vector y,N_Vector fy,N_Vector r,N_Vector z,realtype gamma,realtype delta,int lr,void *P_data,N_Vector vtemp)
00379 {
00380   MagparFunctionInfoBegin;
00381 
00382   /* as defined in call to CVSpgmr in pvode_init: 1==left, 2==right */
00383   assert(lr==1);
00384 
00385 #ifdef UNIPROC
00386   ierr = VecPlaceArray(vode_w1,NV_DATA_S(r));CHKERRQ(ierr);
00387   ierr = VecPlaceArray(vode_w2,NV_DATA_S(z));CHKERRQ(ierr);
00388 #else
00389   ierr = VecPlaceArray(vode_w1,NV_DATA_P(r));CHKERRQ(ierr);
00390   ierr = VecPlaceArray(vode_w2,NV_DATA_P(z));CHKERRQ(ierr);
00391 #endif
00392 
00393 /* no difference in performance visible with mumag std prob. #4
00394    between abstol=0.1*delta*abstol and reltol=0.01
00395    because just 1 interation is usually sufficient
00396    (except if the Jacobian has been recalculated)
00397 
00398   KSP ksp_Jac;
00399   ierr = KSPSetTolerances(ksp_Jac,0.01,0.0,PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
00400 
00401   PetscInfo3(0,"set atol to: 0.1*delta*ewt[0]=%g*%g=%g\n",
00402     delta,NV_DATA_P(ewt)[0],0.1*delta*NV_DATA_P(ewt)[0]
00403   );
00404   ierr = KSPSetTolerances(ksp_Jac,0.0,0.1*delta*NV_DATA_P(ewt)[0],PETSC_DEFAULT,PETSC_DEFAULT);CHKERRQ(ierr);
00405 */
00406 
00407 /* TODO: useful/necessary before every call to KSPSolve?
00408 */
00409 /*
00410   ierr = KSPSetInitialGuessKnoll(ksp_Jac,PETSC_TRUE);CHKERRQ(ierr);
00411   ierr = KSPSetInitialGuessNonzero(ksp_Jac,PETSC_TRUE);CHKERRQ(ierr);
00412 */
00413   int its1;
00414   ierr = KSPSolve(ksp_Jac,vode_w1,vode_w2);CHKERRQ(ierr);
00415 
00416   ierr = VecResetArray(vode_w1);CHKERRQ(ierr);
00417   ierr = VecResetArray(vode_w2);CHKERRQ(ierr);
00418 
00419   ierr = KSPGetIterationNumber(ksp_Jac,(PetscInt*)&its1);CHKERRQ(ierr);
00420   KSPConvergedReason reason;
00421   ierr = KSPGetConvergedReason(ksp_Jac,&reason);CHKERRQ(ierr);
00422 
00423   ierr = PetscGetTime(&t_t2);CHKERRQ(ierr);
00424   PetscInfo2(0,"timing: %s took %g s\n",__FUNCT__,t_t2-t_t1);
00425   PetscInfo2(0,"psolve: %i its, reason: %i\n",its1,reason);
00426   if (reason<0) {
00427     PetscReal rnorm;
00428 
00429     ierr = KSPGetResidualNorm(ksp_Jac,&rnorm);CHKERRQ(ierr);
00430     PetscPrintf(PETSC_COMM_WORLD,
00431       "Warning: psolve: KSP did not converge - reason: %i, rnorm: %g, its: %i\n",
00432       reason,rnorm,its1
00433     );
00434   }
00435 
00436   MagparFunctionProfReturn(0);
00437 }
00438 
00439 
00440 int Jtimes(N_Vector v,N_Vector Jv,realtype t,N_Vector y,N_Vector fy,void *jac_data,N_Vector tmp)
00441 {
00442   MagparFunctionInfoBegin;
00443 
00444 #ifdef UNIPROC
00445   ierr = VecPlaceArray(vode_w1,NV_DATA_S(v));CHKERRQ(ierr);
00446   ierr = VecPlaceArray(vode_w2,NV_DATA_S(Jv));CHKERRQ(ierr);
00447 #else
00448   ierr = VecPlaceArray(vode_w1,NV_DATA_P(v));CHKERRQ(ierr);
00449   ierr = VecPlaceArray(vode_w2,NV_DATA_P(Jv));CHKERRQ(ierr);
00450 #endif
00451 
00452   ierr = MatMult(vode_pmat,vode_w1,vode_w2);CHKERRQ(ierr);
00453 
00454   ierr = VecResetArray(vode_w1);CHKERRQ(ierr);
00455   ierr = VecResetArray(vode_w2);CHKERRQ(ierr);
00456 
00457   MagparFunctionProfReturn(0);
00458 }

magpar - Parallel Finite Element Micromagnetics Package
Copyright (C) 2002-2009 Werner Scholz