| 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 <gsl/gsl_randist.h> | 
|---|
| 32 | #include "mymath.h" | 
|---|
| 33 |  | 
|---|
| 34 |  | 
|---|
| 35 | // use double precision fft when we have it | 
|---|
| 36 | #ifdef HAVE_CONFIG_H | 
|---|
| 37 | #include <config.h> | 
|---|
| 38 | #endif | 
|---|
| 39 |  | 
|---|
| 40 | #ifdef HAVE_DFFTW_H | 
|---|
| 41 | #include "dfftw.h" | 
|---|
| 42 | #else | 
|---|
| 43 | #include "fftw.h" | 
|---|
| 44 | #endif | 
|---|
| 45 |  | 
|---|
| 46 | #include "data.h" | 
|---|
| 47 | #include "errors.h" | 
|---|
| 48 | #include "helpers.h" | 
|---|
| 49 | #include "mymath.h" | 
|---|
| 50 | #include "ions.h" | 
|---|
| 51 | #include "init.h" | 
|---|
| 52 |  | 
|---|
| 53 | /** Readin of Thermostat related values from parameter file. | 
|---|
| 54 | * \param *P Problem at hand | 
|---|
| 55 | * \param *source parameter file | 
|---|
| 56 | */ | 
|---|
| 57 | void InitThermostats(struct Problem *P, FILE *source) | 
|---|
| 58 | { | 
|---|
| 59 | struct FileData *F = &P->Files; | 
|---|
| 60 | struct Ions *I = &P->Ion; | 
|---|
| 61 | char *thermo = MallocString(12, "IonsInitRead: thermo"); | 
|---|
| 62 | int j; | 
|---|
| 63 |  | 
|---|
| 64 | // initialize the naming stuff and all | 
|---|
| 65 | I->ThermostatImplemented = (int *) Malloc((MaxThermostats)*(sizeof(int)), "IonsInitRead: *ThermostatImplemented"); | 
|---|
| 66 | I->ThermostatNames = (char **) Malloc((MaxThermostats)*(sizeof(char *)), "IonsInitRead: *ThermostatNames"); | 
|---|
| 67 | for (j=0;j<MaxThermostats;j++) | 
|---|
| 68 | I->ThermostatNames[j] = (char *) MallocString(12*(sizeof(char)), "IonsInitRead: ThermostatNames[]"); | 
|---|
| 69 | strcpy(I->ThermostatNames[0],"None"); | 
|---|
| 70 | I->ThermostatImplemented[0] = 1; | 
|---|
| 71 | strcpy(I->ThermostatNames[1],"Woodcock"); | 
|---|
| 72 | I->ThermostatImplemented[1] = 1; | 
|---|
| 73 | strcpy(I->ThermostatNames[2],"Gaussian"); | 
|---|
| 74 | I->ThermostatImplemented[2] = 1; | 
|---|
| 75 | strcpy(I->ThermostatNames[3],"Langevin"); | 
|---|
| 76 | I->ThermostatImplemented[3] = 1; | 
|---|
| 77 | strcpy(I->ThermostatNames[4],"Berendsen"); | 
|---|
| 78 | I->ThermostatImplemented[4] = 1; | 
|---|
| 79 | strcpy(I->ThermostatNames[5],"NoseHoover"); | 
|---|
| 80 | I->ThermostatImplemented[5] = 1; | 
|---|
| 81 | I->Thermostat = -1; | 
|---|
| 82 | if (F->MeOutMes) fprintf(F->TemperatureFile, "# %s\t%s\t%s --- ","Step", "ActualTemp(1)", "ActualTemp(2)"); | 
|---|
| 83 |  | 
|---|
| 84 | // read desired Thermostat from file along with needed additional parameters | 
|---|
| 85 | if (ParseForParameter(P->Call.out[ReadOut],source,"Thermostat", 0, 1, 1, string_type, thermo, 1, optional)) { | 
|---|
| 86 | if (strcmp(thermo, I->ThermostatNames[0]) == 0) { // None | 
|---|
| 87 | if (I->ThermostatImplemented[0] == 1) { | 
|---|
| 88 | I->Thermostat = None; | 
|---|
| 89 | } else { | 
|---|
| 90 | if (P->Par.me == 0) | 
|---|
| 91 | fprintf(stderr, "(%i) Warning: %s thermostat not implemented, falling back to None.", P->Par.me, I->ThermostatNames[0]); | 
|---|
| 92 | I->Thermostat = None; | 
|---|
| 93 | } | 
|---|
| 94 | } else if (strcmp(thermo, I->ThermostatNames[1]) == 0) { // Woodcock | 
|---|
| 95 | if (I->ThermostatImplemented[1] == 1) { | 
|---|
| 96 | I->Thermostat = Woodcock; | 
|---|
| 97 | ParseForParameter(P->Call.out[ReadOut],source,"Thermostat", 0, 2, 1, int_type, &P->R.ScaleTempStep, 1, critical); // read scaling frequency | 
|---|
| 98 | } else { | 
|---|
| 99 | if (P->Par.me == 0) | 
|---|
| 100 | fprintf(stderr, "(%i) Warning: %s thermostat not implemented, falling back to None.", P->Par.me, I->ThermostatNames[1]); | 
|---|
| 101 | I->Thermostat = None; | 
|---|
| 102 | } | 
|---|
| 103 | } else if (strcmp(thermo, I->ThermostatNames[2]) == 0) { // Gaussian | 
|---|
| 104 | if (I->ThermostatImplemented[2] == 1) { | 
|---|
| 105 | I->Thermostat = Gaussian; | 
|---|
| 106 | ParseForParameter(P->Call.out[ReadOut],source,"Thermostat", 0, 2, 1, int_type, &P->R.ScaleTempStep, 1, critical); // read collision rate | 
|---|
| 107 | } else { | 
|---|
| 108 | if (P->Par.me == 0) | 
|---|
| 109 | fprintf(stderr, "(%i) Warning: %s thermostat not implemented, falling back to None.", P->Par.me, I->ThermostatNames[2]); | 
|---|
| 110 | I->Thermostat = None; | 
|---|
| 111 | } | 
|---|
| 112 | } else if (strcmp(thermo, I->ThermostatNames[3]) == 0) { // Langevin | 
|---|
| 113 | if (I->ThermostatImplemented[3] == 1) { | 
|---|
| 114 | I->Thermostat = Langevin; | 
|---|
| 115 | ParseForParameter(P->Call.out[ReadOut],source,"Thermostat", 0, 2, 1, double_type, &P->R.TempFrequency, 1, critical); // read gamma | 
|---|
| 116 | if (ParseForParameter(P->Call.out[ReadOut],source,"Thermostat", 0, 3, 1, double_type, &P->R.alpha, 1, optional)) { | 
|---|
| 117 | if (P->Par.me == 0) | 
|---|
| 118 | fprintf(stderr,"(%i) Extended Stochastic Thermostat detected with interpolation coefficient %lg\n", P->Par.me, P->R.alpha); | 
|---|
| 119 | } else { | 
|---|
| 120 | P->R.alpha = 1.; | 
|---|
| 121 | } | 
|---|
| 122 | } else { | 
|---|
| 123 | if (P->Par.me == 0) | 
|---|
| 124 | fprintf(stderr, "(%i) Warning: %s thermostat not implemented, falling back to None.", P->Par.me, I->ThermostatNames[3]); | 
|---|
| 125 | I->Thermostat = None; | 
|---|
| 126 | } | 
|---|
| 127 | } else if (strcmp(thermo, I->ThermostatNames[4]) == 0) { // Berendsen | 
|---|
| 128 | if (I->ThermostatImplemented[4] == 1) { | 
|---|
| 129 | I->Thermostat = Berendsen; | 
|---|
| 130 | ParseForParameter(P->Call.out[ReadOut],source,"Thermostat", 0, 2, 1, double_type, &P->R.TempFrequency, 1, critical); // read \tau_T | 
|---|
| 131 | } else { | 
|---|
| 132 | if (P->Par.me == 0) | 
|---|
| 133 | fprintf(stderr, "(%i) Warning: %s thermostat not implemented, falling back to None.", P->Par.me, I->ThermostatNames[4]); | 
|---|
| 134 | I->Thermostat = None; | 
|---|
| 135 | } | 
|---|
| 136 | } else if (strcmp(thermo, I->ThermostatNames[5]) == 0) { // Nose-Hoover | 
|---|
| 137 | if (I->ThermostatImplemented[5] == 1) { | 
|---|
| 138 | I->Thermostat = NoseHoover; | 
|---|
| 139 | ParseForParameter(P->Call.out[ReadOut],source,"Thermostat", 0, 2, 1, double_type, &P->R.HooverMass, 1, critical); // read Hoovermass | 
|---|
| 140 | P->R.alpha = 0.; | 
|---|
| 141 | } else { | 
|---|
| 142 | if (P->Par.me == 0) | 
|---|
| 143 | fprintf(stderr, "(%i) Warning: %s thermostat not implemented, falling back to None.", P->Par.me, I->ThermostatNames[5]); | 
|---|
| 144 | I->Thermostat = None; | 
|---|
| 145 | } | 
|---|
| 146 | } | 
|---|
| 147 | if (I->Thermostat == -1) { | 
|---|
| 148 | if (P->Par.me == 0) | 
|---|
| 149 | fprintf(stderr,"(%i) Warning: thermostat name was not understood!\n", P->Par.me); | 
|---|
| 150 | I->Thermostat = None; | 
|---|
| 151 | } | 
|---|
| 152 | } else { | 
|---|
| 153 | if ((P->R.MaxOuterStep > 0) && (P->R.TargetTemp != 0)) | 
|---|
| 154 | debug(P, "No thermostat chosen despite finite temperature MD, falling back to None."); | 
|---|
| 155 | I->Thermostat = None; | 
|---|
| 156 | } | 
|---|
| 157 | if (F->MeOutMes) fprintf(F->TemperatureFile, "%s Thermostat\n",I->ThermostatNames[(int)I->Thermostat]); | 
|---|
| 158 | Free(thermo, "InitThermostats: thermo"); | 
|---|
| 159 | } | 
|---|
| 160 |  | 
|---|
| 161 | /** Parses for a given keyword the ion coordinates and velocites. | 
|---|
| 162 | * \param *P Problem at hand, contains pointer to Ion and IonType structure | 
|---|
| 163 | * \param *source | 
|---|
| 164 | * \param *keyword keyword string | 
|---|
| 165 | * \param repetition which repeated version of the keyword shall be read by ReadParameters() | 
|---|
| 166 | * \param relative whether atom coordinates are relative to unit cell size or absolute | 
|---|
| 167 | * \param Bohr conversion factor to atomiclength (e.g. 1.0 if coordinates in bohr radius, 0.529... if given in Angstrom) | 
|---|
| 168 | * \param sigma variance of maxwell-boltzmann distribution | 
|---|
| 169 | * \param *R where to put the read coordinates | 
|---|
| 170 | * \param *U where to put the read velocities | 
|---|
| 171 | * \param *IMT whether its MoveType#FixedIon or not | 
|---|
| 172 | * \return if 1 - success, 0 - failure | 
|---|
| 173 | */ | 
|---|
| 174 | int ParseIonsCoordinatesAndVelocities(struct Problem *P, FILE *source, char *keyword, int repetition, int relative, double sigma, double *R, double *U, int *IMT) | 
|---|
| 175 | { | 
|---|
| 176 | //struct RunStruct *Run = &P->R; | 
|---|
| 177 | struct Ions *I = &P->Ion; | 
|---|
| 178 | struct Lattice *L = &P->Lat; | 
|---|
| 179 | int k; | 
|---|
| 180 | double R_trafo[3]; | 
|---|
| 181 | gsl_rng * r; | 
|---|
| 182 | const gsl_rng_type * T; | 
|---|
| 183 | double Bohr = (I->IsAngstroem) ? ANGSTROEMINBOHRRADIUS : 1.; | 
|---|
| 184 |  | 
|---|
| 185 | gsl_rng_env_setup(); | 
|---|
| 186 | T = gsl_rng_default; | 
|---|
| 187 | r = gsl_rng_alloc (T); | 
|---|
| 188 | if (ParseForParameter(P->Call.out[ReadOut],source, keyword, 0, 1, 1, double_type, &R_trafo[0], repetition, optional) && | 
|---|
| 189 | ParseForParameter(P->Call.out[ReadOut],source, keyword, 0, 2, 1, double_type, &R_trafo[1], repetition, optional) && | 
|---|
| 190 | ParseForParameter(P->Call.out[ReadOut],source, keyword, 0, 3, 1, double_type, &R_trafo[2], repetition, optional) && | 
|---|
| 191 | ParseForParameter(P->Call.out[ReadOut],source, keyword, 0, 4, 1, int_type, IMT, repetition, optional)) { | 
|---|
| 192 | // if read successful, then try also parsing velocities | 
|---|
| 193 | if ((ParseForParameter(P->Call.out[ReadOut],source, keyword, 0, 5, 1, double_type, &U[0], repetition, optional)) && | 
|---|
| 194 | (ParseForParameter(P->Call.out[ReadOut],source, keyword, 0, 6, 1, double_type, &U[1], repetition, optional)) && | 
|---|
| 195 | (ParseForParameter(P->Call.out[ReadOut],source, keyword, 0, 7, 1, double_type, &U[2], repetition, optional))) { | 
|---|
| 196 | //nothing | 
|---|
| 197 | } else {  // if no velocities specified, set to maxwell-boltzmann distributed | 
|---|
| 198 | if ((I->Thermostat != None)) { | 
|---|
| 199 | if (P->Par.me == 0) fprintf(stderr, "(%i) Missing velocities of ion %s: Maxwell-Boltzmann with %lg\n", P->Par.me, keyword, sigma); | 
|---|
| 200 | for (k=0;k<NDIM;k++) | 
|---|
| 201 | U[k] = gsl_ran_gaussian (r, sigma); | 
|---|
| 202 | } else { | 
|---|
| 203 | for (k=0;k<NDIM;k++) | 
|---|
| 204 | U[k] = 0.; | 
|---|
| 205 | } | 
|---|
| 206 | } | 
|---|
| 207 | // change if coordinates were relative | 
|---|
| 208 | if (relative) { | 
|---|
| 209 | //fprintf(stderr,"(%i)Ion coordinates are relative %i ... \n",P->Par.me, relative); | 
|---|
| 210 | RMat33Vec3(R, L->RealBasis, R_trafo); // multiply with real basis | 
|---|
| 211 | } else { | 
|---|
| 212 | for (k=0;k<NDIM;k++) // otherweise just copy to vector | 
|---|
| 213 | R[k] = R_trafo[k]; | 
|---|
| 214 | } | 
|---|
| 215 | // check if given MoveType is valid | 
|---|
| 216 | if (*IMT < 0 || *IMT >= MaxIonMoveType) { | 
|---|
| 217 | fprintf(stderr,"Bad Ion MoveType set to MoveIon for %s\n", keyword); | 
|---|
| 218 | *IMT = 0; | 
|---|
| 219 | } | 
|---|
| 220 | if (!relative) { | 
|---|
| 221 | //fprintf(stderr,"converting with %lg\n", Bohr); | 
|---|
| 222 | SM(R, Bohr, NDIM); // convert angstroem to bohrradius | 
|---|
| 223 | SM(U, Bohr, NDIM); // convert angstroem to bohrradius | 
|---|
| 224 | } | 
|---|
| 225 | // finally periodicly correct coordinates to remain in unit cell | 
|---|
| 226 | RMat33Vec3(R_trafo, L->InvBasis, R); | 
|---|
| 227 | for (k=0; k <NDIM; k++) { // periodic correction until within unit cell | 
|---|
| 228 | while (R_trafo[k] < 0) | 
|---|
| 229 | R_trafo[k] += 1.0; | 
|---|
| 230 | while (R_trafo[k] >= 1.0) | 
|---|
| 231 | R_trafo[k] -= 1.0; | 
|---|
| 232 | } | 
|---|
| 233 | RMat33Vec3(R, L->RealBasis, R_trafo); | 
|---|
| 234 | // print coordinates if desired | 
|---|
| 235 | if ((P->Call.out[ReadOut])) { | 
|---|
| 236 | fprintf(stderr,"(%i) coordinates of Ion %s: (x,y,z) = (",P->Par.me, keyword); | 
|---|
| 237 | for(k=0;k<NDIM;k++) { | 
|---|
| 238 | fprintf(stderr,"%lg ",R[k]); | 
|---|
| 239 | if (k != NDIM-1) fprintf(stderr,", "); | 
|---|
| 240 | else fprintf(stderr,")\n"); | 
|---|
| 241 | } | 
|---|
| 242 | } | 
|---|
| 243 | gsl_rng_free (r); | 
|---|
| 244 | return 1; | 
|---|
| 245 | } else { | 
|---|
| 246 | for (k=0;k<NDIM;k++) { | 
|---|
| 247 | U[k] = R[k] = 0.; | 
|---|
| 248 | } | 
|---|
| 249 | *IMT = 0; | 
|---|
| 250 | gsl_rng_free (r); | 
|---|
| 251 | return 0; | 
|---|
| 252 | } | 
|---|
| 253 | } | 
|---|
| 254 |  | 
|---|
| 255 | /** Readin of the ion section of parameter file. | 
|---|
| 256 | * Among others the following paramaters are read from file: | 
|---|
| 257 | * Ions::MaxTypes, IonType::Max_IonsOfType, IonType::Z, IonType::R, | 
|---|
| 258 | * IonType:IMT, ... | 
|---|
| 259 | * \param P Problem at hand (containing Ions and Lattice structures) | 
|---|
| 260 | * \param *source file pointer | 
|---|
| 261 | */ | 
|---|
| 262 | void IonsInitRead(struct Problem *P, FILE *source) { | 
|---|
| 263 | struct Ions *I = &P->Ion; | 
|---|
| 264 | //struct RunStruct *Run = &P->R; | 
|---|
| 265 | int i,it,j,IMT,d,me, count; | 
|---|
| 266 | int relative; // whether read-in coordinate are relative (1) or absolute | 
|---|
| 267 | double Bohr = ANGSTROEMINBOHRRADIUS; /* Angstroem */ | 
|---|
| 268 | double sigma, R[3], U[3]; | 
|---|
| 269 | struct IonConstrained *ptr = NULL; | 
|---|
| 270 |  | 
|---|
| 271 | I->Max_TotalIons = 0; | 
|---|
| 272 | I->TotalZval = 0; | 
|---|
| 273 | MPI_Comm_rank(MPI_COMM_WORLD, &me); | 
|---|
| 274 | ParseForParameter(P->Call.out[ReadOut],source,"RCut", 0, 1, 1, double_type, &I->R_cut, 1, critical); | 
|---|
| 275 | ParseForParameter(P->Call.out[ReadOut],source,"IsAngstroem", 0, 1, 1, int_type, &I->IsAngstroem, 1, critical); | 
|---|
| 276 | if (!I->IsAngstroem) { | 
|---|
| 277 | Bohr = 1.0; | 
|---|
| 278 | } else {  // adapt RealBasis (is in Angstroem as well) | 
|---|
| 279 | SM(P->Lat.RealBasis, Bohr, NDIM_NDIM); | 
|---|
| 280 | RMatReci3(P->Lat.InvBasis,  P->Lat.RealBasis); | 
|---|
| 281 | } | 
|---|
| 282 | ParseForParameter(P->Call.out[ReadOut],source,"MaxTypes", 0, 1, 1, int_type, &I->Max_Types, 1, critical); | 
|---|
| 283 | I->I = (struct IonType *) Malloc(sizeof(struct IonType)*I->Max_Types, "IonsInitRead: IonType"); | 
|---|
| 284 | if (!ParseForParameter(P->Call.out[ReadOut],source,"RelativeCoord", 0, 1, 1, int_type, &relative, 1, optional)) | 
|---|
| 285 | relative = 0; | 
|---|
| 286 | if (!ParseForParameter(P->Call.out[ReadOut],source,"StructOpt", 0, 1, 1, int_type, &I->StructOpt, 1, optional)) | 
|---|
| 287 | I->StructOpt = 0; | 
|---|
| 288 |  | 
|---|
| 289 | InitThermostats(P, source); | 
|---|
| 290 |  | 
|---|
| 291 | /* Ions Data */ | 
|---|
| 292 | I->RLatticeVec = NULL; | 
|---|
| 293 | I->TotalMass = 0; | 
|---|
| 294 | char *free_name, *name; | 
|---|
| 295 | name = free_name = Malloc(MAXSTRINGSIZE*sizeof(char),"IonsInitRead: Name"); | 
|---|
| 296 | for (i=0; i < I->Max_Types; i++) { | 
|---|
| 297 | sprintf(name,"Ion_Type%i",i+1); | 
|---|
| 298 | I->I[i].corecorr = NotCoreCorrected; | 
|---|
| 299 | I->I[i].Name = MallocString(MAXSTRINGSIZE, "IonsInitRead: Name"); | 
|---|
| 300 | I->I[i].Symbol = MallocString(MAXSTRINGSIZE, "IonsInitRead: Symbol"); | 
|---|
| 301 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 1, 1, int_type, &I->I[i].Max_IonsOfType, 1, critical); | 
|---|
| 302 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 2, 1, int_type, &I->I[i].Z, 1, critical); | 
|---|
| 303 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 3, 1, double_type, &I->I[i].rgauss, 1, critical); | 
|---|
| 304 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 4, 1, int_type, &I->I[i].l_max, 1, critical); | 
|---|
| 305 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 5, 1, int_type, &I->I[i].l_loc, 1, critical); | 
|---|
| 306 | ParseForParameter(P->Call.out[ReadOut],source, name, 0, 6, 1, double_type, &I->I[i].IonMass, 1, critical); | 
|---|
| 307 | if(!ParseForParameter(P->Call.out[ReadOut],source, name, 0, 7, 1, string_type, &I->I[i].Name[0], 1, optional)) | 
|---|
| 308 | sprintf(&I->I[i].Name[0],"type%i",i); | 
|---|
| 309 | if(!ParseForParameter(P->Call.out[ReadOut],source, name, 0, 8, 1, string_type, &I->I[i].Symbol[0], 1, optional)) | 
|---|
| 310 | sprintf(&I->I[i].Symbol[0],"t%i",i); | 
|---|
| 311 | 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); | 
|---|
| 312 | I->I[i].moment = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: moment"); | 
|---|
| 313 | I->I[i].sigma = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: sigma"); | 
|---|
| 314 | I->I[i].sigma_rezi = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: sigma_rezi"); | 
|---|
| 315 | I->I[i].sigma_PAS = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: sigma_PAS"); | 
|---|
| 316 | I->I[i].sigma_rezi_PAS = (double **) Malloc(sizeof(double *) * I->I[i].Max_IonsOfType, "IonsInitRead: sigma_rezi_PAS"); | 
|---|
| 317 | for (it=0;it<I->I[i].Max_IonsOfType;it++) { | 
|---|
| 318 | I->I[i].moment[it] = (double *) Malloc(sizeof(double) * NDIM*NDIM, "IonsInitRead: moment"); | 
|---|
| 319 | I->I[i].sigma[it] = (double *) Malloc(sizeof(double) * NDIM*NDIM, "IonsInitRead: sigma"); | 
|---|
| 320 | I->I[i].sigma_rezi[it] = (double *) Malloc(sizeof(double) * NDIM*NDIM, "IonsInitRead: sigma_rezi"); | 
|---|
| 321 | I->I[i].sigma_PAS[it] = (double *) Malloc(sizeof(double) * NDIM, "IonsInitRead: sigma_PAS"); | 
|---|
| 322 | I->I[i].sigma_rezi_PAS[it] = (double *) Malloc(sizeof(double) * NDIM, "IonsInitRead: sigma_rezi_PAS"); | 
|---|
| 323 | } | 
|---|
| 324 | //I->I[i].IonFac = I->I[i].IonMass; | 
|---|
| 325 | I->I[i].IonMass *= Units2Electronmass;  // in config given in amu not in "atomic units" (electron mass, m_e = 1) | 
|---|
| 326 | // proportional factor between electron and proton mass | 
|---|
| 327 | I->I[i].IonFac = Units2Electronmass/I->I[i].IonMass; | 
|---|
| 328 | I->TotalMass += I->I[i].Max_IonsOfType*I->I[i].IonMass; | 
|---|
| 329 | sigma = sqrt(P->R.TargetTemp/I->I[i].IonMass); | 
|---|
| 330 | I->I[i].ZFactor = -I->I[i].Z*4.*PI; | 
|---|
| 331 | I->I[i].alpha = (double *) Malloc(sizeof(double) * I->I[i].Max_IonsOfType, "IonsInitRead: alpha"); | 
|---|
| 332 | I->I[i].R = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: R"); | 
|---|
| 333 | I->I[i].R_old = (double *) Malloc(sizeof(double) *NDIM* I->I[i].Max_IonsOfType, "IonsInitRead: R_old"); | 
|---|
| 334 | I->I[i].R_old_old = (double *) Malloc(sizeof(double) *NDIM* I->I[i].Max_IonsOfType, "IonsInitRead: R_old_old"); | 
|---|
| 335 | I->I[i].Constraints = (struct IonConstrained **) Malloc(sizeof(struct IonConstrained *)*I->I[i].Max_IonsOfType, "IonsInitRead: **Constraints"); | 
|---|
| 336 | for (it=0;it<I->I[i].Max_IonsOfType;it++) | 
|---|
| 337 | I->I[i].Constraints[it] = NULL; | 
|---|
| 338 | I->I[i].FIon = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FIon"); | 
|---|
| 339 | I->I[i].FIon_old = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FIon_old"); | 
|---|
| 340 | SetArrayToDouble0(I->I[i].FIon_old, NDIM*I->I[i].Max_IonsOfType); | 
|---|
| 341 | I->I[i].SearchDir = Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: SearchDir"); | 
|---|
| 342 | I->I[i].GammaA = Malloc(sizeof(double) * I->I[i].Max_IonsOfType, "IonsInitRead: GammaA"); | 
|---|
| 343 | SetArrayToDouble0(I->I[i].GammaA, I->I[i].Max_IonsOfType); | 
|---|
| 344 | I->I[i].U = (double *) Malloc(sizeof(double) *NDIM* I->I[i].Max_IonsOfType, "IonsInitRead: U"); | 
|---|
| 345 | SetArrayToDouble0(I->I[i].U, NDIM*I->I[i].Max_IonsOfType); | 
|---|
| 346 | I->I[i].SFactor = NULL; | 
|---|
| 347 | I->I[i].IMT = (enum IonMoveType *) Malloc(sizeof(enum IonMoveType) * I->I[i].Max_IonsOfType, "IonsInitRead: IMT"); | 
|---|
| 348 | I->I[i].FIonL = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FIonL"); | 
|---|
| 349 | I->I[i].FIonNL = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FIonNL"); | 
|---|
| 350 | I->I[i].FMagnetic = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FMagnetic"); | 
|---|
| 351 | I->I[i].FConstraint = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FConstraint"); | 
|---|
| 352 | I->I[i].FEwald = (double *) Malloc(sizeof(double) * NDIM * I->I[i].Max_IonsOfType, "IonsInitRead: FEwald"); | 
|---|
| 353 | I->I[i].alpha = (double *) Malloc(sizeof(double) * I->I[i].Max_IonsOfType, "IonsInitRead: alpha"); | 
|---|
| 354 | // now parse ion coordination | 
|---|
| 355 | for (j=0; j < I->I[i].Max_IonsOfType; j++) { | 
|---|
| 356 | I->I[i].alpha[j] = 2.; | 
|---|
| 357 | sprintf(name,"Ion_Type%i_%i",i+1,j+1); | 
|---|
| 358 | for (d=0; d <NDIM; d++) // transfor to old and old_old coordinates as well | 
|---|
| 359 | I->I[i].FMagnetic[d+j*NDIM] = 0.; | 
|---|
| 360 | // first ones are starting positions | 
|---|
| 361 | if ((count = ParseIonsCoordinatesAndVelocities(P, source, name, 1, relative, sigma, &I->I[i].R[NDIM*j], &I->I[i].U[NDIM*j], &IMT))) { | 
|---|
| 362 | for (d=0; d <NDIM; d++) // transfor to old and old_old coordinates as well | 
|---|
| 363 | I->I[i].R_old_old[d+NDIM*j] = I->I[i].R_old[d+NDIM*j] = I->I[i].R[d+NDIM*j]; | 
|---|
| 364 | I->I[i].IMT[j] = IMT; | 
|---|
| 365 | if (P->Call.out[ReadOut]) fprintf(stderr, "(%i) R[%d,%d] = (%lg, %lg, %lg)\n", P->Par.me, i,j,I->I[i].R[0+NDIM*j],I->I[i].R[1+NDIM*j],I->I[i].R[2+NDIM*j]); | 
|---|
| 366 | if (P->Call.out[ReadOut]) fprintf(stderr, "(%i) U[%d,%d] = (%lg, %lg, %lg)\n", P->Par.me, i,j,I->I[i].U[0+NDIM*j],I->I[i].U[1+NDIM*j],I->I[i].U[2+NDIM*j]); | 
|---|
| 367 | if (P->Call.out[ReadOut]) fprintf(stderr, "(%i) IMT[%d,%d] = %i\n", P->Par.me, i,j,I->I[i].IMT[j]); | 
|---|
| 368 | } else { | 
|---|
| 369 | Error(SomeError, "Could not find or parse coordinates of an ion"); | 
|---|
| 370 | } | 
|---|
| 371 | // following ones are constrained motions | 
|---|
| 372 | while (ParseIonsCoordinatesAndVelocities(P, source, name, ++count, relative, sigma, R, U, &IMT)) { | 
|---|
| 373 | if (P->Call.out[ReadOut]) fprintf(stderr, "(%i) Constrained read %d ...\n", P->Par.me, count-1); | 
|---|
| 374 | ptr = AddConstraintItem(&I->I[i], j);  // allocate memory | 
|---|
| 375 | for (d=0; d< NDIM; d++) { // fill the constraint item | 
|---|
| 376 | ptr->R[d] = R[d]; | 
|---|
| 377 | ptr->U[d] = U[d]; | 
|---|
| 378 | } | 
|---|
| 379 | ptr->IMT = IMT; | 
|---|
| 380 | ptr->step = count-1; | 
|---|
| 381 | if (P->Call.out[ReadOut]) fprintf(stderr, "(%i) R[%d,%d] = (%lg, %lg, %lg)\n", P->Par.me, i,j,ptr->R[0],ptr->R[1],ptr->R[2]); | 
|---|
| 382 | if (P->Call.out[ReadOut]) fprintf(stderr, "(%i) U[%d,%d] = (%lg, %lg, %lg)\n", P->Par.me, i,j,ptr->U[0],ptr->U[1],ptr->U[2]); | 
|---|
| 383 | if (P->Call.out[ReadOut]) fprintf(stderr, "(%i) IMT[%d,%d] = %i\n", P->Par.me, i,j,ptr->IMT); | 
|---|
| 384 | } | 
|---|
| 385 | //if (P->Call.out[ReadOut]) | 
|---|
| 386 | fprintf(stderr,"(%i) A total of %d additional constrained moves for ion (%d,%d) was parsed.\n", P->Par.me, count-2, i,j); | 
|---|
| 387 |  | 
|---|
| 388 | I->Max_TotalIons++; | 
|---|
| 389 | } | 
|---|
| 390 | } | 
|---|
| 391 | Free(free_name, "IonsInitRead: free_name"); | 
|---|
| 392 | I->Max_Max_IonsOfType = 0; | 
|---|
| 393 | for (i=0; i < I->Max_Types; i++) | 
|---|
| 394 | I->Max_Max_IonsOfType = MAX(I->Max_Max_IonsOfType, I->I[i].Max_IonsOfType); | 
|---|
| 395 | I->FTemp = (double *) Malloc(sizeof(double) * NDIM * I->Max_Max_IonsOfType, "IonsInitRead:"); | 
|---|
| 396 | } | 
|---|
| 397 |  | 
|---|
| 398 | /** Allocates memory for a IonConstrained item and adds to end of list. | 
|---|
| 399 | * \param *I IonType structure | 
|---|
| 400 | * \param ion which ion of the type | 
|---|
| 401 | * \return pointer to created item | 
|---|
| 402 | */ | 
|---|
| 403 | struct IonConstrained * AddConstraintItem(struct IonType *I, int ion) | 
|---|
| 404 | { | 
|---|
| 405 | struct IonConstrained **ptr = &(I->Constraints[ion]); | 
|---|
| 406 | while (*ptr != NULL) { // advance to end of list | 
|---|
| 407 | ptr = &((*ptr)->next); | 
|---|
| 408 | } | 
|---|
| 409 | // allocated memory for structure and items within | 
|---|
| 410 | *ptr = (struct IonConstrained *) Malloc(sizeof(struct IonConstrained), "CreateConstraintItem: IonConstrained"); | 
|---|
| 411 | (*ptr)->R = (double *) Malloc(sizeof(double)*NDIM, "AddConstraintItem: *R"); | 
|---|
| 412 | (*ptr)->U = (double *) Malloc(sizeof(double)*NDIM, "AddConstraintItem: *U"); | 
|---|
| 413 | (*ptr)->next = NULL; | 
|---|
| 414 | return *ptr; | 
|---|
| 415 | } | 
|---|
| 416 |  | 
|---|
| 417 | /** Removes first of item of IonConstrained list for given \a ion. | 
|---|
| 418 | * Frees memory of items within and then | 
|---|
| 419 | * \param *I IonType structure | 
|---|
| 420 | * \param ion which ion of the type | 
|---|
| 421 | * \return 1 - success, 0 - failure (list is already empty, start pointer was NULL) | 
|---|
| 422 | */ | 
|---|
| 423 | int RemoveConstraintItem(struct IonType *I, int ion) | 
|---|
| 424 | { | 
|---|
| 425 | struct IonConstrained **ptr = &(I->Constraints[ion]); | 
|---|
| 426 | struct IonConstrained *next_ptr; | 
|---|
| 427 | if (*ptr != NULL) { | 
|---|
| 428 | next_ptr = (*ptr)->next; | 
|---|
| 429 | Free((*ptr)->R, "RemoveConstraintItem: R"); | 
|---|
| 430 | Free((*ptr)->U, "RemoveConstraintItem: U"); | 
|---|
| 431 | Free((*ptr), "RemoveConstraintItem: IonConstrained structure"); | 
|---|
| 432 | *ptr = next_ptr; // set start of list to next item (automatically is null if ptr was last item) | 
|---|
| 433 | return 1; | 
|---|
| 434 | } else { | 
|---|
| 435 | return 0; | 
|---|
| 436 | } | 
|---|
| 437 | } | 
|---|
| 438 |  | 
|---|
| 439 | /** Calculated Ewald force. | 
|---|
| 440 | * The basic idea of the ewald method is to add a countercharge - here of gaussian form - | 
|---|
| 441 | * which shields the long-range charges making them effectively short-ranged, while the | 
|---|
| 442 | * countercharges themselves can be analytically (here by (hidden) Fouriertransform: it's | 
|---|
| 443 | * added to the electron density) integrated and withdrawn. | 
|---|
| 444 | * \f[ | 
|---|
| 445 | *  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|} | 
|---|
| 446 | *    \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 ) | 
|---|
| 447 | *    \qquad (4.10) | 
|---|
| 448 | * \f] | 
|---|
| 449 | * Calculates the core-to-core force between the ions of all super cells. | 
|---|
| 450 | * In order for this series to converge there must be a certain summation | 
|---|
| 451 | * applied, which is the ewald summation and which is nothing else but to move | 
|---|
| 452 | * in a circular motion from the current cell to the outside up to Ions::R_cut. | 
|---|
| 453 | * \param *P Problem at hand | 
|---|
| 454 | * \param first if != 0 table mirror cells to take into (local!) account of ewald summation | 
|---|
| 455 | */ | 
|---|
| 456 | void CalculateEwald(struct Problem *P, int first) | 
|---|
| 457 | { | 
|---|
| 458 | int r,is1,is2,ia1,ia2,ir,ir2,i,j,k,ActualVec,MaxVec,MaxCell,Is_Neighb_Cell,LocalActualVec; //,is | 
|---|
| 459 | int MaxPar=P->Par.procs, ParMe=P->Par.me, MaxLocalVec, StartVec; | 
|---|
| 460 | double rcut2,r2,erre2,addesr,addpre,arg,fac,gkl,esr,fxx,repand; | 
|---|
| 461 | double R1[3]; | 
|---|
| 462 | double R2[3]; | 
|---|
| 463 | double R3[3]; | 
|---|
| 464 | double t[3]; | 
|---|
| 465 | struct Lattice *L = &P->Lat; | 
|---|
| 466 | struct PseudoPot *PP = &P->PP; | 
|---|
| 467 | struct Ions *I = &P->Ion; | 
|---|
| 468 | if (first) { | 
|---|
| 469 | SpeedMeasure(P, InitSimTime, StopTimeDo); | 
|---|
| 470 | rcut2 = I->R_cut*I->R_cut; | 
|---|
| 471 | ActualVec = 0;  // counts number of cells taken into account | 
|---|
| 472 | MaxCell = (int)(5.*I->R_cut/pow(L->Volume,1./3.));    // the number of cells in each direction is prop. to axis length over cutoff | 
|---|
| 473 | if (MaxCell < 2) MaxCell = 2;     // take at least 2 | 
|---|
| 474 | for (i = -MaxCell; i <= MaxCell; i++) { | 
|---|
| 475 | for (j = -MaxCell; j <= MaxCell; j++) { | 
|---|
| 476 | for (k = -MaxCell; k <= MaxCell; k++) { | 
|---|
| 477 | r2 = 0.; | 
|---|
| 478 | for (ir=0; ir <NDIM; ir++) {  // t is the offset vector pointing to distant cell (only diagonal entries) | 
|---|
| 479 | t[ir] = i*L->RealBasis[0*NDIM+ir]+j*L->RealBasis[1*NDIM+ir]+k*L->RealBasis[2*NDIM+ir]; | 
|---|
| 480 | r2 = t[ir]*t[ir];   // is squared distance to other cell | 
|---|
| 481 | } | 
|---|
| 482 | Is_Neighb_Cell = ((abs(i)<=1) && (abs(j)<=1) && (abs(k)<=1));   // whether it's directly adjacent | 
|---|
| 483 | if ((r2 <= rcut2) || Is_Neighb_Cell) {    // if it's either adjacent or within cutoff, count it in | 
|---|
| 484 | ActualVec++; | 
|---|
| 485 | } | 
|---|
| 486 | } | 
|---|
| 487 | } | 
|---|
| 488 | } | 
|---|
| 489 | MaxVec = ActualVec;   // store number of cells | 
|---|
| 490 | I->MaxVec = ActualVec; | 
|---|
| 491 | MaxLocalVec = MaxVec / MaxPar;  // share among processes | 
|---|
| 492 | StartVec = ParMe*MaxLocalVec; // for this process start at its patch | 
|---|
| 493 | r = MaxVec % MaxPar;  // rest not fitting... | 
|---|
| 494 | if (ParMe >= r) {   // ones who don't get extra cells have to shift their start vector | 
|---|
| 495 | StartVec += r; | 
|---|
| 496 | } else {    // others get extra cell and have to shift also by a bit | 
|---|
| 497 | StartVec += ParMe; | 
|---|
| 498 | MaxLocalVec++; | 
|---|
| 499 | } | 
|---|
| 500 | I->MaxLocalVec = MaxLocalVec; | 
|---|
| 501 | LocalActualVec = ActualVec = 0; | 
|---|
| 502 | // now go through the same loop again and note down every offset vector for cells in this process' patch | 
|---|
| 503 | if (MaxLocalVec != 0) { | 
|---|
| 504 | I->RLatticeVec = (double *) | 
|---|
| 505 | Realloc(I->RLatticeVec, sizeof(double)*NDIM*MaxLocalVec, "CalculateEwald: I->RLatticeVec"); | 
|---|
| 506 | } else { | 
|---|
| 507 | fprintf(stderr,"(%i) Warning in Ewald summation: Got MaxLocalVec == 0\n", P->Par.me); | 
|---|
| 508 | } | 
|---|
| 509 | for (i = -MaxCell; i <= MaxCell; i++) { | 
|---|
| 510 | for (j = -MaxCell; j <= MaxCell; j++) { | 
|---|
| 511 | for (k = -MaxCell; k <= MaxCell; k++) { | 
|---|
| 512 | r2 = 0.; | 
|---|
| 513 | for (ir=0; ir <NDIM; ir++) {  // create offset vector from diagonal entries | 
|---|
| 514 | t[ir] = i*L->RealBasis[0*NDIM+ir]+j*L->RealBasis[1*NDIM+ir]+k*L->RealBasis[2*NDIM+ir]; | 
|---|
| 515 | r2 = t[ir]*t[ir]; | 
|---|
| 516 | } | 
|---|
| 517 | Is_Neighb_Cell = ((abs(i)<=1) && (abs(j)<=1) && (abs(k)<=1)); | 
|---|
| 518 | if ((r2 <= rcut2) || Is_Neighb_Cell) {  // if adjacent or within cutoff ... | 
|---|
| 519 | if (ActualVec >= StartVec && ActualVec < StartVec+MaxLocalVec) { // ... and belongs to patch, store 'em | 
|---|
| 520 | I->RLatticeVec[0+NDIM*LocalActualVec] = t[0]; | 
|---|
| 521 | I->RLatticeVec[1+NDIM*LocalActualVec] = t[1]; | 
|---|
| 522 | I->RLatticeVec[2+NDIM*LocalActualVec] = t[2]; | 
|---|
| 523 | LocalActualVec++; | 
|---|
| 524 | } | 
|---|
| 525 | ActualVec++; | 
|---|
| 526 | } | 
|---|
| 527 | } | 
|---|
| 528 | } | 
|---|
| 529 | } | 
|---|
| 530 | SpeedMeasure(P, InitSimTime, StartTimeDo); | 
|---|
| 531 | } | 
|---|
| 532 | SpeedMeasure(P, EwaldTime, StartTimeDo); | 
|---|
| 533 |  | 
|---|
| 534 | // first set everything to zero | 
|---|
| 535 | esr = 0.0; | 
|---|
| 536 | //for (is1=0;is1 < I->Max_Types; is1++) | 
|---|
| 537 | // then take each ion of each type once | 
|---|
| 538 | for (is1=0;is1 < I->Max_Types; is1++) { | 
|---|
| 539 | // reset FTemp for IonType | 
|---|
| 540 | for (ia1=0;ia1 < I->I[is1].Max_IonsOfType; ia1++) | 
|---|
| 541 | for (i=0; i< NDIM; i++) | 
|---|
| 542 | I->FTemp[i+NDIM*(ia1)] = 0.; | 
|---|
| 543 | // then sum for each on of the IonType | 
|---|
| 544 | for (ia1=0;ia1 < I->I[is1].Max_IonsOfType; ia1++) { | 
|---|
| 545 | for (i=0;i<NDIM;i++) { | 
|---|
| 546 | R1[i]=I->I[is1].R[i+NDIM*ia1];    // R1 is local coordinate of current first ion | 
|---|
| 547 | } | 
|---|
| 548 | for (ir2=0;ir2<I->MaxLocalVec;ir2++) {  // for every cell of local patch (each with the same atoms) | 
|---|
| 549 | for (is2=0;is2 < I->Max_Types; is2++) { // and for each ion of each type a second time | 
|---|
| 550 | // gkl = 1./(sqrt(r_is1,gauss^2 + r_is2,gauss^2)) | 
|---|
| 551 | gkl=1./sqrt(I->I[is1].rgauss*I->I[is1].rgauss + I->I[is2].rgauss*I->I[is2].rgauss); | 
|---|
| 552 | for (ia2=0;ia2<I->I[is2].Max_IonsOfType; ia2++) { | 
|---|
| 553 | for (i=0;i<3;i++) { | 
|---|
| 554 | R2[i]=I->RLatticeVec[i+NDIM*ir2]+I->I[is2].R[i+NDIM*ia2]; // R2 is coordinate of current second ion in the distant cell! | 
|---|
| 555 | } | 
|---|
| 556 |  | 
|---|
| 557 | erre2=0.0; | 
|---|
| 558 | for (i=0;i<NDIM;i++) { | 
|---|
| 559 | R3[i] = R1[i]-R2[i];    // R3 = R_is1,ia1 - R_is2,ia2 - L | 
|---|
| 560 | erre2+=R3[i]*R3[i];     // erre2 = |R_is1,ia1 - R_is2,ia2 - L|^2 | 
|---|
| 561 | } | 
|---|
| 562 | if (erre2 > MYEPSILON) {  // appears as one over ... in fac, thus check if zero | 
|---|
| 563 | arg = sqrt(erre2); // arg = |R_is1,ia1 - R_is2,ia2 - L| | 
|---|
| 564 | fac=PP->zval[is1]*PP->zval[is2]/arg*0.5;    // fac = -1/2 * Z_is1 * Z_is2 / arg | 
|---|
| 565 |  | 
|---|
| 566 | arg *= gkl;             // arg = |R_is1,ia1 - R_is2,ia2 - L|/(sqrt(r_is1,gauss^2 + r_is2,gauss^2)) | 
|---|
| 567 | addesr = derf(arg); | 
|---|
| 568 | addesr = (1.-addesr)*fac; // complementary error function: addesr = 1/2*erfc(arg)/|R_is1,ia1 - R_is2,ia2 - L| | 
|---|
| 569 | esr += addesr; | 
|---|
| 570 | addpre=exp(-arg*arg)*gkl; | 
|---|
| 571 | addpre = PP->fac1sqrtPI*PP->zval[is1]*PP->zval[is2]*addpre;  // addpre = exp(-|R_is1,ia1 - R_is2,ia2 - L|^2/(r_is1,gauss^2 + r_is2,gauss^2))/(sqrt(pi)*sqrt(r_is1,gauss^2 + r_is2,gauss^2)) | 
|---|
| 572 | repand = (addesr+addpre)/erre2; | 
|---|
| 573 | //              if ((fabs(repand) > MYEPSILON)) { | 
|---|
| 574 | //                fprintf(stderr,"(%i) Ewald[is%d,ia%d/is%d,ia%d,(%d)]: Z1 %lg, Z2 %lg\tpre %lg\t esr %lg\t fac %lg\t arg %lg\tR3 (%lg,%lg,%lg)\n", P->Par.me,  is1, ia1, is2, ia2, ir2, PP->zval[is1], PP->zval[is2],addpre,addesr, fac, arg, R3[0], R3[1], R3[2]); | 
|---|
| 575 | //              } | 
|---|
| 576 | for (i=0;i<NDIM;i++) { | 
|---|
| 577 | fxx=repand*R3[i]; | 
|---|
| 578 | //                if ((fabs(repand) > MYEPSILON)) { | 
|---|
| 579 | //                                                                fprintf(stderr,"%i %i %i %i %i %g\n",is1+1,ia1+1,is2+1,ia2+1,i+1,fxx); | 
|---|
| 580 | //                } | 
|---|
| 581 | I->FTemp[i+NDIM*(ia1)] += fxx*2.0;      // actio = reactio? | 
|---|
| 582 | //I->FTemp[i+NDIM*(ia2)] -= fxx; | 
|---|
| 583 | } | 
|---|
| 584 | } | 
|---|
| 585 | } | 
|---|
| 586 | } | 
|---|
| 587 | } | 
|---|
| 588 | } | 
|---|
| 589 | MPI_Allreduce (I->FTemp , I->I[is1].FEwald, NDIM*I->I[is1].Max_IonsOfType, MPI_DOUBLE, MPI_SUM, P->Par.comm); | 
|---|
| 590 | } | 
|---|
| 591 | SpeedMeasure(P, EwaldTime, StopTimeDo); | 
|---|
| 592 | //for (is=0;is < I->Max_Types; is++) { | 
|---|
| 593 | //} | 
|---|
| 594 | MPI_Allreduce ( &esr, &L->E->AllTotalIonsEnergy[EwaldEnergy], 1, MPI_DOUBLE, MPI_SUM, P->Par.comm); | 
|---|
| 595 | //  fprintf(stderr,"\n"); | 
|---|
| 596 | } | 
|---|
| 597 |  | 
|---|
| 598 | /** Sum up all forces acting on Ions. | 
|---|
| 599 | * IonType::FIon = IonType::FEwald  + IonType::FIonL + IonType::FIonNL + IonType::FMagnetic for all | 
|---|
| 600 | * dimensions #NDIM and each Ion of IonType | 
|---|
| 601 | * \param *P Problem at hand | 
|---|
| 602 | */ | 
|---|
| 603 | void CalculateIonForce(struct Problem *P) | 
|---|
| 604 | { | 
|---|
| 605 | struct Ions *I = &P->Ion; | 
|---|
| 606 | int i,j,d; | 
|---|
| 607 | for (i=0; i < I->Max_Types; i++) | 
|---|
| 608 | for (j=0; j < I->I[i].Max_IonsOfType; j++) | 
|---|
| 609 | for (d=0; d<NDIM;d++) | 
|---|
| 610 | 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] + I->I[i].FMagnetic[d+j*NDIM]); | 
|---|
| 611 | } | 
|---|
| 612 |  | 
|---|
| 613 | /** Write Forces to FileData::ForcesFile. | 
|---|
| 614 | * goes through all Ions per IonType and each dimension of #NDIM and prints in one line: | 
|---|
| 615 | * Position IonType::R, total force Ion IonType::FIon, local force IonType::FIonL, | 
|---|
| 616 | * non-local IonType::FIonNL, ewald force IonType::FEwald | 
|---|
| 617 | * \param *P Problem at hand | 
|---|
| 618 | */ | 
|---|
| 619 | void OutputIonForce(struct Problem *P) | 
|---|
| 620 | { | 
|---|
| 621 | struct RunStruct *R = &P->R; | 
|---|
| 622 | struct FileData *F = &P->Files; | 
|---|
| 623 | struct Ions *I = &P->Ion; | 
|---|
| 624 | FILE *fout = NULL; | 
|---|
| 625 | int i,j; | 
|---|
| 626 | if (F->MeOutMes != 1) return; | 
|---|
| 627 | fout = F->ForcesFile; | 
|---|
| 628 | for (i=0; i < I->Max_Types; i++) | 
|---|
| 629 | for (j=0; j < I->I[i].Max_IonsOfType; j++) | 
|---|
| 630 | 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\t%e\t%e\t%e\n", i,j, | 
|---|
| 631 | I->I[i].R[0+j*NDIM], I->I[i].R[1+j*NDIM], I->I[i].R[2+j*NDIM], | 
|---|
| 632 | I->I[i].FIon[0+j*NDIM], I->I[i].FIon[1+j*NDIM], I->I[i].FIon[2+j*NDIM], | 
|---|
| 633 | I->I[i].FIonL[0+j*NDIM], I->I[i].FIonL[1+j*NDIM], I->I[i].FIonL[2+j*NDIM], | 
|---|
| 634 | I->I[i].FIonNL[0+j*NDIM], I->I[i].FIonNL[1+j*NDIM], I->I[i].FIonNL[2+j*NDIM], | 
|---|
| 635 | I->I[i].FMagnetic[0+j*NDIM], I->I[i].FMagnetic[1+j*NDIM], I->I[i].FMagnetic[2+j*NDIM], | 
|---|
| 636 | I->I[i].FEwald[0+j*NDIM], I->I[i].FEwald[1+j*NDIM], I->I[i].FEwald[2+j*NDIM]); | 
|---|
| 637 | fflush(fout); | 
|---|
| 638 | fprintf(fout, "MeanForce:\t%e\n", R->MeanForce[0]); | 
|---|
| 639 | } | 
|---|
| 640 |  | 
|---|
| 641 | /** Reads Forces from CallOptions::ForcesFile. | 
|---|
| 642 | * goes through all Ions per IonType and each dimension of #NDIM and parses in one line: | 
|---|
| 643 | * Position IonType::R, total force Ion IonType::FIon, local force IonType::FIonL, | 
|---|
| 644 | * non-local IonType::FIonNL, ewald force IonType::FEwald | 
|---|
| 645 | * \param *P Problem at hand | 
|---|
| 646 | */ | 
|---|
| 647 | void ParseIonForce(struct Problem *P) | 
|---|
| 648 | { | 
|---|
| 649 | //struct RunStruct *Run = &P->R; | 
|---|
| 650 | struct Ions *I = &P->Ion; | 
|---|
| 651 | FILE *finput = NULL; | 
|---|
| 652 | char line[1024]; | 
|---|
| 653 | int i,j; | 
|---|
| 654 | double i1, j1; | 
|---|
| 655 | double R[NDIM]; | 
|---|
| 656 |  | 
|---|
| 657 | if (P->Call.ForcesFile == NULL) return; | 
|---|
| 658 | finput = fopen(P->Call.ForcesFile, "r"); | 
|---|
| 659 | //fprintf(stderr, "File pointer says %p\n", finput); | 
|---|
| 660 | if (finput == NULL) | 
|---|
| 661 | Error(InitReading, "ForcesFile does not exist."); | 
|---|
| 662 | fscanf(finput, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", line,line,line,line,line,line,line,line,line,line,line,line,line,line,line,line,line,line,line,line);        // skip header line | 
|---|
| 663 | for (i=0; i < I->Max_Types; i++) | 
|---|
| 664 | for (j=0; j < I->I[i].Max_IonsOfType; j++) | 
|---|
| 665 | if (feof(finput)) { | 
|---|
| 666 | Error(InitReading, "ForcesFile does not contain enough lines."); | 
|---|
| 667 | } else { | 
|---|
| 668 | //fscanf(finput, "%s\n", line); | 
|---|
| 669 | //if (strlen(line) < 100) { | 
|---|
| 670 | //fprintf(stderr, "i %d, j %d, length of line %ld, line %s.\n", i,j, strlen(line), line); | 
|---|
| 671 | //Error(InitReading, "ForcesFile does not contain enough lines or line is faulty."); | 
|---|
| 672 | //} else | 
|---|
| 673 | //fprintf(stderr, "Parsed line: '%s'\n", line); | 
|---|
| 674 | fscanf(finput, "%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\t%le\n", &i1,&j1, | 
|---|
| 675 | &R[0], &R[1], &R[2], | 
|---|
| 676 | &I->I[i].FIon[0+j*NDIM], &I->I[i].FIon[1+j*NDIM], &I->I[i].FIon[2+j*NDIM], | 
|---|
| 677 | &I->I[i].FIonL[0+j*NDIM], &I->I[i].FIonL[1+j*NDIM], &I->I[i].FIonL[2+j*NDIM], | 
|---|
| 678 | &I->I[i].FIonNL[0+j*NDIM], &I->I[i].FIonNL[1+j*NDIM], &I->I[i].FIonNL[2+j*NDIM], | 
|---|
| 679 | &I->I[i].FMagnetic[0+j*NDIM], &I->I[i].FMagnetic[1+j*NDIM], &I->I[i].FMagnetic[2+j*NDIM], | 
|---|
| 680 | &I->I[i].FEwald[0+j*NDIM], &I->I[i].FEwald[1+j*NDIM], &I->I[i].FEwald[2+j*NDIM]); | 
|---|
| 681 | if ((i != (int)i1) || (j != (int)j1)) | 
|---|
| 682 | Error(InitReading, "Line does not match to desired ion."); | 
|---|
| 683 | } | 
|---|
| 684 | fclose(finput); | 
|---|
| 685 | //fprintf(stderr, "MeanForce:\t%e\n", Run->MeanForce[0]); | 
|---|
| 686 | }; | 
|---|
| 687 |  | 
|---|
| 688 | /** Frees memory IonType. | 
|---|
| 689 | * All pointers from IonType and the pointer on it are free'd | 
|---|
| 690 | * \param *I Ions structure to be free'd | 
|---|
| 691 | * \sa IonsInitRead where memory is allocated | 
|---|
| 692 | */ | 
|---|
| 693 | void RemoveIonsRead(struct Ions *I) | 
|---|
| 694 | { | 
|---|
| 695 | int i, it; | 
|---|
| 696 | for (i=0; i < I->Max_Types; i++) { | 
|---|
| 697 | Free(I->I[i].Name, "RemoveIonsRead: I->I[i].Name"); | 
|---|
| 698 | Free(I->I[i].Symbol, "RemoveIonsRead: I->I[i].Symbol"); | 
|---|
| 699 | for (it=0;it<I->I[i].Max_IonsOfType;it++) { | 
|---|
| 700 | Free(I->I[i].moment[it], "RemoveIonsRead: I->I[i].moment[it]"); | 
|---|
| 701 | Free(I->I[i].sigma[it], "RemoveIonsRead: I->I[i].sigma[it]"); | 
|---|
| 702 | Free(I->I[i].sigma_rezi[it], "RemoveIonsRead: I->I[i].sigma_rezi[it]"); | 
|---|
| 703 | Free(I->I[i].sigma_PAS[it], "RemoveIonsRead: I->I[i].sigma_PAS[it]"); | 
|---|
| 704 | Free(I->I[i].sigma_rezi_PAS[it], "RemoveIonsRead: I->I[i].sigma_rezi_PAS[it]"); | 
|---|
| 705 | while (RemoveConstraintItem(&I->I[i], it)); // empty the constrained item list | 
|---|
| 706 | } | 
|---|
| 707 | Free(I->I[i].sigma, "RemoveIonsRead: I->I[i].sigma"); | 
|---|
| 708 | Free(I->I[i].sigma_rezi, "RemoveIonsRead: I->I[i].sigma_rezi"); | 
|---|
| 709 | Free(I->I[i].sigma_PAS, "RemoveIonsRead: I->I[i].sigma_PAS"); | 
|---|
| 710 | Free(I->I[i].sigma_rezi_PAS, "RemoveIonsRead: I->I[i].sigma_rezi_PAS"); | 
|---|
| 711 | Free(I->I[i].R, "RemoveIonsRead: I->I[i].R"); | 
|---|
| 712 | Free(I->I[i].R_old, "RemoveIonsRead: I->I[i].R_old"); | 
|---|
| 713 | Free(I->I[i].R_old_old, "RemoveIonsRead: I->I[i].R_old_old"); | 
|---|
| 714 | Free(I->I[i].Constraints, "RemoveIonsRead: I->I[i].Constraints"); | 
|---|
| 715 | Free(I->I[i].FIon, "RemoveIonsRead: I->I[i].FIon"); | 
|---|
| 716 | Free(I->I[i].FIon_old, "RemoveIonsRead: I->I[i].FIon_old"); | 
|---|
| 717 | Free(I->I[i].SearchDir, "RemoveIonsRead: I->I[i].SearchDir"); | 
|---|
| 718 | Free(I->I[i].GammaA, "RemoveIonsRead: I->I[i].GammaA"); | 
|---|
| 719 | Free(I->I[i].FIonL, "RemoveIonsRead: I->I[i].FIonL"); | 
|---|
| 720 | Free(I->I[i].FIonNL, "RemoveIonsRead: I->I[i].FIonNL"); | 
|---|
| 721 | Free(I->I[i].FMagnetic, "RemoveIonsRead: I->I[i].FMagnetic"); | 
|---|
| 722 | Free(I->I[i].U, "RemoveIonsRead: I->I[i].U"); | 
|---|
| 723 | Free(I->I[i].SFactor, "RemoveIonsRead: I->I[i].SFactor"); | 
|---|
| 724 | Free(I->I[i].IMT, "RemoveIonsRead: I->I[i].IMT"); | 
|---|
| 725 | Free(I->I[i].FEwald, "RemoveIonsRead: I->I[i].FEwald"); | 
|---|
| 726 | Free(I->I[i].alpha, "RemoveIonsRead: I->I[i].alpha"); | 
|---|
| 727 | } | 
|---|
| 728 | if (I->R_cut == 0.0) | 
|---|
| 729 | Free(I->RLatticeVec, "RemoveIonsRead: I->RLatticeVec"); | 
|---|
| 730 | Free(I->FTemp, "RemoveIonsRead: I->FTemp"); | 
|---|
| 731 | Free(I->I, "RemoveIonsRead: I->I"); | 
|---|
| 732 | } | 
|---|
| 733 |  | 
|---|
| 734 | /** Shifts center of gravity of ion forces IonType::FIon. | 
|---|
| 735 | * First sums up all forces of movable ions for net center of gravity force, | 
|---|
| 736 | * then reduces each force by this temp over Ions#Max_TotalIons, so that all in all | 
|---|
| 737 | * the net force is 0. | 
|---|
| 738 | * \param *P Problem at hand | 
|---|
| 739 | * \sa CorrectVelocity() | 
|---|
| 740 | */ | 
|---|
| 741 | void CorrectForces(struct Problem *P) | 
|---|
| 742 | { | 
|---|
| 743 | struct Ions *I = &P->Ion; | 
|---|
| 744 | double *FIon; | 
|---|
| 745 | double FTemp[NDIM]; | 
|---|
| 746 | int is, ia, d, NumIons = 0; | 
|---|
| 747 | for (d=0; d<NDIM; d++) | 
|---|
| 748 | FTemp[d] = 0.; | 
|---|
| 749 | for (is=0; is < I->Max_Types; is++) {         // calculate force temperature for each type ... | 
|---|
| 750 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) {    // .. and each ion of this type ... | 
|---|
| 751 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 752 | if (I->I[is].IMT[ia] == MoveIon) {                // .. if it's influenced | 
|---|
| 753 | NumIons++; | 
|---|
| 754 | for (d=0; d<NDIM; d++) | 
|---|
| 755 | FTemp[d] += FIon[d]; | 
|---|
| 756 | } | 
|---|
| 757 | } | 
|---|
| 758 | } | 
|---|
| 759 | //if (P->Files.MeOutMes != 1) return; | 
|---|
| 760 | //  fprintf(stderr, "TotalForce before: %e\t %e\t %e\n", FTemp[0], FTemp[1], FTemp[2]); | 
|---|
| 761 | for (is=0; is < I->Max_Types; is++) {         // and then reduce each by this value | 
|---|
| 762 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 763 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 764 | if (I->I[is].IMT[ia] == MoveIon) { | 
|---|
| 765 | for (d=0; d<NDIM; d++) | 
|---|
| 766 | FIon[d] -= FTemp[d]/NumIons; | 
|---|
| 767 | } | 
|---|
| 768 | } | 
|---|
| 769 | } | 
|---|
| 770 | /*  for (d=0; d<NDIM; d++) | 
|---|
| 771 | FTemp[d] = 0.; | 
|---|
| 772 | for (is=0; is < I->Max_Types; is++) {         // calculate force temperature for each type ... | 
|---|
| 773 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) {    // .. and each ion of this type ... | 
|---|
| 774 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 775 | if (I->I[is].IMT[ia] == MoveIon) {                // .. if it's influenced | 
|---|
| 776 | for (d=0; d<NDIM; d++) | 
|---|
| 777 | FTemp[d] += FIon[d]; | 
|---|
| 778 | } | 
|---|
| 779 | } | 
|---|
| 780 | } | 
|---|
| 781 | if (P->Files.MeOutMes != 1) return; | 
|---|
| 782 | fprintf(stderr, "TotalForce after: %e\t %e\t %e\n", FTemp[0], FTemp[1], FTemp[2]); | 
|---|
| 783 | */ | 
|---|
| 784 | } | 
|---|
| 785 |  | 
|---|
| 786 |  | 
|---|
| 787 | /** Shifts center of gravity of ion velocities (rather momentums). | 
|---|
| 788 | * First sums up ion speed U times their IonMass (summed up for each | 
|---|
| 789 | * dimension) in temp, then reduces the velocity by temp per Ions::TotalMass (so here | 
|---|
| 790 | * total number of Ions is included) | 
|---|
| 791 | * \param *P Problem at hand | 
|---|
| 792 | * \sa CorrectForces() | 
|---|
| 793 | */ | 
|---|
| 794 | void CorrectVelocity(struct Problem *P) | 
|---|
| 795 | { | 
|---|
| 796 | struct Ions *I = &P->Ion; | 
|---|
| 797 | double *U; | 
|---|
| 798 | double UTemp[NDIM]; | 
|---|
| 799 | int is, ia, d; | 
|---|
| 800 | for (d=0; d<NDIM; d++) | 
|---|
| 801 | UTemp[d] = 0; | 
|---|
| 802 | for (is=0; is < I->Max_Types; is++) {         // all types ... | 
|---|
| 803 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) {    // ... all ions per type ... | 
|---|
| 804 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 805 | //if (I->I[is].IMT[ia] == MoveIon) {      // ... even FixedIon moves, only not by other's forces | 
|---|
| 806 | for (d=0; d<NDIM; d++) | 
|---|
| 807 | UTemp[d] += I->I[is].IonMass*U[d]; | 
|---|
| 808 | //} | 
|---|
| 809 | } | 
|---|
| 810 | } | 
|---|
| 811 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 812 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 813 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 814 | //if (I->I[is].IMT[ia] == MoveIon) { | 
|---|
| 815 | for (d=0; d<NDIM; d++) | 
|---|
| 816 | U[d] -= UTemp[d]/I->TotalMass;                // shift by mean velocity over mass and number of ions | 
|---|
| 817 | //} | 
|---|
| 818 | } | 
|---|
| 819 | } | 
|---|
| 820 | } | 
|---|
| 821 |  | 
|---|
| 822 | /** Moves ions according to calculated force. | 
|---|
| 823 | * Goes through each type of IonType and each ion therein, takes mass and | 
|---|
| 824 | * Newton to move each ion to new coordinates IonType::R, while remembering the last | 
|---|
| 825 | * two coordinates and the last force of the ion. Coordinates R are being | 
|---|
| 826 | * transformed to inverted base, shifted by +-1.0 and back-transformed to | 
|---|
| 827 | * real base. | 
|---|
| 828 | * \param *P Problem at hand | 
|---|
| 829 | * \sa CalculateIonForce | 
|---|
| 830 | * \sa UpdateIonsU | 
|---|
| 831 | * \warning U is not changed here, only used to move the ion. | 
|---|
| 832 | */ | 
|---|
| 833 | void UpdateIonsR(struct Problem *P) | 
|---|
| 834 | { | 
|---|
| 835 | struct Ions *I = &P->Ion; | 
|---|
| 836 | int is, ia, d; | 
|---|
| 837 | double *R, *R_old, *R_old_old, *FIon, *FIon_old, *U, *FIonL, *FIonNL, *FEwald; | 
|---|
| 838 | double IonMass, a; | 
|---|
| 839 | double sR[NDIM], sRold[NDIM], sRoldold[NDIM]; | 
|---|
| 840 | const int delta_t = P->R.delta_t; | 
|---|
| 841 | for (is=0; is < I->Max_Types; is++) { // go through all types ... | 
|---|
| 842 | IonMass = I->I[is].IonMass; | 
|---|
| 843 | if (IonMass < MYEPSILON) fprintf(stderr,"UpdateIonsR: IonMass = %lg",IonMass); | 
|---|
| 844 | a = delta_t*0.5/IonMass;            // F/m = a and thus: s = 0.5 * F/m * t^2 + v * t =: t * (F * a + v) | 
|---|
| 845 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { // .. and each ion of the type | 
|---|
| 846 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 847 | FIonL = &I->I[is].FIonL[NDIM*ia]; | 
|---|
| 848 | FIonNL = &I->I[is].FIonNL[NDIM*ia]; | 
|---|
| 849 | FEwald = &I->I[is].FEwald[NDIM*ia]; | 
|---|
| 850 | FIon_old = &I->I[is].FIon_old[NDIM*ia]; | 
|---|
| 851 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 852 | R = &I->I[is].R[NDIM*ia]; | 
|---|
| 853 | R_old = &I->I[is].R_old[NDIM*ia]; | 
|---|
| 854 | R_old_old = &I->I[is].R_old_old[NDIM*ia]; | 
|---|
| 855 | //if (I->I[is].IMT[ia] == MoveIon) { // even FixedIon moves, only not by other's forces | 
|---|
| 856 | for (d=0; d<NDIM; d++) { | 
|---|
| 857 | R_old_old[d] = R_old[d];                              // shift old values | 
|---|
| 858 | R_old[d] = R[d]; | 
|---|
| 859 | R[d] += delta_t*(U[d]+a*FIon[d]);                   // F = m * a and s = 0.5 * a * t^2 | 
|---|
| 860 | FIon_old[d] = FIon[d];                                        // store old force | 
|---|
| 861 | //                                FIon[d] = 0.;                                                                         // zero all as a sign that's been moved | 
|---|
| 862 | //                                FIonL[d] = 0.; | 
|---|
| 863 | //                                FIonNL[d] = 0.; | 
|---|
| 864 | //                                FEwald[d] = 0.; | 
|---|
| 865 | // don't reset forces here anymore, as we OutputVis() after this and before next CalculateForce() (rendering them null in the cute graphs) | 
|---|
| 866 | } | 
|---|
| 867 | if (I->I[is].Constraints[ia] != NULL) { // override current resulting R if constrained is given | 
|---|
| 868 | fprintf(stderr, "(%i) Using constrained coordinates R of step %d on ion (%i,%i)\n", P->Par.me, I->I[is].Constraints[ia]->step, is, ia); | 
|---|
| 869 | if ((I->I[is].Constraints[ia]->step != P->R.OuterStep) && (P->Par.me == 0)) | 
|---|
| 870 | fprintf(stderr, "(%i) WARNING: constraint step %d does not match Outerstep %d for ion (%d,%d)\n", P->Par.me, I->I[is].Constraints[ia]->step, P->R.OuterStep, is, ia); | 
|---|
| 871 | for (d=0; d<NDIM; d++) | 
|---|
| 872 | R[d] = I->I[is].Constraints[ia]->R[d]; | 
|---|
| 873 | I->I[is].IMT[ia] = I->I[is].Constraints[ia]->IMT; | 
|---|
| 874 | //RemoveConstraintItem(&I->I[is],ia); // and remove this first item from the list: // is done now  at UpdateIonsU() | 
|---|
| 875 | } | 
|---|
| 876 | RMat33Vec3(sR, P->Lat.InvBasis, R); | 
|---|
| 877 | RMat33Vec3(sRold, P->Lat.InvBasis, R_old); | 
|---|
| 878 | RMat33Vec3(sRoldold, P->Lat.InvBasis, R_old_old); | 
|---|
| 879 | for (d=0; d <NDIM; d++) { | 
|---|
| 880 | while (sR[d] < 0) { | 
|---|
| 881 | sR[d] += 1.0; | 
|---|
| 882 | sRold[d] += 1.0; | 
|---|
| 883 | sRoldold[d] += 1.0; | 
|---|
| 884 | } | 
|---|
| 885 | while (sR[d] >= 1.0) { | 
|---|
| 886 | sR[d] -= 1.0; | 
|---|
| 887 | sRold[d] -= 1.0; | 
|---|
| 888 | sRoldold[d] -= 1.0; | 
|---|
| 889 | } | 
|---|
| 890 | } | 
|---|
| 891 | RMat33Vec3(R, P->Lat.RealBasis, sR); | 
|---|
| 892 | RMat33Vec3(R_old, P->Lat.RealBasis, sRold); | 
|---|
| 893 | RMat33Vec3(R_old_old, P->Lat.RealBasis, sRoldold); | 
|---|
| 894 | //} | 
|---|
| 895 | } | 
|---|
| 896 | } | 
|---|
| 897 | } | 
|---|
| 898 |  | 
|---|
| 899 | /** Resets the forces array. | 
|---|
| 900 | * \param *P Problem at hand | 
|---|
| 901 | */ | 
|---|
| 902 | void ResetForces(struct Problem *P) | 
|---|
| 903 | { | 
|---|
| 904 | struct Ions *I = &P->Ion; | 
|---|
| 905 | double *FIon, *FIonL, *FIonNL, *FEwald; | 
|---|
| 906 | int is, ia, d; | 
|---|
| 907 | for (is=0; is < I->Max_Types; is++) { // go through all types ... | 
|---|
| 908 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { // .. and each ion of the type | 
|---|
| 909 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 910 | FIonL = &I->I[is].FIonL[NDIM*ia]; | 
|---|
| 911 | FIonNL = &I->I[is].FIonNL[NDIM*ia]; | 
|---|
| 912 | FEwald = &I->I[is].FEwald[NDIM*ia]; | 
|---|
| 913 | for (d=0; d<NDIM; d++) { | 
|---|
| 914 | FIon[d] = 0.;                   // zero all as a sign that's been moved | 
|---|
| 915 | FIonL[d] = 0.; | 
|---|
| 916 | FIonNL[d] = 0.; | 
|---|
| 917 | FEwald[d] = 0.; | 
|---|
| 918 | } | 
|---|
| 919 | } | 
|---|
| 920 | } | 
|---|
| 921 | }; | 
|---|
| 922 |  | 
|---|
| 923 | /** Changes ion's velocity according to acting force. | 
|---|
| 924 | * IonType::U is changed by the weighted force of actual step and last one | 
|---|
| 925 | * according to Newton. | 
|---|
| 926 | * \param *P Problem at hand | 
|---|
| 927 | * \sa UpdateIonsR | 
|---|
| 928 | * \sa CalculateIonForce | 
|---|
| 929 | * \warning R is not changed here. | 
|---|
| 930 | */ | 
|---|
| 931 | void UpdateIonsU(struct Problem *P) | 
|---|
| 932 | { | 
|---|
| 933 | struct Ions *I = &P->Ion; | 
|---|
| 934 | int is, ia, d; | 
|---|
| 935 | double *FIon, *FIon_old, *U; | 
|---|
| 936 | double IonMass, a; | 
|---|
| 937 | const int delta_t = P->R.delta_t; | 
|---|
| 938 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 939 | IonMass = I->I[is].IonMass; | 
|---|
| 940 | if (IonMass < MYEPSILON) fprintf(stderr,"UpdateIonsU: IonMass = %lg",IonMass); | 
|---|
| 941 | a = delta_t*0.5/IonMass;                            // (F+F_old)/2m = a and thus: v = (F+F_old)/2m * t = (F + F_old) * a | 
|---|
| 942 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 943 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 944 | if (I->I[is].Constraints[ia] != NULL) { // override current resulting R and U if constrained is given | 
|---|
| 945 | fprintf(stderr, "(%i) Setting constrained motion U at step %d on ion (%i,%i)\n", P->Par.me, I->I[is].Constraints[ia]->step, is, ia); | 
|---|
| 946 | if ((I->I[is].Constraints[ia]->step != P->R.OuterStep) && (P->Par.me == 0)) | 
|---|
| 947 | fprintf(stderr, "(%i) WARNING: constraint step %d does not match Outerstep %d for ion (%d,%d)\n", P->Par.me, I->I[is].Constraints[ia]->step, P->R.OuterStep, is, ia); | 
|---|
| 948 | for (d=0; d<NDIM; d++) | 
|---|
| 949 | U[d] = I->I[is].Constraints[ia]->U[d]; | 
|---|
| 950 | RemoveConstraintItem(&I->I[is],ia); // and remove this first item from the list | 
|---|
| 951 | } else { | 
|---|
| 952 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 953 | FIon_old = &I->I[is].FIon_old[NDIM*ia]; | 
|---|
| 954 | //if (I->I[is].IMT[ia] == MoveIon) | 
|---|
| 955 | for (d=0; d<NDIM; d++) { | 
|---|
| 956 | U[d] += a * (FIon[d]+FIon_old[d]); | 
|---|
| 957 | } | 
|---|
| 958 | } | 
|---|
| 959 | } | 
|---|
| 960 | } | 
|---|
| 961 | } | 
|---|
| 962 |  | 
|---|
| 963 | /** CG process to optimise structure. | 
|---|
| 964 | * \param *P Problem at hand | 
|---|
| 965 | */ | 
|---|
| 966 | void UpdateIons(struct Problem *P) | 
|---|
| 967 | { | 
|---|
| 968 | struct Ions *I = &P->Ion; | 
|---|
| 969 | int is, ia, d; | 
|---|
| 970 | double *R, *R_old, *R_old_old, *FIon, *S, *GammaA; | 
|---|
| 971 | double IonFac, GammaB; //, GammaT; | 
|---|
| 972 | double FNorm, StepNorm; | 
|---|
| 973 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 974 | IonFac = I->I[is].IonFac; | 
|---|
| 975 | GammaA = I->I[is].GammaA; | 
|---|
| 976 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 977 | FIon = &I->I[is].FIon[NDIM*ia]; | 
|---|
| 978 | S = &I->I[is].SearchDir[NDIM*ia]; | 
|---|
| 979 | GammaB = GammaA[ia]; | 
|---|
| 980 | GammaA[ia] = RSP3(FIon,S); | 
|---|
| 981 | FNorm = sqrt(RSP3(FIon,FIon)); | 
|---|
| 982 | StepNorm = log(1.+IonFac*FNorm); // Fix Hack | 
|---|
| 983 | if (FNorm != 0) | 
|---|
| 984 | StepNorm /= sqrt(RSP3(FIon,FIon)); | 
|---|
| 985 | else | 
|---|
| 986 | StepNorm = 0; | 
|---|
| 987 | //if (GammaB != 0.0) { | 
|---|
| 988 | //        GammaT = GammaA[ia]/GammaB; | 
|---|
| 989 | //        for (d=0; d>NDIM; d++) | 
|---|
| 990 | //          S[d] = FIon[d]+GammaT*S[d]; | 
|---|
| 991 | //      } else { | 
|---|
| 992 | for (d=0; d<NDIM; d++) | 
|---|
| 993 | S[d] = StepNorm*FIon[d]; | 
|---|
| 994 | //      } | 
|---|
| 995 | R = &I->I[is].R[NDIM*ia]; | 
|---|
| 996 | R_old = &I->I[is].R_old[NDIM*ia]; | 
|---|
| 997 | R_old_old = &I->I[is].R_old_old[NDIM*ia]; | 
|---|
| 998 | if (I->I[is].IMT[ia] == MoveIon) | 
|---|
| 999 | for (d=0; d<NDIM; d++) { | 
|---|
| 1000 | R_old_old[d] = R_old[d]; | 
|---|
| 1001 | R_old[d] = R[d]; | 
|---|
| 1002 | R[d] += S[d]; // FixHack*IonFac; | 
|---|
| 1003 | } | 
|---|
| 1004 | } | 
|---|
| 1005 | } | 
|---|
| 1006 | } | 
|---|
| 1007 |  | 
|---|
| 1008 | /** Print coordinates of all ions to stdout. | 
|---|
| 1009 | * \param *P Problem at hand | 
|---|
| 1010 | * \param actual (1 - don't at current RunStruct#OuterStep, 0 - do) | 
|---|
| 1011 | */ | 
|---|
| 1012 | void OutputIonCoordinates(struct Problem *P, int actual) | 
|---|
| 1013 | { | 
|---|
| 1014 | //struct RunStruct *R = &P->R; | 
|---|
| 1015 | struct Ions *I = &P->Ion; | 
|---|
| 1016 | char filename[MAXSTRINGSIZE]; | 
|---|
| 1017 | FILE *output; | 
|---|
| 1018 | int is, ia, nr = 0; | 
|---|
| 1019 | double Bohr = (I->IsAngstroem) ? 1./ANGSTROEMINBOHRRADIUS : 1.; | 
|---|
| 1020 | /*  if (P->Par.me == 0 && P->Call.out[ReadOut]) { | 
|---|
| 1021 | fprintf(stderr, "(%i) ======= Differential Ion Coordinates =========\n",P->Par.me); | 
|---|
| 1022 | for (is=0; is < I->Max_Types; is++) | 
|---|
| 1023 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) | 
|---|
| 1024 | //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]); | 
|---|
| 1025 | 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_old[NDIM*ia+0],I->I[is].R[NDIM*ia+1]-I->I[is].R_old[NDIM*ia+1],I->I[is].R[NDIM*ia+2]-I->I[is].R_old[NDIM*ia+2]); | 
|---|
| 1026 | fprintf(stderr, "(%i) =========================================\n",P->Par.me); | 
|---|
| 1027 | }*/ | 
|---|
| 1028 | if (actual) | 
|---|
| 1029 | sprintf(filename, "%s.MD", P->Call.MainParameterFile); | 
|---|
| 1030 | else | 
|---|
| 1031 | sprintf(filename, "%s.opt", P->Call.MainParameterFile); | 
|---|
| 1032 | if (((actual) && (P->R.OuterStep <= 0)) || ((!actual) && (P->R.StructOptStep == 1))) { // on first step write complete config file | 
|---|
| 1033 | WriteParameters(P, filename); | 
|---|
| 1034 | } else { // afterwards simply add the current ion coordinates as constrained steps | 
|---|
| 1035 | if ((P->Par.me == 0) && (output = fopen(filename,"a"))) { | 
|---|
| 1036 | fprintf(output,"# ====== MD step %d ========= \n", (actual) ? P->R.OuterStep : P->R.StructOptStep); | 
|---|
| 1037 | for (is=0; is < I->Max_Types; is++) | 
|---|
| 1038 | for (ia=0;ia<I->I[is].Max_IonsOfType;ia++) { | 
|---|
| 1039 | fprintf(output,"Ion_Type%i_%i\t%2.9f\t%2.9f\t%2.9f\t%i\t%2.9f\t%2.9f\t%2.9f\t# Number in molecule %i\n", is+1, ia+1, I->I[is].R[0+NDIM*ia]*Bohr, I->I[is].R[1+NDIM*ia]*Bohr, I->I[is].R[2+NDIM*ia]*Bohr, I->I[is].IMT[ia], I->I[is].U[0+NDIM*ia]*Bohr, I->I[is].U[1+NDIM*ia]*Bohr, I->I[is].U[2+NDIM*ia]*Bohr, ++nr); | 
|---|
| 1040 | } | 
|---|
| 1041 | fflush(output); | 
|---|
| 1042 | } | 
|---|
| 1043 | } | 
|---|
| 1044 | } | 
|---|
| 1045 |  | 
|---|
| 1046 | /** Calculates kinetic energy (Ions::EKin) of movable Ions. | 
|---|
| 1047 | * Does 0.5 / IonType::IonMass * IonTye::U^2 for each Ion, | 
|---|
| 1048 | * also retrieves actual temperatur by 2/3 from just | 
|---|
| 1049 | * calculated Ions::EKin. | 
|---|
| 1050 | * \param *P Problem at hand | 
|---|
| 1051 | */ | 
|---|
| 1052 | void CalculateEnergyIonsU(struct Problem *P) | 
|---|
| 1053 | { | 
|---|
| 1054 | struct Ions *I = &P->Ion; | 
|---|
| 1055 | int is, ia, d; | 
|---|
| 1056 | double *U; | 
|---|
| 1057 | double IonMass, a, ekin = 0; | 
|---|
| 1058 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 1059 | IonMass = I->I[is].IonMass; | 
|---|
| 1060 | a = 0.5*IonMass; | 
|---|
| 1061 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 1062 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 1063 | //if (I->I[is].IMT[ia] == MoveIon) // even FixedIon moves, only not by other's forces | 
|---|
| 1064 | for (d=0; d<NDIM; d++) { | 
|---|
| 1065 | ekin += a * U[d]*U[d]; | 
|---|
| 1066 | } | 
|---|
| 1067 | } | 
|---|
| 1068 | } | 
|---|
| 1069 | I->EKin = ekin; | 
|---|
| 1070 | I->ActualTemp = (2./(3.*I->Max_TotalIons)*I->EKin); | 
|---|
| 1071 | } | 
|---|
| 1072 |  | 
|---|
| 1073 | /**     Scales ion velocities to match temperature. | 
|---|
| 1074 | * In order to match Ions::ActualTemp with desired RunStruct::TargetTemp | 
|---|
| 1075 | * each velocity in each dimension (for all types, all ions) is scaled | 
|---|
| 1076 | * with the ratio of these two. Ions::EKin is recalculated. | 
|---|
| 1077 | * \param *P Problem at hand | 
|---|
| 1078 | */ | 
|---|
| 1079 | void ScaleTemp(struct Problem *P) | 
|---|
| 1080 | { | 
|---|
| 1081 | struct Ions *I = &P->Ion; | 
|---|
| 1082 | int is, ia, d; | 
|---|
| 1083 | double *U; | 
|---|
| 1084 | double IonMass, a, ekin = 0; | 
|---|
| 1085 | if (I->ActualTemp < MYEPSILON) fprintf(stderr,"ScaleTemp: I->ActualTemp = %lg",I->ActualTemp); | 
|---|
| 1086 | double ScaleTempFactor = sqrt(P->R.TargetTemp/I->ActualTemp); | 
|---|
| 1087 | for (is=0; is < I->Max_Types; is++) { | 
|---|
| 1088 | IonMass = I->I[is].IonMass; | 
|---|
| 1089 | a = 0.5*IonMass; | 
|---|
| 1090 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 1091 | U = &I->I[is].U[NDIM*ia]; | 
|---|
| 1092 | //if (I->I[is].IMT[ia] == MoveIon) // even FixedIon moves, only not by other's forces | 
|---|
| 1093 | for (d=0; d<NDIM; d++) { | 
|---|
| 1094 | U[d] *= ScaleTempFactor; | 
|---|
| 1095 | ekin += a * U[d]*U[d]; | 
|---|
| 1096 | } | 
|---|
| 1097 | } | 
|---|
| 1098 | } | 
|---|
| 1099 | I->EKin = ekin; | 
|---|
| 1100 | I->ActualTemp = (2./(3.*I->Max_TotalIons)*I->EKin); | 
|---|
| 1101 | } | 
|---|
| 1102 |  | 
|---|
| 1103 | /** Calculates mean force vector as stop criteria in structure optimization. | 
|---|
| 1104 | * Calculates a mean force vector per ion as the usual euclidian norm over total | 
|---|
| 1105 | * number of ions and dimensions, being the sum of each ion force (for all type, | 
|---|
| 1106 | * all ions, all dims) squared. | 
|---|
| 1107 | * The mean force is archived in RunStruct::MeanForce and printed to screen. | 
|---|
| 1108 | * \param *P Problem at hand | 
|---|
| 1109 | */ | 
|---|
| 1110 | void GetOuterStop(struct Problem *P) | 
|---|
| 1111 | { | 
|---|
| 1112 | struct RunStruct *R = &P->R; | 
|---|
| 1113 | struct Ions *I = &P->Ion; | 
|---|
| 1114 | int is, ia, IonNo=0, i, d; | 
|---|
| 1115 | double MeanForce = 0.0; | 
|---|
| 1116 | for (is=0; is < I->Max_Types; is++) | 
|---|
| 1117 | for (ia=0; ia < I->I[is].Max_IonsOfType; ia++) { | 
|---|
| 1118 | IonNo++; | 
|---|
| 1119 | for (d=0; d <NDIM; d++) | 
|---|
| 1120 | MeanForce += I->I[is].FIon[d+NDIM*ia]*I->I[is].FIon[d+NDIM*ia]; | 
|---|
| 1121 | } | 
|---|
| 1122 | for (i=MAXOLD-1; i > 0; i--) | 
|---|
| 1123 | R->MeanForce[i] = R->MeanForce[i-1]; | 
|---|
| 1124 | MeanForce = sqrt(MeanForce/(IonNo*NDIM)); | 
|---|
| 1125 | R->MeanForce[0] = MeanForce; | 
|---|
| 1126 | if (P->Call.out[LeaderOut] && (P->Par.me == 0)) | 
|---|
| 1127 | fprintf(stderr,"MeanForce = %e\n", R->MeanForce[0]); | 
|---|
| 1128 | } | 
|---|
| 1129 |  | 
|---|
| 1130 |  | 
|---|