/********************************************/ /* Program To Fit Finnis-Sinclair Potential */ /* */ /* V2.0 May 28 2000 Ju Li (MIT) */ /********************************************/ #include "z.h" double potential_energy (Structure *S, double param[MAX_OP]) { int i,j,k,l,nn[MAX_ATOM],ni[MAX_ATOM][MAX_FIRST],swapped; double *ds, *dx, RCUT, AA, BB, CC, DD, ff, pote, *DS, *DX, *DX_NEXT, H[3][3], K, U, W, ALPHA_ZrC, BETA_ZrC, ALPHA_CZr, BETA_CZr, A[MAX_TYPE][MAX_TYPE], B[MAX_TYPE][MAX_TYPE], LAMBDA, C[MAX_TYPE][MAX_TYPE], D[MAX_TYPE][MAX_TYPE], sc, cc, cz, ss, tt, m[4], xx[3], wk[3], wx[3], RC[MAX_TYPE][MAX_TYPE], h, neigh[MAX_ATOM][MAX_FIRST*4], GAMMA; A[0][0] = 2.9296875; B[0][0] = 2.58787395638939; C[0][0] = 1.32308467741935; D[0][0] = 4.3672464262563; RC[0][0] = 7.0; K = 0.1; RC[0][1] = RC[1][0] = W = 3.5; U = 0.1; RC[1][1] = 0.; i = 0; A[0][1] = A[1][0] = param[i++]; B[0][1] = B[1][0] = param[i++]; C[0][1] = C[1][0] = param[i++]; D[0][1] = D[1][0] = param[i++]; LAMBDA = 0; ALPHA_ZrC = ALPHA_CZr = param[i++]; BETA_ZrC = BETA_CZr = param[i++]; GAMMA = 2.; IZERO (S->n, nn); M3MULTIPLY (S->a, S->H, H); for (DS=S->ds,DX=S->dx,i=0; in; i++) for (j=i; jn; j++,DS+=3*MAX_IMAGE,DX=DX_NEXT) { DX_NEXT = DX + 4*MAX_IMAGE; RCUT = RC[S->t[i]][S->t[j]]; swapped = (S->t[i] == C_ATOM) && (S->t[j] == Zr_ATOM); for (ds=DS,dx=DX; dx= RCUT) break; if (S->t[i] == S->t[j]) continue; if (dx[3] >= W) continue; if ((nn[i]==MAX_FIRST) || (nn[j]==MAX_FIRST)) pe("potential_energy: MAX_FIRST=%d reached.\n",MAX_FIRST); V3DIV ( dx, dx[3], &(neigh[i][4*nn[i]]) ); neigh[i][4*nn[i]+3] = dx[3]; ni[i][nn[i]++] = j; V3DIV ( dx, -dx[3], &(neigh[j][4*nn[j]]) ); neigh[j][4*nn[j]+3] = dx[3]; ni[j][nn[j]++] = i; if (swapped) V3NEG(dx,dx); } } pote = 0; VZERO (S->n, S->X); for (DX=S->dx,i=0; in; i++) for (j=i; jn; j++,DX=DX_NEXT) { DX_NEXT = DX + 4*MAX_IMAGE; RCUT = RC[S->t[i]][S->t[j]]; swapped = (S->t[i] == C_ATOM) && (S->t[j] == Zr_ATOM); if (swapped) SWAP(i,j,k); AA = A[S->t[i]][S->t[j]]; BB = B[S->t[i]][S->t[j]]; CC = C[S->t[i]][S->t[j]]; DD = D[S->t[i]][S->t[j]]; for (dx=DX; dx= RCUT) break; if ( S->t[i] == S->t[j] ) if ( S->t[i] == Zr_ATOM ) { pote += 2 * exp( AA * (BB - dx[3]) + K / (dx[3] - RCUT) ); cc = exp( CC * (DD - dx[3]) + K / (dx[3] - RCUT) ); S->X[i] += cc; S->X[j] += cc; } else {} else { if (dx[3] >= W) continue; pote += 2 * exp( AA * (BB - dx[3]) + U / (dx[3] - W) ); for (sc=k=0; k 2-TINY)&&(neigh[i][4*k+3]==dx[3])) continue; sc += pow ( tt / ALPHA_ZrC, BETA_ZrC ) * exp ( GAMMA * ( U / (neigh[i][4*k+3] - W) - CC * neigh[i][4*k+3] ) ); } for (k=0; k 2-TINY)&&(neigh[j][4*k+3]==dx[3])) continue; sc += pow ( tt / ALPHA_CZr, BETA_CZr ) * exp ( GAMMA * ( U / (neigh[j][4*k+3] - W) - CC * neigh[j][4*k+3] ) ); } sc = pow ( sc , 1. / GAMMA ) / exp( U / (dx[3] - W) - CC * dx[3] ); h = exp( CC * (DD - dx[3]) + U / (dx[3] - W) - sc ); S->X[i] += h * h; S->X[j] += h * h; pote -= LAMBDA * h; } } if (swapped) SWAP(i,j,k); } for (i=0; in; i++) pote -= (S->X[i]=sqrt(S->X[i])); if (!S->calculate_force) return (pote); VZERO (3*S->n, S->f); for (DX=S->dx,i=0; in; i++) for (j=i; jn; j++,DX=DX_NEXT) { DX_NEXT = DX + 4*MAX_IMAGE; RCUT = RC[S->t[i]][S->t[j]]; swapped = (S->t[i] == C_ATOM) && (S->t[j] == Zr_ATOM); if (swapped) SWAP(i,j,k); AA = A[S->t[i]][S->t[j]]; BB = B[S->t[i]][S->t[j]]; CC = C[S->t[i]][S->t[j]]; DD = D[S->t[i]][S->t[j]]; for (dx=DX; dx= RCUT) break; if ( S->t[i] == S->t[j] ) if ( S->t[i] == Zr_ATOM ) { ff = ( 2 * ( AA + K / (dx[3] - RCUT) / (dx[3] - RCUT) ) * exp( AA * (BB - dx[3]) + K / (dx[3] - RCUT) ) - ( CC + K / (dx[3] - RCUT) / (dx[3] - RCUT) ) * exp( CC * (DD - dx[3]) + K / (dx[3] - RCUT) ) * ( 0.5 / S->X[i] + 0.5 / S->X[j] ) ) / dx[3]; V3ADDmuL (ff, dx, &(S->f[3*j])); V3SUBmuL (&S->f[3*i], ff, dx); } else {} else { if (dx[3] >= W) continue; for (sc=k=0; k 2-TINY)&&(neigh[i][4*k+3]==dx[3])) continue; sc += pow ( tt / ALPHA_ZrC, BETA_ZrC ) * exp ( GAMMA * ( U / (neigh[i][4*k+3] - W) - CC * neigh[i][4*k+3] ) ); } for (k=0; k 2-TINY)&&(neigh[j][4*k+3]==dx[3])) continue; sc += pow ( tt / ALPHA_CZr, BETA_CZr ) * exp ( GAMMA * ( U / (neigh[j][4*k+3] - W) - CC * neigh[j][4*k+3] ) ); } sc = pow ( sc , 1. / GAMMA ) / exp( U / (dx[3] - W) - CC * dx[3] ); h = exp( CC * (DD - dx[3]) + U / (dx[3] - W) - sc ); cc = h * h / S->X[i] + h * h / S->X[j] + LAMBDA * h; ff = ( 2 * ( AA + U / (dx[3] - W) / (dx[3] - W) ) * exp( AA * (BB - dx[3]) + U / (dx[3] - W) ) - ( CC + U / (dx[3] - W) / (dx[3] - W) ) * cc * ( 1 + sc ) ) / dx[3]; V3ADDmuL (ff, dx, &(S->f[3*j])); V3SUBmuL (&S->f[3*i], ff, dx); if (sc < TINY) continue; V3DIV ( dx, dx[3], xx ); for (k=0; k 2-TINY)&&(neigh[i][4*k+3]==dx[3])) continue; ss = cc / pow(sc, GAMMA-1) / GAMMA * pow ( tt / ALPHA_ZrC, BETA_ZrC ) * exp ( GAMMA * ( U / (neigh[i][4*k+3] - W) - CC * neigh[i][4*k+3] - U / (dx[3] - W) + CC * dx[3] ) ); ff = ss * GAMMA * ( CC + U / (neigh[i][4*k+3] - W) / (neigh[i][4*k+3] - W) ); V3ADDmuL (ff, &(neigh[i][4*k]), &(S->f[3*ni[i][k]]) ); V3SUBmuL (&S->f[3*i], ff, &(neigh[i][4*k])); ss *= BETA_ZrC / tt; V3CROSS ( xx, &(neigh[i][4*k]), m ); V3CROSS ( m, &(neigh[i][4*k]), wk ); V3CROSS ( xx, m, wx ); tt = ss / neigh[i][4*k+3]; V3ADDmuL (tt, wk, &(S->f[3*ni[i][k]]) ); V3SUBmuL (&S->f[3*i], tt, wk); tt = ss / dx[3]; V3ADDmuL (tt, wx, &(S->f[3*j]) ); V3SUBmuL (&S->f[3*i], tt, wx); } for (k=0; k 2-TINY)&&(neigh[j][4*k+3]==dx[3])) continue; ss = cc / pow(sc, GAMMA-1) / GAMMA * pow ( tt / ALPHA_CZr, BETA_CZr ) * exp ( GAMMA * ( U / (neigh[j][4*k+3] - W) - CC * neigh[j][4*k+3] - U / (dx[3] - W) + CC * dx[3] ) ); ff = ss * GAMMA * ( CC + U / (neigh[j][4*k+3] - W) / (neigh[j][4*k+3] - W) ); V3ADDmuL (ff, &(neigh[j][4*k]), &(S->f[3*ni[j][k]]) ); V3SUBmuL (&(S->f[3*j]), ff, &(neigh[j][4*k])); ss *= BETA_CZr / tt; V3CROSS ( &(neigh[j][4*k]), xx, m ); V3CROSS ( m, &(neigh[j][4*k]), wk ); V3CROSS ( m, xx, wx ); tt = ss / neigh[j][4*k+3]; V3ADDmuL (tt, wk, &(S->f[3*ni[j][k]]) ); V3SUBmuL (&(S->f[3*j]), tt, wk); tt = ss / dx[3]; V3ADDmuL (tt, wx, &(S->f[3*i]) ); V3SUBmuL (&(S->f[3*j]), tt, wx); } } } if (swapped) SWAP(i,j,k); } return (pote); } /* end potential_energy() */ static double this_pote (double lattice_constant) { this_structure->a = lattice_constant; return (potential_energy(this_structure, param)); } /* end this_pote() */ #define error_inc(x,target,weight) \ ((weight)*pow(fabs(rerr(x,target)),exponent)) /* the error function */ double fe (double guess[MAX_OP]) { int i, j; double a, b, c, pote, error, B; memcpy (param, guess, MAX_OP*sizeof(double)); error = 0.; for (i=0; ipote = pote; this_structure->a = a; error += error_inc(a, xtal_target[i][XTAL_EQ_A], xtal_weight[i][XTAL_EQ_A]); if (i == NaCl) { c44 = C44_0 (this_structure); bulk_modulus = Bulk_Modulus (this_structure); c = C11_C12 (this_structure); c11 = (3*bulk_modulus + 2*c) / 3; c12 = c11 - c; error += error_inc(bulk_modulus, bulk_modulus_target, bulk_modulus_weight) + error_inc(c11,c11_target,c11_weight) + error_inc(c12,c12_target,c12_weight) + error_inc(c44,c44_target,c44_weight); error += error_inc( -pote, NaCl_cohesive_energy_target, xtal_weight[NaCl][XTAL_EQ_POTE] ); } else error += error_inc( my[i].pote - my[i-1].pote, xtal_target[i][XTAL_EQ_POTE] - xtal_target[i-1][XTAL_EQ_POTE], xtal_weight[i][XTAL_EQ_POTE] ); } my[ZrVAC].a = my[NaCl].a; my[ZrVAC].pote = potential_energy (&my[ZrVAC], param); my[CVAC].a = my[NaCl].a; my[CVAC].pote = potential_energy (&my[CVAC], param); schottky_energy = my[ZrVAC].pote + my[CVAC].pote - (my[ZrVAC].n + my[CVAC].n) * my[NaCl].pote / my[NaCl].n; error += error_inc( schottky_energy, schottky_energy_target, schottky_energy_weight ); /* pure Zr */ this_structure = &my[PureZr]; this_structure->pote = onemin (this_pote, 1, 10, EPS, &a); this_structure->a = a; error += error_inc( CUBE(my[PureZr].a) * my[PureZr].volume / my[PureZr].n, PureZr_atomic_volume_target, PureZr_atomic_volume_weight ); B = Bulk_Modulus (this_structure); error += error_inc( B, PureZr_bulk_modulus_target, PureZr_bulk_modulus_weight ); error += error_inc( -this_structure->pote / this_structure->n, PureZr_cohesive_energy_target, PureZr_cohesive_energy_weight ); /* pure C */ /* this_structure = &my[PureC]; */ /* this_structure->pote = onemin (this_pote, 1, 6, EPS, &a); */ /* this_structure->a = a; */ /* error += error_inc( CUBE(my[PureC].a)/4, PureC_atomic_volume_target, */ /* PureC_atomic_volume_weight ); */ /* B = Bulk_Modulus (this_structure); */ /* error += error_inc( B, PureC_bulk_modulus_target, */ /* PureC_bulk_modulus_weight ); */ /* error += error_inc( -this_structure->pote, PureC_cohesive_energy_target, */ /* PureC_cohesive_energy_weight ); */ my[PureC].n = 1; my[PureC].pote = -7.43; /* ZrC heat of formation */ error += error_inc ( my[PureZr].pote / my[PureZr].n + my[PureC].pote / my[PureC].n - my[NaCl].pote, heat_of_formation_target, heat_of_formation_weight ); /* ZrC atomic force constants */ my[ZrC_CDIS].a = my[NaCl].a; potential_energy (&my[ZrC_CDIS], param); for (i=0; iH, S->HI, S->volume); M3rows_to_cover_sphere (S->H, cbrt(MAX_IMAGE*S->volume*3./4/PI), maxnc); V3aDd (maxnc, 4); m = total_replica(maxnc) * S->n; MALLOC ( construct_neighbor_list, ds, 3*m, double ); MALLOC ( construct_neighbor_list, dr2, m, double ); MALLOC ( construct_neighbor_list, idx, m, int ); S->mass = 0; for (i=0; in; i++) S->mass += ATOM_MASS_IN_G(Z[S->t[i]]); for (DS=S->ds,i=0; in; i++) for (j=i; jn; j++) { for (m=0,nc[0]=-maxnc[0]; nc[0]<=maxnc[0]; nc[0]++) for (nc[1]=-maxnc[1]; nc[1]<=maxnc[1]; nc[1]++) for (nc[2]=-maxnc[2]; nc[2]<=maxnc[2]; nc[2]++) { if (i==j) if (nc[0] < 0) continue; else if (nc[0] == 0) if (nc[1] < 0) continue; else if (nc[1] == 0) if (nc[2] <= 0) continue; V3ADDSUB (nc, &S->s[3*j], &S->s[3*i], &ds[3*m]); V3mM3 (&ds[3*m], S->H, dx); dr2[m] = V3LENGTH2 (dx); m++; } qsort_numerical_recipes ( m, dr2, idx, USE_NEW_IDX ); if (m < MAX_IMAGE) { for (n=0; n MAX_ATOM) pe ("Structure %d exceeds MAX_ATOM = %d\n", i, MAX_ATOM); MALLOC (main, my[i].t, my[i].n, int); MALLOC (main, my[i].s, 3*my[i].n, double); MALLOC (main, my[i].ds, 3*my[i].n*(my[i].n+1)/2*MAX_IMAGE, double); MALLOC (main, my[i].dx, 4*my[i].n*(my[i].n+1)/2*MAX_IMAGE, double); MALLOC (main, my[i].X, my[i].n, double); MALLOC (main, my[i].f, 3*my[i].n, double); } my[i=NaCl].name = "NaCl"; M3ASSIGN ( 0,.5,.5, .5,0,.5, .5,.5,0, my[i].H ); my[i].t[j=0] = Zr_ATOM; V3ZERO ( &my[i].s[3*j] ); my[i].t[++j] = C_ATOM; V3ASSIGN ( -.5,.5,.5, &my[i].s[3*j] ); my[i=ZnS].name = "ZnS"; M3ASSIGN ( 0,.5,.5, .5,0,.5, .5,.5,0, my[i].H ); my[i].t[j=0] = Zr_ATOM; V3ZERO ( &my[i].s[3*j] ); my[i].t[++j] = C_ATOM; V3ASSIGN ( .25,.25,.25, &my[i].s[3*j] ); my[i=CsCl].name = "CsCl"; M3IDENTITY ( my[i].H ); my[i].t[j=0] = Zr_ATOM; V3ZERO ( &my[i].s[3*j] ); my[i].t[++j] = C_ATOM; V3ASSIGN ( .5,.5,.5, &my[i].s[3*j] ); my[i=ZrVAC].name = "ZrVAC"; M3IDENTITY ( my[i].H ); my[i].t[j=0] = Zr_ATOM; V3ASSIGN ( .5,.5,0, &my[i].s[3*j] ); my[i].t[++j] = Zr_ATOM; V3ASSIGN ( 0,.5,.5, &my[i].s[3*j] ); my[i].t[++j] = Zr_ATOM; V3ASSIGN ( .5,0,.5, &my[i].s[3*j] ); my[i].t[++j] = C_ATOM; V3ASSIGN ( .5,0,0, &my[i].s[3*j] ); my[i].t[++j] = C_ATOM; V3ASSIGN ( 1,.5,0, &my[i].s[3*j] ); my[i].t[++j] = C_ATOM; V3ASSIGN ( .5,.5,.5, &my[i].s[3*j] ); my[i].t[++j] = C_ATOM; V3ASSIGN ( 1,0,.5, &my[i].s[3*j] ); my[i=CVAC].name = "CVAC"; M3EQV (my[ZrVAC].H, my[i].H); for (j=0; j MAX_CATEGORY) pe("number of categories (%d) > MAX_CATEGORY (%d)\n", n_category, MAX_CATEGORY); for (n_op=i=0; i MAX_OP) pe("number of parameters > MAX_OP (%d)\n", MAX_OP); for (j=0; j 0) { just_print_it = 0; signal (SIGINT, wrap_up); ndiv = 100; kb = 0; FORTRAN_SYMBOL(minaf77) (fe, &n_op, &ndiv, &del, bound[0], bound[1], guess, param); } else memcpy (param, guess, MAX_OP*sizeof(double)); wrap_up (SIG_SUCCESS); return (0); } /* end main() */