checkiterationllg.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: checkiterationllg.c 2681 2009-07-31 04:30:53Z scholz $\n\n";
00025 static char const Td[] = "$Today: " __FILE__ "  " __DATE__ "  "  __TIME__  " $\n\n";
00026 
00027 #include "llg.h"
00028 #include "io/magpario.h"
00029 #include "util/util.h"
00030 #include "field/field.h"
00031 
00032 #ifdef ADDONS
00033 #include "addons/addons.h"
00034 #endif
00035 
00036 static int         doinit=1;
00037 
00038 static PetscReal   tol;
00039 static PetscReal   renormtol=-1.0;
00040 static int         condinp_equil;
00041 static PetscReal   condinp_j;
00042 static PetscReal   condinp_equil_j;
00043 static PetscReal   condinp_t;
00044 static PetscReal   *condinp_user=PETSC_NULL;
00045 static int         userinptot = 0;
00046 
00047 /* TODO: resolve this extern dependency */
00048 extern KSP ksp_Au1;
00049 extern KSP ksp_Au2;
00050 extern realtype abstol, reltol; 
00052 int adjtoldem(GridData *gdata, double fac)
00053 {
00054   MagparFunctionInfoBegin;
00055 
00056   if (gdata->VHdem==PETSC_NULL) {
00057     MagparFunctionInfoReturn(0);
00058   }
00059 
00060   PetscReal rtol, atol, dtol;
00061   int maxits;
00062 
00063   ierr = KSPGetTolerances(ksp_Au1,&rtol,&atol,&dtol,(PetscInt*)&maxits);CHKERRQ(ierr);
00064 
00065   if (rtol < 1e-10) {
00066     MagparFunctionInfoReturn(0);
00067   }
00068 
00069   atol *= fac;
00070   rtol *= fac;
00071   ierr = KSPSetTolerances(ksp_Au1,rtol,atol,dtol,maxits);CHKERRQ(ierr);
00072 
00073   PetscPrintf(PETSC_COMM_WORLD,
00074     "at t=%g ns: ",gdata->time*gdata->tscale*1e9
00075   );
00076 
00077   PetscPrintf(PETSC_COMM_WORLD,
00078     "%s KSP reltol to %g , abstol to %g\n",
00079     fac>1.0 ? "Increased" : "Reduced",
00080     rtol,atol
00081   );
00082 
00083   ierr = KSPGetTolerances(ksp_Au2,&rtol,&atol,&dtol,(PetscInt*)&maxits);CHKERRQ(ierr);
00084   atol *= fac;
00085   rtol *= fac;
00086   ierr = KSPSetTolerances(ksp_Au2,rtol,atol,dtol,maxits);CHKERRQ(ierr);
00087 
00088   MagparFunctionInfoReturn(0);
00089 }
00090 
00091 
00092 int adjtol(GridData *gdata, double fac)
00093 {
00094   MagparFunctionInfoBegin;
00095 
00096   if (reltol < 1e-10) {
00097     MagparFunctionInfoReturn(0);
00098   }
00099 
00100   PetscPrintf(PETSC_COMM_WORLD,
00101     "at t=%g ns: ",gdata->time*gdata->tscale*1e9
00102   );
00103 
00104   adjtoldem(gdata,fac);
00105 
00106   reltol *= fac;
00107   abstol *= fac;
00108 
00109   extern void *cvode_mem;
00110   long int nstep;
00111   int flag;
00112   flag=CVodeGetNumSteps(cvode_mem,&nstep);
00113   PetscPrintf(PETSC_COMM_WORLD,
00114     "%s PVODE reltol to %g , abstol to %g ; nstep since last reinit: %i\n",
00115     fac>1.0 ? "Increased" : "Reduced",
00116     reltol,abstol,nstep
00117   );
00118 
00119   ierr = PVodeReInit(gdata);CHKERRQ(ierr);
00120 
00121   MagparFunctionInfoReturn(0);
00122 }
00123 
00124 
00125 int EquilCheck(Vec M,PetscReal time,PetscReal *torque)
00126 {
00127   static PetscReal tlast=time-0.00001;
00128   static Vec Mold=PETSC_NULL;
00129 
00130   MagparFunctionInfoBegin;
00131 
00132   /* initialize upon first call */
00133   if (Mold==PETSC_NULL) {
00134     ierr = VecDuplicate(M,&Mold);CHKERRQ(ierr);
00135     ierr = VecZeroEntries(Mold);CHKERRQ(ierr);
00136 
00137     /* copy M */
00138     ierr = VecCopy(M,Mold);CHKERRQ(ierr);
00139     /* return fake value since we have not done any timesteps yet
00140        just larger than the tolerance to keep the simulation running
00141     */
00142     *torque=tol*1.01;
00143 
00144     MagparFunctionInfoReturn(0);
00145   }
00146 
00147   ierr = VecAXPY(Mold,-1.0,M);CHKERRQ(ierr);
00148 
00149   /* calculate norm of delta M */
00150   *torque=RenormVec(Mold,0.0,PETSC_MAX,ND)/(time-tlast);
00151 
00152   ierr = VecCopy(M,Mold);CHKERRQ(ierr);
00153 
00154   tlast=time;
00155 
00156   MagparFunctionProfReturn(0);
00157 }
00158 
00159 
00160 int CheckIterationLLG_Init(GridData *gdata)
00161 {
00162   PetscTruth flg;
00163 
00164   MagparFunctionLogBegin;
00165   char fn[256];
00166   char line[256];
00167   int rank;
00168   ierr = MPI_Comm_rank(PETSC_COMM_WORLD,&rank);CHKERRQ(ierr);
00169 
00170   ierr = PetscOptionsGetReal(PETSC_NULL,"-renormtol",&renormtol,&flg);CHKERRQ(ierr);
00171   if (flg!=PETSC_TRUE) {
00172     renormtol=1e-2;
00173     PetscPrintf(PETSC_COMM_WORLD,
00174       "Option -renormtol not found, using default value: %g\n",
00175       renormtol
00176     );
00177   }
00178   PetscPrintf(PETSC_COMM_WORLD,"renormtol:   %g\n",renormtol);
00179 
00180   ierr = PetscOptionsGetReal(PETSC_NULL,"-tol",&tol,&flg);CHKERRQ(ierr);
00181   if (flg!=PETSC_TRUE) {
00182     tol=1e-5;
00183     PetscPrintf(PETSC_COMM_WORLD,
00184       "Option -tol not found, using default value: %g\n",
00185       tol
00186     );
00187   }
00188   PetscPrintf(PETSC_COMM_WORLD,"tol (equilibrium): %g\n",tol);
00189 
00190   if (abstol > tol/10.0) {
00191     PetscPrintf(PETSC_COMM_WORLD,
00192       "Warning: abstol=%g should be < (tol=%g)/10.0!\n",
00193       abstol,
00194       tol
00195     );
00196   }
00197 
00198   ierr = PetscOptionsGetInt(PETSC_NULL,"-condinp_equil", (PetscInt*)&condinp_equil, &flg);CHKERRQ(ierr);
00199   if (flg!=PETSC_TRUE) {
00200     condinp_equil=1;
00201     PetscPrintf(PETSC_COMM_WORLD,
00202       "Option -condinp_equil not found, using default value: %i\n",
00203       condinp_equil
00204     );
00205   }
00206   ierr = PetscOptionsGetReal(PETSC_NULL,"-condinp_j",&condinp_j,&flg);CHKERRQ(ierr);
00207   if (flg!=PETSC_TRUE) {
00208     condinp_j=0.1;
00209     PetscPrintf(PETSC_COMM_WORLD,
00210       "Option -condinp_j not found, using default value: %g\n",
00211       condinp_j
00212     );
00213   }
00214   ierr = PetscOptionsGetReal(PETSC_NULL,"-condinp_equil_j",&condinp_equil_j,&flg);CHKERRQ(ierr);
00215   if (flg!=PETSC_TRUE) {
00216     condinp_equil_j=0.0;
00217     PetscPrintf(PETSC_COMM_WORLD,
00218       "Option -condinp_equil_j not found, using default value: %g\n",
00219       condinp_equil_j
00220     );
00221   }
00222   ierr = PetscOptionsGetReal(PETSC_NULL,"-condinp_t",&condinp_t,&flg);CHKERRQ(ierr);
00223   if (flg!=PETSC_TRUE) {
00224     condinp_t=PETSC_MAX;
00225     PetscPrintf(PETSC_COMM_WORLD,
00226       "Option -condinp_t not found, using default value: %g\n",
00227       condinp_t
00228     );
00229   }
00230 
00231   /* user times in file name specified by -condinp_user */
00232   ierr = PetscOptionsGetString(PETSC_NULL,"-condinp_file_t_ns",fn,sizeof(fn),&flg);CHKERRQ(ierr);
00233   if (flg!=PETSC_TRUE) {
00234     PetscPrintf(PETSC_COMM_WORLD,
00235       "Option -condinp_file_t_ns not found, user inp output times NOT activated\n"
00236     );
00237     userinptot = 0;
00238   }
00239   else {
00240     if (!rank) {
00241       FILE *fd=NULL;
00242       PetscPrintf(PETSC_COMM_WORLD,"Opening condinp_file_t_ns file %s\n",fn);
00243       ierr = PetscFOpen(PETSC_COMM_WORLD,fn,"r",&fd);CHKERRQ(ierr);
00244       if (!fd){
00245         SETERRQ1(PETSC_ERR_FILE_OPEN,"Cannot open %s\n",fn);
00246       }
00247       read_one_line(fd,line,sizeof(line),NULL);
00248       if (sscanf(line,"%i",&userinptot) != 1) {
00249         SETERRQ(PETSC_ERR_FILE_UNEXPECTED,"could not read number of user inp values\n");
00250       }
00251       /* alloc memory to store user time values */
00252       ierr = PetscMalloc(userinptot*sizeof(PetscReal),&condinp_user);CHKERRQ(ierr);
00253 
00254       for (int i=0;i<userinptot;i++) {
00255         read_one_line(fd,line,sizeof(line),NULL);
00256         if (sscanf(line,"%lf",condinp_user + i) != 1) {
00257         SETERRQ1(PETSC_ERR_FILE_UNEXPECTED,"could not read user inp time value %i\n",i);
00258         }
00259         condinp_user[i] /= 1e9*gdata->tscale;
00260       }
00261 
00262       PetscPrintf(PETSC_COMM_WORLD,"Number of user inp output times read in: %i\n",userinptot);
00263       ierr = PetscFClose(PETSC_COMM_WORLD,fd);CHKERRQ(ierr);
00264     }
00265     /* broadcast condinp_user data to all processors */
00266     ierr = MPI_Bcast(&userinptot,1,MPI_INT,0,PETSC_COMM_WORLD);CHKERRQ(ierr);
00267     if (rank) {
00268       ierr = PetscMalloc(userinptot*sizeof(PetscReal),&condinp_user);CHKERRQ(ierr);
00269     }
00270     ierr = MPI_Bcast(condinp_user,userinptot,MPIU_SCALAR,0,PETSC_COMM_WORLD);CHKERRQ(ierr);
00271   }
00272   condinp_t /= 1e9*gdata->tscale;
00273 
00274   MagparFunctionLogReturn(0);
00275 }
00276 
00277 
00278 int CheckIterationLLG(GridData *gdata)
00279 {
00280   static PetscReal Etotold=PETSC_MAX;
00281   static PetscReal hextold=PETSC_MAX;
00282   static PetscReal condinp_last_t=PETSC_MIN;
00283   static PetscReal condinp_last_j=PETSC_MIN;
00284   static PetscReal condinp_last_equil_j=PETSC_MIN;
00285 
00286   const PetscReal  tolscale=3.0;
00287 
00288   static int nsteps=-1;
00289   static int csteps;
00290 
00291   static PetscReal Edemold=gdata->Edem;
00292   static PetscReal dEdem1=0;
00293   static PetscReal dEdem2=0;
00294 
00295   static PetscReal timelast=gdata->time;
00296 
00297   static int userinpindex = 0;
00298 
00299 #undef CHKDMDT
00300 #ifdef CHKDMDT
00301   static Vec dMdt;
00302 #endif
00303 
00304   MagparFunctionInfoBegin;
00305 
00306   /* initialize if necessary */
00307   if (doinit) {
00308     ierr = CheckIterationLLG_Init(gdata);CHKERRQ(ierr);
00309 #ifdef CHKDMDT
00310     VecDuplicate(gdata->M,&dMdt);
00311 #endif
00312     doinit=0;
00313   }
00314 
00315 #ifdef CHKDMDT
00316   /* This method could be more expensive than the old method because
00317      we recalculate all the fields when we call calc_dMdt!
00318      However, we would get access the old dMdt - then it would be cheaper.
00319   */
00320   PetscReal veq;
00321   calc_dMdt(PETSC_NULL,0.0,gdata->M,dMdt,gdata);
00322   veq=RenormVec(dMdt,0.0,PETSC_MAX,ND);
00323   gdata->equil=veq;
00324 
00325 #if 1
00326   ierr = EquilCheck(gdata->M,gdata->time,&gdata->vequil);CHKERRQ(ierr);
00327 #endif
00328 
00329   PetscPrintf(PETSC_COMM_WORLD,"torque = %g  %g  %g\n",veq,gdata->vequil,veq/gdata->vequil);
00330 #else
00331   ierr = EquilCheck(gdata->M,gdata->time,&gdata->vequil);CHKERRQ(ierr);
00332 #endif
00333 
00334   /* We could also use differential dMdt calculated in calc_dMdt through RHSfunction (see there).
00335      However, there is more noise than if we take the finite difference over one full time step.
00336   */
00337 
00338   if (gdata->vequil < tol) {
00339     /* count how long we have been in equilibrium in succession */
00340     gdata->equil++;
00341   }
00342   else {
00343     /* reset counter if we are not in equilibrium */
00344     gdata->equil=0;
00345   }
00346 
00347   /* check if total energy increased (which it should not)
00348      print warning only if external field has not changed
00349   */
00350   PetscReal hext;
00351   hext=Hexternal_hext();
00352   if (gdata->Etot > Etotold &&
00353       hext == hextold &&
00354       ((gdata->Etot-Etotold)/Etotold)>1e-8) {
00355 
00356     PetscPrintf(MPI_COMM_WORLD,
00357       "Warning (t=%g ns): Etot increased by %g (%g*Etot) from %g to %g J/m^3\n",
00358       gdata->time*gdata->tscale*1e9,
00359       (gdata->Etot-Etotold)*gdata->escale,
00360       (gdata->Etot-Etotold)/Etotold,
00361       Etotold*gdata->escale,
00362       gdata->Etot*gdata->escale
00363     );
00364 
00365 /*
00366     ierr = adjtol(gdata,1.0/tolscale);CHKERRQ(ierr);
00367 */
00368   }
00369   Etotold=gdata->Etot;
00370   hextold=hext;
00371 
00372   PetscReal valMpHext;
00373   ierr = MpHext(gdata->M,&valMpHext);CHKERRQ(ierr);
00374 
00375   /* check if a set of output data should be written */
00376   if (PetscAbsReal(valMpHext-condinp_last_j) > condinp_j) {
00377     gdata->inp=PetscAbsInt(gdata->inp);
00378 
00379     condinp_last_t=gdata->time;
00380     condinp_last_j=valMpHext;
00381   }
00382   else if (PetscAbsReal(gdata->time-condinp_last_t) > condinp_t) {
00383     gdata->inp=PetscAbsInt(gdata->inp);
00384 
00385     condinp_last_t=gdata->time;
00386     condinp_last_j=valMpHext;
00387   }
00388   else if ( userinpindex < userinptot && gdata->time >= condinp_user[userinpindex]) {
00389       gdata->inp=PetscAbsInt(gdata->inp);
00390 
00391       condinp_last_t=gdata->time;
00392       condinp_last_j=valMpHext;
00393       userinpindex++;
00394   }
00395   else if (condinp_equil==1 && gdata->equil > 0) {
00396     /* check for condinp_equil_j (defaults to 0.0) */
00397     if (PetscAbsReal(valMpHext-condinp_last_equil_j) > condinp_equil_j) {
00398       gdata->inp=PetscAbsInt(gdata->inp);
00399 
00400       condinp_last_t=gdata->time;
00401       condinp_last_j=valMpHext;
00402       condinp_last_equil_j=valMpHext;
00403     }
00404   }
00405 
00406   if (nsteps<0) {
00407     PetscTruth flg;
00408     ierr = PetscOptionsGetInt(PETSC_NULL,"-ts_logsteps",(PetscInt*)&nsteps,&flg);CHKERRQ(ierr);
00409     if (flg!=PETSC_TRUE) {
00410       nsteps=1;
00411       PetscPrintf(PETSC_COMM_WORLD,
00412         "Option -ts_logsteps not found, using default value: %i\n",
00413         nsteps
00414       );
00415     }
00416     if (nsteps<1) {
00417       SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Option set: -ts_logsteps %i, but has to be >0\n",nsteps);
00418     }
00419     csteps=0;
00420   }
00421 
00422   if (csteps % nsteps == 0 || gdata->equil>0) {
00423     ierr = WriteLog(gdata);CHKERRQ(ierr);
00424     ierr = WriteSet(gdata);CHKERRQ(ierr);
00425     csteps=0;
00426   }
00427   csteps++;
00428 
00429 #ifdef ADDONS
00430   /* move magnetization if requested */
00431   ierr = MovingField(gdata);CHKERRQ(ierr);
00432 #endif
00433 
00434   extern void *cvode_mem;
00435   long int nstep;
00436   int flag;
00437   flag=CVodeGetNumSteps(cvode_mem,&nstep);
00438 
00439   /* update external field if system is in equilibrium */
00440   if (gdata->equil>0) {
00441     ierr = Hext_ho_hstep(gdata);CHKERRQ(ierr);
00442 
00443     /* check if we are still in equilibrium */
00444     if (gdata->equil>0) {
00445       /* that's because the field has not been changed */
00446       PetscPrintf(PETSC_COMM_WORLD,"gdata->equil %i >= 1\n",gdata->equil);
00447       gdata->mode=99;
00448     }
00449     /* restart PVODE because the external field is changed abruptly */
00450     else if (nstep>0) {
00451       ierr = PVodeReInit(gdata);CHKERRQ(ierr);
00452     }
00453   }
00454 
00455   /* renormalize M _after_ WriteLog to have consistent data in logfile */
00456 
00457   PetscReal devNorm;
00458   devNorm=RenormVec(gdata->M,1.0,renormtol,ND);
00459 
00460   if (PetscAbsReal(devNorm) > renormtol) {
00461     PetscPrintf(PETSC_COMM_WORLD,
00462       "t=%g ns: renormalized M because |%g| > %g\n",
00463       gdata->time*gdata->tscale*1e9,
00464       devNorm,
00465       renormtol
00466     );
00467 
00468     /* if renormalization occurs within 3 timesteps */
00469     if (nstep<3 && reltol > 1e-10) {
00470       /* adjust tolerances */
00471       ierr = adjtol(gdata,1.0/tolscale);CHKERRQ(ierr);
00472     }
00473     else {
00474       /* only reinit PVODE after renormalization */
00475       ierr = PVodeReInit(gdata);CHKERRQ(ierr);
00476     }
00477   }
00478   /* check if timestep is very small */
00479   else if ((gdata->time-timelast)*gdata->tscale*1e9<1e-5 && nstep>100) {
00480     PetscInfo2(0,
00481       "Warning (t=%g ns): timestep is %g < 1e-4\n",
00482       gdata->time*gdata->tscale*1e9,
00483       (gdata->time-timelast)*gdata->tscale*1e9
00484     );
00485 /*
00486     ierr = adjtol(gdata,1.0/tolscale);CHKERRQ(ierr);
00487     ierr = adjtoldem(gdata,1.0/tolscale);CHKERRQ(ierr);
00488 */
00489 
00490     if (gdata->VHdem!=PETSC_NULL &&
00491           (gdata->Edem-Edemold)*dEdem1<0 &&
00492           (gdata->Edem-Edemold)*dEdem2>0) {
00493       PetscInfo2(0,
00494         "and Edem oscillates: %g %g\n",
00495         gdata->Edem,
00496         Edemold
00497       );
00498 /*
00499       PetscPrintf(PETSC_COMM_WORLD,
00500         "and Edem oscillates: %g %g %g %g\n",
00501         gdata->Edem,
00502         Edemold,
00503         gdata->Edem-Edemold,
00504         dEdem1,
00505         dEdem2
00506       );
00507 */
00508 /*
00509       ierr = adjtoldem(gdata,1.0/tolscale);CHKERRQ(ierr);
00510 */
00511     }
00512   }
00513   /* check if Edem oscillates */
00514   else if (gdata->VHdem!=PETSC_NULL &&
00515            (gdata->Edem-Edemold)*dEdem1<0 &&
00516            (gdata->Edem-Edemold)*dEdem2>0) {
00517     PetscInfo2(0,
00518       "Warning (t=%g ns): Edem oscillates: %g\n",
00519       gdata->time*gdata->tscale*1e9,
00520       gdata->Edem
00521     );
00522 /*
00523     PetscPrintf(PETSC_COMM_WORLD,
00524       "Warning (t=%g ns): Edem oscillates: %g %g %g %g %g\n",
00525       gdata->time*gdata->tscale*1e9,
00526       gdata->Edem,
00527       Edemold,
00528       gdata->Edem-Edemold,
00529       dEdem1,
00530       dEdem2
00531     );
00532 */
00533 /*
00534     ierr = adjtoldem(gdata,1.0/tolscale);CHKERRQ(ierr);
00535 */
00536   }
00537   /* don't do this !?
00538     may lead to
00539     large tolerances->large error->norm not preserved->
00540     minimum time step->very slow simulation
00541   */
00542   else {
00543     long int ncfn;
00544     extern void *cvode_mem;
00545     CVodeGetNumNonlinSolvConvFails(cvode_mem,&ncfn);
00546     if (nstep > 30 &&
00547         devNorm <= renormtol/100.0 &&
00548         reltol <= tol/10.0 &&
00549         reltol <= 1e-2 &&
00550         ncfn == 0) {
00551       ierr = adjtol(gdata,tolscale);CHKERRQ(ierr);
00552     }
00553   }
00554 
00555   timelast=gdata->time;
00556 
00557   dEdem2=dEdem1;
00558   dEdem1=gdata->Edem-Edemold;
00559   Edemold=gdata->Edem;
00560 
00561   MagparFunctionProfReturn(0);
00562 }

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