| 1 | /** \file ions.c | 
|---|
| 2 | * Ionic Force, speed, coordinate and energy calculation. | 
|---|
| 3 | * Herein are all the routines for the molecular dynamics calculations such as | 
|---|
| 4 | * reading of configuration files IonsInitRead() and | 
|---|
| 5 | * free'ing RemoveIonsRead(), | 
|---|
| 6 | * summing up forces CalculateIonForce(), | 
|---|
| 7 | * correcting for temperature CorrectVelocities(), | 
|---|
| 8 | * or for fixation center of balance CorrectForces(), | 
|---|
| 9 | * outputting them to file OutputIonForce(), | 
|---|
| 10 | * calculating kinetic CalculateEnergyIonsU(), ewald CalculateEwald() energies, | 
|---|
| 11 | * moving ion UpdateIonsR() (position) UpdateIonsU() (speed), | 
|---|
| 12 | * scaling to match some temperature ScaleTemp() | 
|---|
| 13 | * are gathered. | 
|---|
| 14 | * Finally, needed for structure optimization GetOuterStop() evaluates the stop | 
|---|
| 15 | * condition of a minimal mean force acting on each ion. | 
|---|
| 16 | * | 
|---|
| 17 | Project: ParallelCarParrinello | 
|---|
| 18 | \author Jan Hamaekers | 
|---|
| 19 | \date 2000 | 
|---|
| 20 |  | 
|---|
| 21 | File: ions.c | 
|---|
| 22 | $Id: ions.c,v 1.34 2007/02/05 16:15:27 foo Exp $ | 
|---|
| 23 | */ | 
|---|
| 24 |  | 
|---|
| 25 | #include <stdlib.h> | 
|---|
| 26 | #include <stdio.h> | 
|---|
| 27 | #include <stddef.h> | 
|---|
| 28 | #include <math.h> | 
|---|
| 29 | #include <string.h> | 
|---|
| 30 | #include <unistd.h> | 
|---|
| 31 | #include "mymath.h" | 
|---|
| 32 |  | 
|---|
| 33 |  | 
|---|
| 34 | // use double precision fft when we have it | 
|---|
| 35 | #ifdef HAVE_CONFIG_H | 
|---|
| 36 | #include <config.h> | 
|---|
| 37 | #endif | 
|---|
| 38 |  | 
|---|
| 39 | #ifdef HAVE_DFFTW_H | 
|---|
| 40 | #include "dfftw.h" | 
|---|
| 41 | #else | 
|---|
| 42 | #include "fftw.h" | 
|---|
| 43 | #endif | 
|---|
| 44 |  | 
|---|
| 45 | #include "data.h" | 
|---|
| 46 | #include "errors.h" | 
|---|
| 47 | #include "helpers.h" | 
|---|
| 48 | #include "mymath.h" | 
|---|
| 49 | #include "ions.h" | 
|---|
| 50 | #include "init.h" | 
|---|
| 51 |  | 
|---|
| 52 | /** Readin of the ion section of parameter file. | 
|---|
| 53 | * Among others the following paramaters are read from file: | 
|---|
| 54 | * Ions::MaxTypes, IonType::Max_IonsOfType, IonType::Z, IonType::R, | 
|---|
| 55 | * IonType:IMT, ... | 
|---|
| 56 | * \param P Problem at hand (containing Ions and Lattice structures) | 
|---|
| 57 | * \param *source file pointer | 
|---|
| 58 | */ | 
|---|
| 59 | void IonsInitRead(struct Problem *P, FILE *source) { | 
|---|
| 60 | struct Ions *I = &P->Ion; | 
|---|
| 61 | //struct RunStruct *Run = &P->R; | 
|---|
| 62 | int i,it,j,IMT,BorAng, d,me, count; | 
|---|
| 63 | int k; | 
|---|
| 64 | struct Lattice *L = &P->Lat; | 
|---|
| 65 | int relative; // whether read-in coordinate are relative (1) or absolute | 
|---|
| 66 | double Bohr = ANGSTROEMINBOHRRADIUS; /* Angstroem */ | 
|---|
| 67 | double sigma, R[3], U[3]; | 
|---|
| 68 |  | 
|---|
| 69 | I->Max_TotalIons = 0; | 
|---|
| 70 | I->TotalZval = 0; | 
|---|
| 71 | MPI_Comm_rank(MPI_COMM_WORLD, &me); | 
|---|
| 72 | ParseForParameter(P->Call.out[ReadOut],source,"RCut", 0, 1, 1, double_type, &I->R_cut, critical); | 
|---|
| 73 | ParseForParameter(P->Call.out[ReadOut],source,"IsAngstroem", 0, 1, 1, int_type, &BorAng, critical); | 
|---|
| 74 | if (!I->IsAngstroem) { | 
|---|
| 75 | Bohr = 1.0; | 
|---|
| 76 | } else {  // adapt RealBasis (is in Angstroem as well) | 
|---|
| 77 | SM(P->Lat.RealBasis, Bohr, NDIM_NDIM); | 
|---|
| 78 | RMatReci3(P->Lat.InvBasis,  P->Lat.RealBasis); | 
|---|
| 79 | } | 
|---|
| 80 | ParseForParameter(P->Call.out[ReadOut],source,"MaxTypes", 0, 1, 1, int_type, &I->Max_Types, critical); | 
|---|
| 81 | I->I = (struct IonType *) Malloc(sizeof(struct IonType)*I->Max_Types, "IonsInitRead: IonType"); | 
|---|
| 82 | if (!ParseForParameter(P->Call.out[ReadOut],source,"RelativeCoord", 0, 1, 1, int_type, &relative, optional)) | 
|---|
| 83 | relative = 0; | 
|---|
| 84 | if (!ParseForParameter(P->Call.out[ReadOut],source,"StructOpt", 0, 1, 1, int_type, &I->StructOpt, optional)) | 
|---|
| 85 | I->StructOpt = 0; | 
|---|
| 86 |  | 
|---|
| 87 | /* Ions Data */ | 
|---|
| 88 | I->RLatticeVec = NULL; | 
|---|
| 89 | I->TotalMass = 0; | 
|---|
| 90 | char *free_name, *name; | 
|---|
| 91 | name = free_name = Malloc(255*sizeof(char),"IonsInitRead: Name"); | 
|---|
| 92 | for (i=0; i < I->Max_Types; i++) { | 
|---|
| 93 | sprintf(name,"Ion_Type%i",i+1); | 
|---|
| 94 | I->I[i].corecorr = NotCoreCorrected; | 
|---|
| 95 | I->I[i].Name = MallocString(255, "IonsInitRead: Name"); | 
|---|
| 96 | I->I[i].Symbol = MallocString(255, "IonsInitRead: Symbol"); | 
|---|
| 97 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 1, 1, int_type, &I->I[i].Max_IonsOfType, critical); | 
|---|
| 98 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 2, 1, int_type, &I->I[i].Z, critical); | 
|---|
| 99 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 3, 1, double_type, &I->I[i].rgauss, critical); | 
|---|
| 100 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 4, 1, int_type, &I->I[i].l_max, critical); | 
|---|
| 101 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 5, 1, int_type, &I->I[i].l_loc, critical); | 
|---|
| 102 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 6, 1, double_type, &I->I[i].IonMass, critical); | 
|---|
| 103 | if(!ParseForParameter(P->Call.out[ReadOut],source, name, 0, 7, 1, string_type, &I->I[i].Name[0], optional)) | 
|---|
| 104 | sprintf(&I->I[i].Name[0],"type%i",i); | 
|---|
| 105 | if(!ParseForParameter(P->Call.out[ReadOut],source, name, 0, 8, 1, string_type, &I->I[i].Symbol[0], optional)) | 
|---|
| 106 | sprintf(&I->I[i].Symbol[0],"t%i",i); | 
|---|
| 107 | if (P->Call.out[ReadOut]) fprintf(stderr,"(%i) Element name: %s, symbol: %s\n",P->Par.me, I->I[i].Name, I->I[i].Symbol); | 
|---|
| 108 | I->I[i].sigma = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: sigma"); | 
|---|
| 109 | I->I[i].sigma_rezi = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: sigma_rezi"); | 
|---|
| 110 | I->I[i].sigma_PAS = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: sigma_PAS"); | 
|---|
| 111 | I->I[i].sigma_rezi_PAS = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: sigma_rezi_PAS"); | 
|---|
| 112 | for (it=0;it<I->I[i].Max_IonsOfType;it++) { | 
|---|
| 113 | I->I[i].sigma[it] = (double *) Malloc(sizeof(double) * NDIM*NDIM, "IonsInitRead: sigma"); | 
|---|
| 114 | I->I[i].sigma_rezi[it] = (double *) Malloc(sizeof(double) * NDIM*NDIM, "IonsInitRead: sigma_rezi"); | 
|---|
| 115 | I->I[i].sigma_PAS[it] = (double *) Malloc(sizeof(double) * NDIM, "IonsInitRead: sigma_PAS"); | 
|---|
| 116 | I->I[i].sigma_rezi_PAS[it] = (double *) Malloc(sizeof(double) * NDIM, "IonsInitRead: sigma_rezi_PAS"); | 
|---|
| 117 | } | 
|---|
| 118 | //I->I[i].IonFac = I->I[i].IonMass; | 
|---|
| 119 | I->I[i].IonFac = 1/I->I[i].IonMass; | 
|---|
| 120 | I->TotalMass += I->I[i].Max_IonsOfType*I->I[i].IonMass; | 
|---|
| 121 | I->I[i].ZFactor = -I->I[i].Z*4.*PI; | 
|---|
| 122 | I->I[i].alpha = (double *) Malloc(sizeof(double) * I->I[i].Max_IonsOfType, "IonsInitRead: alpha"); | 
|---|
| 123 | I->I[i].R = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: R"); | 
|---|
| 124 | I->I[i].R_old = (double *) Malloc(sizeof(double) *NDIM* I->I[i].Max_IonsOfType, "IonsInitRead: R_old"); | 
|---|
| 125 | I->I[i].R_old_old = (double *) Malloc(sizeof(double) *NDIM* I->I[i].Max_IonsOfType, "IonsInitRead: R_old_old"); | 
|---|
| 126 | I->I[i].FIon = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FIon"); | 
|---|
| 127 | I->I[i].FIon_old = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FIon_old"); | 
|---|
| 128 | SetArrayToDouble0(I->I[i].FIon_old, NDIM*I->I[i].Max_IonsOfType); | 
|---|
| 129 | I->I[i].SearchDir = Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: SearchDir"); | 
|---|
| 130 | I->I[i].GammaA = Malloc(sizeof(double) * I->I[i].Max_IonsOfType, "IonsInitRead: GammaA"); | 
|---|
| 131 | SetArrayToDouble0(I->I[i].GammaA, I->I[i].Max_IonsOfType); | 
|---|
| 132 | I->I[i].U = (double *) Malloc(sizeof(double) *NDIM* I->I[i].Max_IonsOfType, "IonsInitRead: U"); | 
|---|
| 133 | SetArrayToDouble0(I->I[i].U, NDIM*I->I[i].Max_IonsOfType); | 
|---|
| 134 | I->I[i].SFactor = NULL; | 
|---|
| 135 | I->I[i].IMT = (enum IonMoveType *) Malloc(sizeof(enum IonMoveType) * I->I[i].Max_IonsOfType, "IonsInitRead: IMT"); | 
|---|
| 136 | I->I[i].FIonL = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FIonL"); | 
|---|
| 137 | I->I[i].FIonNL = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FIonNL"); | 
|---|
| 138 | I->I[i].FEwald = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FEwald"); | 
|---|
| 139 | I->I[i].alpha = (double *) Malloc(sizeof(double) * I->I[i].Max_IonsOfType, "IonsInitRead: alpha"); | 
|---|
| 140 | for (j=0; j < I->I[i].Max_IonsOfType; j++) { | 
|---|
| 141 | I->I[i].alpha[j] = 2.; | 
|---|
| 142 | sprintf(name,"Ion_Type%i_%i",i+1,j+1); | 
|---|
| 143 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 1, 1, double_type, &R[0], critical); | 
|---|
| 144 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 2, 1, double_type, &R[1], critical); | 
|---|
| 145 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 3, 1, double_type, &R[2], critical); | 
|---|
| 146 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 4, 1, int_type, &IMT, critical); | 
|---|
| 147 | // change if coordinates were relative | 
|---|
| 148 | if (relative) { | 
|---|
| 149 | //fprintf(stderr,"(%i)Ion coordinates are relative %i ... \n",P->Par.me, relative); | 
|---|
| 150 | RMat33Vec3(&I->I[i].R[0+NDIM*j], L->RealBasis, R); // multiply with real basis | 
|---|
| 151 | } else { | 
|---|
| 152 | for (k=0;k<NDIM;k++) // and copy to old vector | 
|---|
| 153 | I->I[i].R[k+NDIM*j] = R[k]; | 
|---|
| 154 | } | 
|---|
| 155 | if (IMT < 0 || IMT >= MaxIonMoveType) { | 
|---|
| 156 | fprintf(stderr,"Bad Ion MoveType set to MoveIon for Ion (%i,%i)\n",i,j); | 
|---|
| 157 | IMT = 0; | 
|---|
| 158 | } | 
|---|
| 159 |  | 
|---|
| 160 | if ((P->Call.out[ReadOut])) {  // rotate coordinates | 
|---|
| 161 | fprintf(stderr,"(%i) coordinates of Ion %i: (x,y,z) = (",P->Par.me,j); | 
|---|
| 162 | for(k=0;k<NDIM;k++) { | 
|---|
| 163 | fprintf(stderr,"%lg ",I->I[i].R[k+NDIM*j]); | 
|---|
| 164 | if (k != NDIM-1) fprintf(stderr,", "); | 
|---|
| 165 | else fprintf(stderr,")\n"); | 
|---|
| 166 | } | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | I->I[i].IMT[j] = (enum IonMoveType)IMT; | 
|---|
| 170 | SM(&I->I[i].R[NDIM*j], 1./Bohr, NDIM); | 
|---|
| 171 | RMat33Vec3(R, L->InvBasis, &I->I[i].R[NDIM*j]); | 
|---|
| 172 | for (d=0; d <NDIM; d++) { | 
|---|
| 173 | while (R[d] < 0) | 
|---|
| 174 | R[d] += 1.0; | 
|---|
| 175 | while (R[d] >= 1.0) | 
|---|
| 176 | R[d] -= 1.0; | 
|---|
| 177 | } | 
|---|
| 178 | RMat33Vec3(&I->I[i].R[NDIM*j], L->RealBasis, R); | 
|---|
| 179 | for (d=0; d <NDIM; d++) { | 
|---|
| 180 | I->I[i].R_old_old[d+NDIM*j] = I->I[i].R_old[d+NDIM*j] = I->I[i].R[d+NDIM*j]; | 
|---|
| 181 | } | 
|---|
| 182 | I->Max_TotalIons++; | 
|---|
| 183 | } | 
|---|
| 184 | } | 
|---|
| 185 | Free(free_name); | 
|---|
| 186 | I->Max_Max_IonsOfType = 0; | 
|---|
| 187 | for (i=0; i < I->Max_Types; i++) | 
|---|
| 188 | I->Max_Max_IonsOfType = MAX(I->Max_Max_IonsOfType, I->I[i].Max_IonsOfType); | 
|---|
| 189 | I->FTemp = (double *) Malloc(sizeof(double) * NDIM * I->Max_Max_IonsOfType, "IonsInitRead:"); | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 | /** Calculated Ewald force. | 
|---|
| 193 | * \f[ | 
|---|
| 194 | *  E_{K-K} = \frac{1}{2} \sum_L \sum_{K=\{(I_s,I_a,J_s,J_a)|R_{I_s,I_a} - R_{J_s,J_a} - L\neq 0\}} \frac{Z_{I_s} Z_{J_s}} {|R_{I_s,I_a} - R_{J_s,J_a} - L|} | 
|---|
| 195 | *    \textnormal{erfc} \Bigl ( \frac{|R_{I_s,I_a} - R_{J_s,J_a} - L|} {\sqrt{r_{I_s}^{Gauss}+r_{J_s}^{Gauss}}}\Bigr ) | 
|---|
| 196 | *    \qquad (4.10) | 
|---|
| 197 | * \f] | 
|---|
| 198 | * Calculates the core-to-core force between the ions of all super cells. | 
|---|
| 199 | * In order for this series to converge there must be a certain summation | 
|---|
| 200 | * applied, which is the ewald summation and which is nothing else but to move | 
|---|
| 201 | * in a circular motion from the current cell to the outside up to Ions::R_cut. | 
|---|
| 202 | * \param *P Problem at hand | 
|---|
| 203 | * \param first additional calculation beforehand if != 0 | 
|---|
| 204 | */ | 
|---|
| 205 | void CalculateEwald(struct Problem *P, int first) | 
|---|
| 206 | { | 
|---|
| 207 | int r,is,is1,is2,ia1,ia2,ir,ir2,i,j,k,ActualVec,MaxVec,MaxCell,Is_Neighb_Cell,LocalActualVec; | 
|---|
| 208 | int MaxPar=P->Par.procs, ParMe=P->Par.me, MaxLocalVec, StartVec; | 
|---|
| 209 | double rcut2,r2,erre2,addesr,addpre,arg,fac,gkl,esr,fxx,repand; | 
|---|
| 210 | double R1[3]; | 
|---|
| 211 | double R2[3]; | 
|---|
| 212 | double R3[3]; | 
|---|
| 213 | double t[3]; | 
|---|
| 214 | struct Lattice *L = &P->Lat; | 
|---|
| 215 | struct PseudoPot *PP = &P->PP; | 
|---|
| 216 | struct Ions *I = &P->Ion; | 
|---|
| 217 | if (I->R_cut != 0.0) { | 
|---|
| 218 | if (first) { | 
|---|
| 219 | SpeedMeasure(P, InitSimTime, StopTimeDo); | 
|---|
| 220 | rcut2 = I->R_cut*I->R_cut; | 
|---|
| 221 | ActualVec =0; | 
|---|
| 222 | MaxCell = (int)5.*I->R_cut/pow(L->Volume,1./3.); | 
|---|
| 223 | if (MaxCell < 2) MaxCell = 2; | 
|---|
| 224 | for (i = -MaxCell; i <= MaxCell; i++) { | 
|---|
| 225 | for (j = -MaxCell; j <= MaxCell; j++) { | 
|---|
| 226 | for (k = -MaxCell; k <= MaxCell; k++) { | 
|---|
| 227 | r2 = 0.0; | 
|---|
| 228 | for (ir=0; ir <3; ir++) { | 
|---|
| 229 | t[ir] = i*L->RealBasis[0*NDIM+ir]+j*L->RealBasis[1*NDIM+ir]+k*L->RealBasis[2*NDIM+ir]; | 
|---|
| 230 | r2 = t[ir]*t[ir]; | 
|---|
| 231 | } | 
|---|
| 232 | Is_Neighb_Cell = ((abs(i)<=1) && (abs(j)<=1) && (abs(k)<=1)); | 
|---|
| 233 | if ((r2 <= rcut2) || Is_Neighb_Cell) { | 
|---|
| 234 | ActualVec++; | 
|---|
| 235 | } | 
|---|
| 236 | } | 
|---|
| 237 | } | 
|---|
| 238 | } | 
|---|
| 239 | MaxVec = ActualVec; | 
|---|
| 240 | I->MaxVec = ActualVec; | 
|---|
| 241 | MaxLocalVec = MaxVec / MaxPar; | 
|---|
| 242 | StartVec = ParMe*MaxLocalVec; | 
|---|
| 243 | r = MaxVec % MaxPar; | 
|---|
| 244 | if (ParMe >= r) { | 
|---|
| 245 | StartVec += r; | 
|---|
| 246 | } else { | 
|---|
| 247 | StartVec += ParMe; | 
|---|
| 248 | MaxLocalVec++; | 
|---|
| 249 | } | 
|---|
| 250 | I->MaxLocalVec = MaxLocalVec; | 
|---|
| 251 | LocalActualVec = ActualVec = 0; | 
|---|
| 252 | I->RLatticeVec = (double *) | 
|---|
| 253 | Realloc(I->RLatticeVec, sizeof(double)*NDIM*MaxLocalVec, "CalculateEwald:"); | 
|---|
| 254 | for (i = -MaxCell; i <= MaxCell; i++) { | 
|---|
| 255 | for (j = -MaxCell; j <= MaxCell; j++) { | 
|---|
| 256 | for (k = -MaxCell; k <= MaxCell; k++) { | 
|---|
| 257 | r2 = 0.0; | 
|---|
| 258 | for (ir=0; ir <3; ir++) { | 
|---|
| 259 | t[ir] = i*L->RealBasis[0*NDIM+ir]+j*L->RealBasis[1*NDIM+ir]+k*L->RealBasis[2*NDIM+ir]; | 
|---|
| 260 | r2 = t[ir]*t[ir]; | 
|---|
| 261 | } | 
|---|
| 262 | Is_Neighb_Cell = ((abs(i)<=1) && (abs(j)<=1) && (abs(k)<=1)); | 
|---|
| 263 | if ((r2 <= rcut2) || Is_Neighb_Cell) { | 
|---|
| 264 | if (ActualVec >= StartVec && ActualVec < StartVec+MaxLocalVec) { | 
|---|
| 265 | I->RLatticeVec[0+NDIM*LocalActualVec] = t[0]; | 
|---|
| 266 | I->RLatticeVec[1+NDIM*LocalActualVec] = t[1]; | 
|---|
| 267 | I->RLatticeVec[2+NDIM*LocalActualVec] = t[2]; | 
|---|
| 268 | LocalActualVec++; | 
|---|
| 269 | } | 
|---|
| 270 | ActualVec++; | 
|---|
| 271 | } | 
|---|
| 272 | } | 
|---|
| 273 | } | 
|---|
| 274 | } | 
|---|
| 275 | SpeedMeasure(P, InitSimTime, StartTimeDo); | 
|---|
| 276 | } | 
|---|
| 277 | SpeedMeasure(P, EwaldTime, StartTimeDo); | 
|---|
| 278 | esr = 0.0; | 
|---|
| 279 | for (is1=0;is1 < I->Max_Types; is1++) | 
|---|
| 280 | for (ia1=0;ia1 < I->I[is1].Max_IonsOfType; ia1++) | 
|---|
| 281 | for (i=0; i< NDIM; i++) | 
|---|
| 282 | I->FTemp[i+NDIM*(ia1)] = 0; | 
|---|
| 283 | for (is1=0;is1 < I->Max_Types; is1++) { | 
|---|
| 284 | for (ia1=0;ia1 < I->I[is1].Max_IonsOfType; ia1++) { | 
|---|
| 285 | for (i=0;i<3;i++) { | 
|---|
| 286 | R1[i]=I->I[is1].R[i+NDIM*ia1]; | 
|---|
| 287 | } | 
|---|
| 288 | for (ir2=0;ir2<I->MaxLocalVec;ir2++) { | 
|---|
| 289 | for (is2=0;is2 < I->Max_Types; is2++) { | 
|---|
| 290 | gkl=1./sqrt(I->I[is1].rgauss*I->I[is1].rgauss + I->I[is2].rgauss*I->I[is2].rgauss); | 
|---|
| 291 | for (ia2=0;ia2<I->I[is2].Max_IonsOfType; ia2++) { | 
|---|
| 292 | for (i=0;i<3;i++) { | 
|---|
| 293 | R2[i]=I->RLatticeVec[i+NDIM*ir2]+I->I[is2].R[i+NDIM*ia2]; | 
|---|
| 294 | } | 
|---|
| 295 | erre2=0.0; | 
|---|
| 296 | for (i=0;i<3;i++) { | 
|---|
| 297 | R3[i] = R1[i]-R2[i]; | 
|---|
| 298 | erre2+=R3[i]*R3[i]; | 
|---|
| 299 | } | 
|---|
| 300 | if (erre2 > MYEPSILON) { | 
|---|
| 301 | arg=sqrt(erre2); | 
|---|
| 302 | fac=PP->zval[is1]*PP->zval[is2]/arg*0.5; | 
|---|
| 303 |  | 
|---|
| 304 | arg *= gkl; | 
|---|
| 305 | addesr = derf(arg); | 
|---|
| 306 | addesr = (1.0-addesr)*fac; | 
|---|
| 307 | esr += addesr; | 
|---|
| 308 | addpre=exp(-arg*arg)*gkl; | 
|---|
| 309 | addpre=PP->fac1sqrtPI*PP->zval[is1]*PP->zval[is2]*addpre; | 
|---|
| 310 | repand=(addesr+addpre)/erre2; | 
|---|
| 311 | for (i=0;i<3;i++) { | 
|---|
| 312 | fxx=repand*R3[i]; | 
|---|
| 313 | /*fprintf(stderr,"%i %i %i %i %i %g\n",is1+1,ia1+1,is2+1,ia2+1,i+1,fxx);*/ | 
|---|
| 314 | I->FTemp[i+NDIM*(ia1)] += fxx; | 
|---|
| 315 | I->FTemp[i+NDIM*(ia2)] -= fxx; | 
|---|
| 316 | } | 
|---|
| 317 | } | 
|---|
| 318 | } | 
|---|
| 319 | } | 
|---|
| 320 | } | 
|---|
| 321 | } | 
|---|
| 322 | } | 
|---|
| 323 | } else { | 
|---|
| 324 | esr = 0.0; | 
|---|
| 325 | for (is1=0;is1 < I->Max_Types; is1++) | 
|---|
| 326 | for (ia1=0;ia1 < I->I[is1].Max_IonsOfType; ia1++) | 
|---|
| 327 | for (i=0; i< NDIM; i++) | 
|---|
| 328 | I->FTemp[i+NDIM*(ia1)] = 0.; | 
|---|
| 329 | } | 
|---|
| 330 | SpeedMeasure(P, EwaldTime, StopTimeDo); | 
|---|
| 331 | for (is=0;is < I->Max_Types; is++) { | 
|---|
| 332 | MPI_Allreduce (I->FTemp , I->I[is].FEwald, NDIM*I->I[is].Max_IonsOfType, MPI_DOUBLE, MPI_SUM, P->Par.comm); | 
|---|
| 333 | } | 
|---|
| 334 | MPI_Allreduce ( &esr, &L->E->AllTotalIonsEnergy[EwaldEnergy], 1, MPI_DOUBLE, MPI_SUM, P->Par.comm); | 
|---|
| 335 | } | 
|---|
| 336 |  | 
|---|
| 337 | /** Sum up all forces acting on Ions. | 
|---|
| 338 | * IonType::FIon = IonType::FEwald  + IonType::FIonL + IonType::FIonNL for all | 
|---|
| 339 | * dimensions #NDIM and each Ion of IonType | 
|---|
| 340 | * \param *P Problem at hand | 
|---|
| 341 | */ | 
|---|
| 342 | void CalculateIonForce(struct Problem *P) | 
|---|
| 343 | { | 
|---|
| 344 | struct Ions *I = &P->Ion; | 
|---|
| 345 | int i,j,d; | 
|---|
| 346 | for (i=0; i < I->Max_Types; i++) | 
|---|
| 347 | for (j=0; j < I->I[i].Max_IonsOfType; j++) | 
|---|
| 348 | for (d=0; d<NDIM;d++) | 
|---|
| 349 | I->I[i].FIon[d+j*NDIM] = I->I[i].FEwald[d+j*NDIM] + I->I[i].FIonL[d+j*NDIM] + I->I[i].FIonNL[d+j*NDIM]; | 
|---|
| 350 | } | 
|---|
| 351 |  | 
|---|
| 352 | /** Write Forces to FileData::ForcesFile. | 
|---|
| 353 | * goes through all Ions per IonType and each dimension of #NDIM and prints in one line: | 
|---|
| 354 | * Position IonType::R, total force Ion IonType::FIon, local force IonType::FIonL, | 
|---|
| 355 | * non-local IonType::FIonNL, ewald force IonType::FEwald | 
|---|
| 356 | * \param *P Problem at hand | 
|---|
| 357 | */ | 
|---|
| 358 | void OutputIonForce(struct Problem *P) | 
|---|
| 359 | { | 
|---|
| 360 | struct RunStruct *R = &P->R; | 
|---|
| 361 | struct FileData *F = &P->Files; | 
|---|
| 362 | struct Ions *I = &P->Ion; | 
|---|
| 363 | FILE *fout = NULL; | 
|---|
| 364 | int i,j; | 
|---|
| 365 | if (F->MeOutMes != 1) return; | 
|---|
| 366 | fout = F->ForcesFile; | 
|---|
| 367 | for (i=0; i < I->Max_Types; i++) | 
|---|
| 368 | for (j=0; j < I->I[i].Max_IonsOfType; j++) | 
|---|
| 369 | fprintf(fout, "%i\t%i\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\t%e\n", i,j, | 
|---|
| 370 | I->I[i].R[0+j*NDIM], I->I[i].R[1+j*NDIM], I->I[i].R[2+j*NDIM], | 
|---|
| 371 | I->I[i].FIon[0+j*NDIM], I->I[i].FIon[1+j*NDIM], I->I[i].FIon[2+j*NDIM], | 
|---|
| 372 | I->I[i].FIonL[0+j*NDIM], I->I[i].FIonL[1+j*NDIM], I->I[i].FIonL[2+j*NDIM], | 
|---|
| 373 | I->I[i].FIonNL[0+j*NDIM], I->I[i].FIonNL[1+j*NDIM], I->I[i].FIonNL[2+j*NDIM], | 
|---|
| 374 | I->I[i].FEwald[0+j*NDIM], I->I[i].FEwald[1+j*NDIM], I->I[i].FEwald[2+j*NDIM]); | 
|---|
| 375 | fflush(fout); | 
|---|
| 376 | fprintf(fout, "MeanForce:\t%e\n", R->MeanForce[0]); | 
|---|
| 377 | } | 
|---|
| 378 |  | 
|---|
| 379 | /** Frees memory IonType. | 
|---|
| 380 | * All pointers from IonType and the pointer on it are free'd | 
|---|
| 381 | * \param *I Ions structure to be free'd | 
|---|
| 382 | * \sa IonsInitRead where memory is allocated | 
|---|
| 383 | */ | 
|---|
| 384 | void RemoveIonsRead(struct Ions *I) | 
|---|
| 385 | { | 
|---|
| 386 | int i, it; | 
|---|
| 387 | for (i=0; i < I->Max_Types; i++) { | 
|---|
| 388 | //fprintf(stderr,"Name\n"); | 
|---|
| 389 | Free(I->I[i].Name); | 
|---|
| 390 | //fprintf(stderr,"Abbreviation\n"); | 
|---|
| 391 | Free(I->I[i].Symbol); | 
|---|
| 392 | for (it=0;it<I->I[i].Max_IonsOfType;it++) { | 
|---|
| 393 | //fprintf(stderr,"sigma[it]\n"); | 
|---|
| 394 | Free(I->I[i].sigma[it]); | 
|---|
| 395 | //fprintf(stderr,"sigma_rezi[it]\n"); | 
|---|
| 396 | Free(I->I[i].sigma_rezi[it]); | 
|---|
| 397 | //fprintf(stderr,"sigma_PAS[it]\n"); | 
|---|
| 398 | Free(I->I[i].sigma_PAS[it]); | 
|---|
| 399 | //fprintf(stderr,"sigma_rezi_PAS[it]\n"); | 
|---|
| 400 | Free(I->I[i].sigma_rezi_PAS[it]); | 
|---|
| 401 | } | 
|---|
| 402 | //fprintf(stderr,"sigma\n"); | 
|---|
| 403 | Free(I->I[i].sigma); | 
|---|
| 404 | //fprintf(stderr,"sigma_rezi\n"); | 
|---|
| 405 | Free(I->I[i].sigma_rezi); | 
|---|
| 406 | //fprintf(stderr,"sigma_PAS\n"); | 
|---|
| 407 | Free(I->I[i].sigma_PAS); | 
|---|
| 408 | //fprintf(stderr,"sigma_rezi_PAS\n"); | 
|---|
| 409 | Free(I->I[i].sigma_rezi_PAS); | 
|---|
| 410 | //fprintf(stderr,"R\n"); | 
|---|
| 411 | Free(I->I[i].R); | 
|---|
| 412 | //fprintf(stderr,"R_old\n"); | 
|---|
| 413 | Free(I->I[i].R_old); | 
|---|
| 414 | //fprintf(stderr,"R_old_old\n"); | 
|---|
| 415 | Free(I->I[i].R_old_old); | 
|---|
| 416 | //fprintf(stderr,"FIon\n"); | 
|---|
| 417 | Free(I->I[i].FIon); | 
|---|
| 418 | //fprintf(stderr,"FIon_old\n"); | 
|---|
| 419 | Free(I->I[i].FIon_old); | 
|---|
| 420 | //fprintf(stderr,"SearchDir\n"); | 
|---|
| 421 | Free(I->I[i].SearchDir); | 
|---|
| 422 | //fprintf(stderr,"GammaA\n"); | 
|---|
| 423 | Free(I->I[i].GammaA); | 
|---|
| 424 | //fprintf(stderr,"FIonL\n"); | 
|---|
| 425 | Free(I->I[i].FIonL); | 
|---|
| 426 | //fprintf(stderr,"FIonNL\n"); | 
|---|
| 427 | Free(I->I[i].FIonNL); | 
|---|
| 428 | //fprintf(stderr,"U\n"); | 
|---|
| 429 | Free(I->I[i].U); | 
|---|
| 430 | //fprintf(stderr,"SFactor\n"); | 
|---|
| 431 | Free(I->I[i].SFactor); | 
|---|
| 432 | //fprintf(stderr,"IMT\n"); | 
|---|
| 433 | Free(I->I[i].IMT); | 
|---|
| 434 | //fprintf(stderr,"FEwald\n"); | 
|---|
| 435 | Free(I->I[i].FEwald); | 
|---|
| 436 | Free(I->I[i].alpha); | 
|---|
| 437 | } | 
|---|
| 438 | //fprintf(stderr,"RLatticeVec\n"); | 
|---|
| 439 | if (I->R_cut == 0.0) | 
|---|
| 440 | Free(I->RLatticeVec); | 
|---|
| 441 | //fprintf(stderr,"FTemp\n"); | 
|---|
| 442 | Free(I->FTemp); | 
|---|
| 443 | //fprintf(stderr,"I\n"); | 
|---|
| 444 | Free(I->I); | 
|---|
| 445 | } | 
|---|
| 446 |  | 
|---|
| 447 | /** Shifts center of gravity of ion forces IonType::FIon. | 
|---|
| 448 | * First sums up all forces of movable ions to a "force temperature", | 
|---|
| 449 | * then reduces each force by this temp, so that all in all | 
|---|
| 450 | * the net force is 0. | 
|---|
| 451 | * \param *P Problem at hand | 
|---|
| 452 | * \sa CorrectVelocity | 
|---|
| 453 | * \note why is FTemp not divided by number of ions: is probably correct, but this | 
|---|
| 454 | *       function was not really meaningful from the beginning. | 
|---|
| 455 | */ | 
|---|
| 456 | void CorrectForces(struct Problem *P) | 
|---|
| 457 | { | 
|---|
| 458 | struct Ions *I = &P->Ion; | 
|---|
| 459 | double *FIon; | 
|---|
| 460 | double FTemp[NDIM]; | 
|---|
| 461 | int is, ia, d; | 
|---|
| 462 | for (d=0; d<NDIM; d++) | 
|---|
| 463 | FTemp[d] = 0; | 
|---|
| 464 | for (is=0; is < I->Max_Types; is++) {         // calculate force temperature for each type ... | 
|---|
| 465 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) {    // .. and each ion of this type ... | 
|---|
| 466 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 467 | if (I->I[is].IMT[ia] == MoveIon) {                // .. if it's movable | 
|---|
| 468 | for (d=0; d<NDIM; d++) | 
|---|
| 469 | FTemp[d] += FIon[d]; | 
|---|
| 470 | } | 
|---|
| 471 | } | 
|---|
| 472 | } | 
|---|
| 473 | for (is=0; is < I->Max_Types; is++) {         // and then reduce each by this value | 
|---|
| 474 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 475 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 476 | if (I->I[is].IMT[ia] == MoveIon) { | 
|---|
| 477 | for (d=0; d<NDIM; d++) | 
|---|
| 478 | FIon[d] -= FTemp[d];                                           // (?) why not -= FTemp[d]/I->Max_TotalIons | 
|---|
| 479 | } | 
|---|
| 480 | } | 
|---|
| 481 | } | 
|---|
| 482 | } | 
|---|
| 483 |  | 
|---|
| 484 |  | 
|---|
| 485 | /** Shifts center of gravity of ion velocities (rather momentums). | 
|---|
| 486 | * First sums up ion speed U times their IonMass (summed up for each | 
|---|
| 487 | * dimension), then reduces the velocity by temp per Ions::TotalMass (so here | 
|---|
| 488 | * total number of Ions is included) | 
|---|
| 489 | * \param *P Problem at hand | 
|---|
| 490 | * \sa CorrectForces | 
|---|
| 491 | */ | 
|---|
| 492 | void CorrectVelocity(struct Problem *P) | 
|---|
| 493 | { | 
|---|
| 494 | struct Ions *I = &P->Ion; | 
|---|
| 495 | double *U; | 
|---|
| 496 | double UTemp[NDIM]; | 
|---|
| 497 | int is, ia, d; | 
|---|
| 498 | for (d=0; d<NDIM; d++) | 
|---|
| 499 | UTemp[d] = 0; | 
|---|
| 500 | for (is=0; is < I->Max_Types; is++) {         // all types ... | 
|---|
| 501 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) {    // ... all ions per type ... | 
|---|
| 502 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 503 | if (I->I[is].IMT[ia] == MoveIon) {        // ... if it's movable | 
|---|
| 504 | for (d=0; d<NDIM; d++) | 
|---|
| 505 | UTemp[d] += I->I[is].IonMass*U[d]; | 
|---|
| 506 | } | 
|---|
| 507 | } | 
|---|
| 508 | } | 
|---|
| 509 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 510 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 511 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 512 | if (I->I[is].IMT[ia] == MoveIon) { | 
|---|
| 513 | for (d=0; d<NDIM; d++) | 
|---|
| 514 | U[d] -= UTemp[d]/I->TotalMass;                // shift by mean velocity over mass and number of ions | 
|---|
| 515 | } | 
|---|
| 516 | } | 
|---|
| 517 | } | 
|---|
| 518 | } | 
|---|
| 519 |  | 
|---|
| 520 | /** Moves ions according to calculated force. | 
|---|
| 521 | * Goes through each type of IonType and each ion therein, takes mass and | 
|---|
| 522 | * Newton to move each ion to new coordinates IonType::R, while remembering the last | 
|---|
| 523 | * two coordinates and the last force of the ion. Coordinates R are being | 
|---|
| 524 | * transformed to inverted base, shifted by +-1.0 and back-transformed to | 
|---|
| 525 | * real base. | 
|---|
| 526 | * \param *P Problem at hand | 
|---|
| 527 | * \sa CalculateIonForce | 
|---|
| 528 | * \sa UpdateIonsU | 
|---|
| 529 | * \warning U is not changed here, only used to move the ion. | 
|---|
| 530 | */ | 
|---|
| 531 | void UpdateIonsR(struct Problem *P) | 
|---|
| 532 | { | 
|---|
| 533 | struct Ions *I = &P->Ion; | 
|---|
| 534 | int is, ia, d; | 
|---|
| 535 | double *R, *R_old, *R_old_old, *FIon, *FIon_old, *U, *FIonL, *FIonNL, *FEwald; | 
|---|
| 536 | double IonMass, a; | 
|---|
| 537 | double sR[NDIM], sRold[NDIM], sRoldold[NDIM]; | 
|---|
| 538 | const int delta_t = P->R.delta_t; | 
|---|
| 539 | for (is=0; is < I->Max_Types; is++) { // go through all types ... | 
|---|
| 540 | IonMass = I->I[is].IonMass; | 
|---|
| 541 | if (IonMass < MYEPSILON) fprintf(stderr,"UpdateIonsR: IonMass = %lg",IonMass); | 
|---|
| 542 | a = delta_t*0.5/IonMass;            // F/m = a and thus: s = 0.5 * F/m * t^2 + v * t =: t * (F * a + v) | 
|---|
| 543 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { // .. and each ion of the type | 
|---|
| 544 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 545 | FIonL = &I->I[is].FIonL[NDIM*ia]; | 
|---|
| 546 | FIonNL = &I->I[is].FIonNL[NDIM*ia]; | 
|---|
| 547 | FEwald = &I->I[is].FEwald[NDIM*ia]; | 
|---|
| 548 | FIon_old = &I->I[is].FIon_old[NDIM*ia]; | 
|---|
| 549 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 550 | R = &I->I[is].R[NDIM*ia]; | 
|---|
| 551 | R_old = &I->I[is].R_old[NDIM*ia]; | 
|---|
| 552 | R_old_old = &I->I[is].R_old_old[NDIM*ia]; | 
|---|
| 553 | if (I->I[is].IMT[ia] == MoveIon) { | 
|---|
| 554 | for (d=0; d<NDIM; d++) { | 
|---|
| 555 | R_old_old[d] = R_old[d];                              // shift old values | 
|---|
| 556 | R_old[d] = R[d]; | 
|---|
| 557 | R[d] += delta_t*(U[d]+a*FIon[d]);                     // F = m * a and s = 0.5 * a * t^2 | 
|---|
| 558 | FIon_old[d] = FIon[d];                                        // store old force | 
|---|
| 559 | FIon[d] = 0;                                                                          // zero all as a sign that's been moved | 
|---|
| 560 | FIonL[d] = 0; | 
|---|
| 561 | FIonNL[d] = 0; | 
|---|
| 562 | FEwald[d] = 0; | 
|---|
| 563 | } | 
|---|
| 564 | RMat33Vec3(sR, P->Lat.InvBasis, R); | 
|---|
| 565 | RMat33Vec3(sRold, P->Lat.InvBasis, R_old); | 
|---|
| 566 | RMat33Vec3(sRoldold, P->Lat.InvBasis, R_old_old); | 
|---|
| 567 | for (d=0; d <NDIM; d++) { | 
|---|
| 568 | while (sR[d] < 0) { | 
|---|
| 569 | sR[d] += 1.0; | 
|---|
| 570 | sRold[d] += 1.0; | 
|---|
| 571 | sRoldold[d] += 1.0; | 
|---|
| 572 | } | 
|---|
| 573 | while (sR[d] >= 1.0) { | 
|---|
| 574 | sR[d] -= 1.0; | 
|---|
| 575 | sRold[d] -= 1.0; | 
|---|
| 576 | sRoldold[d] -= 1.0; | 
|---|
| 577 | } | 
|---|
| 578 | } | 
|---|
| 579 | RMat33Vec3(R, P->Lat.RealBasis, sR); | 
|---|
| 580 | RMat33Vec3(R_old, P->Lat.RealBasis, sRold); | 
|---|
| 581 | RMat33Vec3(R_old_old, P->Lat.RealBasis, sRoldold); | 
|---|
| 582 | } | 
|---|
| 583 | } | 
|---|
| 584 | } | 
|---|
| 585 | } | 
|---|
| 586 |  | 
|---|
| 587 | /** Resets the forces array. | 
|---|
| 588 | * \param *P Problem at hand | 
|---|
| 589 | */ | 
|---|
| 590 | void ResetForces(struct Problem *P) | 
|---|
| 591 | { | 
|---|
| 592 | struct Ions *I = &P->Ion; | 
|---|
| 593 | double *FIon, *FIonL, *FIonNL, *FEwald; | 
|---|
| 594 | int is, ia, d; | 
|---|
| 595 | for (is=0; is < I->Max_Types; is++) { // go through all types ... | 
|---|
| 596 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { // .. and each ion of the type | 
|---|
| 597 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 598 | FIonL = &I->I[is].FIonL[NDIM*ia]; | 
|---|
| 599 | FIonNL = &I->I[is].FIonNL[NDIM*ia]; | 
|---|
| 600 | FEwald = &I->I[is].FEwald[NDIM*ia]; | 
|---|
| 601 | for (d=0; d<NDIM; d++) { | 
|---|
| 602 | FIon[d] = 0.;                   // zero all as a sign that's been moved | 
|---|
| 603 | FIonL[d] = 0.; | 
|---|
| 604 | FIonNL[d] = 0.; | 
|---|
| 605 | FEwald[d] = 0.; | 
|---|
| 606 | } | 
|---|
| 607 | } | 
|---|
| 608 | } | 
|---|
| 609 | }; | 
|---|
| 610 |  | 
|---|
| 611 | /** Changes ion's velocity according to acting force. | 
|---|
| 612 | * IonType::U is changed by the weighted force of actual step and last one | 
|---|
| 613 | * according to Newton. | 
|---|
| 614 | * \param *P Problem at hand | 
|---|
| 615 | * \sa UpdateIonsR | 
|---|
| 616 | * \sa CalculateIonForce | 
|---|
| 617 | * \warning R is not changed here. | 
|---|
| 618 | */ | 
|---|
| 619 | void UpdateIonsU(struct Problem *P) | 
|---|
| 620 | { | 
|---|
| 621 | struct Ions *I = &P->Ion; | 
|---|
| 622 | int is, ia, d; | 
|---|
| 623 | double *FIon, *FIon_old, *U; | 
|---|
| 624 | double IonMass, a; | 
|---|
| 625 | const int delta_t = P->R.delta_t; | 
|---|
| 626 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 627 | IonMass = I->I[is].IonMass; | 
|---|
| 628 | if (IonMass < MYEPSILON) fprintf(stderr,"UpdateIonsU: IonMass = %lg",IonMass); | 
|---|
| 629 | a = delta_t*0.5/IonMass;                            // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a | 
|---|
| 630 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 631 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 632 | FIon_old = &I->I[is].FIon_old[NDIM*ia]; | 
|---|
| 633 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 634 | if (I->I[is].IMT[ia] == MoveIon) | 
|---|
| 635 | for (d=0; d<NDIM; d++) { | 
|---|
| 636 | U[d] += a * (FIon[d]+FIon_old[d]); | 
|---|
| 637 | } | 
|---|
| 638 | } | 
|---|
| 639 | } | 
|---|
| 640 | } | 
|---|
| 641 |  | 
|---|
| 642 | /** CG process to optimise structure. | 
|---|
| 643 | * \param *P Problem at hand | 
|---|
| 644 | */ | 
|---|
| 645 | void UpdateIons(struct Problem *P) | 
|---|
| 646 | { | 
|---|
| 647 | struct Ions *I = &P->Ion; | 
|---|
| 648 | int is, ia, d; | 
|---|
| 649 | double *R, *R_old, *R_old_old, *FIon, *S, *GammaA; | 
|---|
| 650 | double IonFac, GammaB; //, GammaT; | 
|---|
| 651 | double FNorm, StepNorm; | 
|---|
| 652 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 653 | IonFac = I->I[is].IonFac; | 
|---|
| 654 | GammaA = I->I[is].GammaA; | 
|---|
| 655 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 656 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 657 | S = &I->I[is].SearchDir[NDIM*ia]; | 
|---|
| 658 | GammaB = GammaA[ia]; | 
|---|
| 659 | GammaA[ia] = RSP3(FIon,S); | 
|---|
| 660 | FNorm = sqrt(RSP3(FIon,FIon)); | 
|---|
| 661 | StepNorm = log(1.+IonFac*FNorm); // Fix Hack | 
|---|
| 662 | if (FNorm != 0) | 
|---|
| 663 | StepNorm /= sqrt(RSP3(FIon,FIon)); | 
|---|
| 664 | else | 
|---|
| 665 | StepNorm = 0; | 
|---|
| 666 | //if (GammaB != 0.0) { | 
|---|
| 667 | //        GammaT = GammaA[ia]/GammaB; | 
|---|
| 668 | //        for (d=0; d>NDIM; d++) | 
|---|
| 669 | //          S[d] = FIon[d]+GammaT*S[d]; | 
|---|
| 670 | //      } else { | 
|---|
| 671 | for (d=0; d<NDIM; d++) | 
|---|
| 672 | S[d] = StepNorm*FIon[d]; | 
|---|
| 673 | //      } | 
|---|
| 674 | R = &I->I[is].R[NDIM*ia]; | 
|---|
| 675 | R_old = &I->I[is].R_old[NDIM*ia]; | 
|---|
| 676 | R_old_old = &I->I[is].R_old_old[NDIM*ia]; | 
|---|
| 677 | if (I->I[is].IMT[ia] == MoveIon) | 
|---|
| 678 | for (d=0; d<NDIM; d++) { | 
|---|
| 679 | R_old_old[d] = R_old[d]; | 
|---|
| 680 | R_old[d] = R[d]; | 
|---|
| 681 | R[d] += S[d]; // FixHack*IonFac; | 
|---|
| 682 | } | 
|---|
| 683 | } | 
|---|
| 684 | } | 
|---|
| 685 | } | 
|---|
| 686 |  | 
|---|
| 687 | /** Print coordinates of all ions to stdout. | 
|---|
| 688 | * \param *P Problem at hand | 
|---|
| 689 | */ | 
|---|
| 690 | void OutputIonCoordinates(struct Problem *P) | 
|---|
| 691 | { | 
|---|
| 692 | struct Ions *I = &P->Ion; | 
|---|
| 693 | int is, ia; | 
|---|
| 694 | if (P->Par.me == 0) { | 
|---|
| 695 | fprintf(stderr, "(%i) ======= Updated Ion Coordinates =========\n",P->Par.me); | 
|---|
| 696 | for (is=0; is < I->Max_Types; is++) | 
|---|
| 697 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) | 
|---|
| 698 | //fprintf(stderr, "(%i) R[%i/%i][%i/%i] = (%e,%e,%e)\n", P->Par.me, is, I->Max_Types, ia, I->I[is].Max_IonsOfType, I->I[is].R[NDIM*ia+0],I->I[is].R[NDIM*ia+1],I->I[is].R[NDIM*ia+2]); | 
|---|
| 699 | fprintf(stderr, "Ion_Type%i_%i\t%.6f\t%.6f\t%.6f\t0\t# Atom from StructOpt\n", is+1, ia+1, I->I[is].R[NDIM*ia+0],I->I[is].R[NDIM*ia+1],I->I[is].R[NDIM*ia+2]); | 
|---|
| 700 | fprintf(stderr, "(%i) =========================================\n",P->Par.me); | 
|---|
| 701 | } | 
|---|
| 702 | } | 
|---|
| 703 |  | 
|---|
| 704 | /** Calculates kinetic energy (Ions::EKin) of movable Ions. | 
|---|
| 705 | * Does 0.5 / IonType::IonMass * IonTye::U^2 for each Ion, | 
|---|
| 706 | * also retrieves actual temperatur by 2/3 from just | 
|---|
| 707 | * calculated Ions::EKin. | 
|---|
| 708 | * \param *P Problem at hand | 
|---|
| 709 | */ | 
|---|
| 710 | void CalculateEnergyIonsU(struct Problem *P) | 
|---|
| 711 | { | 
|---|
| 712 | struct Ions *I = &P->Ion; | 
|---|
| 713 | int is, ia, d; | 
|---|
| 714 | double *U; | 
|---|
| 715 | double IonMass, a, ekin = 0; | 
|---|
| 716 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 717 | IonMass = I->I[is].IonMass; | 
|---|
| 718 | a = 0.5*IonMass; | 
|---|
| 719 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 720 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 721 | if (I->I[is].IMT[ia] == MoveIon) | 
|---|
| 722 | for (d=0; d<NDIM; d++) { | 
|---|
| 723 | ekin += a * U[d]*U[d]; | 
|---|
| 724 | } | 
|---|
| 725 | } | 
|---|
| 726 | } | 
|---|
| 727 | I->EKin = ekin; | 
|---|
| 728 | I->ActualTemp = (2./(3.*I->Max_TotalIons)*I->EKin); | 
|---|
| 729 | } | 
|---|
| 730 |  | 
|---|
| 731 | /**     Scales ion velocities to match temperature. | 
|---|
| 732 | * In order to match Ions::ActualTemp with desired RunStruct::TargetTemp | 
|---|
| 733 | * each velocity in each dimension (for all types, all ions) is scaled | 
|---|
| 734 | * with the ratio of these two. Ions::EKin is recalculated. | 
|---|
| 735 | * \param *P Problem at hand | 
|---|
| 736 | */ | 
|---|
| 737 | void ScaleTemp(struct Problem *P) | 
|---|
| 738 | { | 
|---|
| 739 | struct Ions *I = &P->Ion; | 
|---|
| 740 | int is, ia, d; | 
|---|
| 741 | double *U; | 
|---|
| 742 | double IonMass, a, ekin = 0; | 
|---|
| 743 | if (I->ActualTemp < MYEPSILON) fprintf(stderr,"ScaleTemp: I->ActualTemp = %lg",I->ActualTemp); | 
|---|
| 744 | double ScaleTempFactor = sqrt(P->R.TargetTemp/I->ActualTemp); | 
|---|
| 745 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 746 | IonMass = I->I[is].IonMass; | 
|---|
| 747 | a = 0.5*IonMass; | 
|---|
| 748 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 749 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 750 | if (I->I[is].IMT[ia] == MoveIon) | 
|---|
| 751 | for (d=0; d<NDIM; d++) { | 
|---|
| 752 | U[d] *= ScaleTempFactor; | 
|---|
| 753 | ekin += a * U[d]*U[d]; | 
|---|
| 754 | } | 
|---|
| 755 | } | 
|---|
| 756 | } | 
|---|
| 757 | I->EKin = ekin; | 
|---|
| 758 | I->ActualTemp = (2./(3.*I->Max_TotalIons)*I->EKin); | 
|---|
| 759 | } | 
|---|
| 760 |  | 
|---|
| 761 | /** Calculates mean force vector as stop criteria in structure optimization. | 
|---|
| 762 | * Calculates a mean force vector per ion as the usual euclidian norm over total | 
|---|
| 763 | * number of ions and dimensions, being the sum of each ion force (for all type, | 
|---|
| 764 | * all ions, all dims) squared. | 
|---|
| 765 | * The mean force is archived in RunStruct::MeanForce and printed to screen. | 
|---|
| 766 | * \param *P Problem at hand | 
|---|
| 767 | */ | 
|---|
| 768 | void GetOuterStop(struct Problem *P) | 
|---|
| 769 | { | 
|---|
| 770 | struct RunStruct *R = &P->R; | 
|---|
| 771 | struct Ions *I = &P->Ion; | 
|---|
| 772 | int is, ia, IonNo=0, i, d; | 
|---|
| 773 | double MeanForce = 0.0; | 
|---|
| 774 | for (is=0; is < I->Max_Types; is++) | 
|---|
| 775 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 776 | IonNo++; | 
|---|
| 777 | for (d=0; d <NDIM; d++) | 
|---|
| 778 | MeanForce += I->I[is].FIon[d+NDIM*ia]*I->I[is].FIon[d+NDIM*ia]; | 
|---|
| 779 | } | 
|---|
| 780 | for (i=MAXOLD-1; i > 0; i--) | 
|---|
| 781 | R->MeanForce[i] = R->MeanForce[i-1]; | 
|---|
| 782 | MeanForce = sqrt(MeanForce/(IonNo*NDIM)); | 
|---|
| 783 | R->MeanForce[0] = MeanForce; | 
|---|
| 784 | if (P->Call.out[LeaderOut] && (P->Par.me == 0)) | 
|---|
| 785 | fprintf(stderr,"MeanForce = %e\n", R->MeanForce[0]); | 
|---|
| 786 | } | 
|---|
| 787 |  | 
|---|
| 788 |  | 
|---|