4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
12 * Copyright (c) 1991-2001
13 * BIOSON Research Institute, Dept. of Biophysical Chemistry
14 * University of Groningen, The Netherlands
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * Do check out http://www.gromacs.org , or mail us at gromacs@gromacs.org .
34 * Gromacs Runs On Most of All Computer Systems
36 static char *SRCID_ionize_c = "$Id$";
53 #define PREFIX "IONIZE: "
55 enum { eionCYL, eionSURF, eionGAUSS, eionNR };
57 enum { ecollPHOTO, ecollINELASTIC, ecollNR };
61 real fj,sigPh,sigIn,vAuger;
65 int nelec,maxelec,elec0,elmin_type;
68 /* BEGIN GLOBAL VARIABLES */
69 static int Energies[] = { 6, 8, 10, 12, 15, 20 };
70 static int ionize_seed = 1993;
71 #define NENER asize(Energies)
73 static t_electron_db edb;
75 /* END GLOBAL VARIABLES */
77 void dump_ca(FILE *fp,t_cross_atom *ca,int i,char *file,int line)
79 fprintf(fp,PREFIX"(line %d) atom %d, z = %d, n = %d, k = %d\n",
80 line,i,ca->z,ca->n,ca->k);
83 t_cross_atom *mk_cross_atom(FILE *log,t_mdatoms *md,
84 char **atomname[],int Eindex)
86 int elem_index[] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 5, 6 };
92 fprintf(log,PREFIX"Filling data structure for ionization\n");
93 fprintf(log,PREFIX"Warning: all fj values set to 0.95 for now\n");
95 snew(elemcnt,NELEM+1);
96 for(i=0; (i<md->nr); i++) {
100 for(j=0; (j<NELEM); j++)
101 if (strncmp(cc,element[j].name,strlen(element[j].name)) == 0) {
102 ca[i].z = element[j].nel;
106 fatal_error(0,PREFIX"Don't know number of electrons for %s",
110 ca[i].sigPh = element[elem_index[ca[i].z]].cross[Eindex].photo;
111 ca[i].sigIn = element[elem_index[ca[i].z]].cross[Eindex].incoh;
112 ca[i].fj = recoil[ca[i].z].Prob_K;
115 ca[i].vAuger = 0.904;
118 ca[i].vAuger = 0.920;
121 ca[i].vAuger = 0.929;
132 fprintf(log,PREFIX"You have the following elements in your system (%d atoms):\n"PREFIX,md->nr);
133 for(j=0; (j<NELEM); j++)
135 fprintf(log," %s: %d",element[j].name,elemcnt[j]);
136 fprintf(log," atoms\n");
143 int number_K(t_cross_atom *ca)
151 int number_L(t_cross_atom *ca)
153 return ca->k-2+ca->z-ca->n;
156 real xray_cross_section(int eColl,t_cross_atom *ca)
170 c = (nK*0.5*ca->fj + nL/(ca->z-2)*(1-ca->fj))*ca->sigPh;
173 c = (ca->z-ca->n)*ca->sigIn/ca->z;
176 fatal_error(0,"No such collision type %d\n",eColl);
181 real prob_K(int eColl,t_cross_atom *ca)
185 if ((ca->z <= 2) || (ca->z == ca->n))
190 Pl = (ca->k-2+ca->z-ca->n)*(1-ca->fj)/(ca->z-2);
191 Pk = (2-ca->k)*ca->fj*0.5;
195 P = (2-ca->k)/(ca->z-ca->n);
198 fatal_error(0,"No such collision type %d\n",eColl);
203 double myexp(double x)
211 real ptheta_incoh(int Eindex,real theta)
212 /* theta should be in degrees */
214 /* These numbers generated by fitting 5 gaussians to the real function
215 * that describes the probability for theta.
216 * We use symmetry in the gaussian (see 180-angle) therefore there
217 * are fewer parameters (only 8 per energylevel).
219 static double ppp[NENER][8] = {
220 { -0.00295169, 10.4847, 0.0341099, /*-*/43.1963,
221 -0.0164054, 30.2452, 71.0311, 2.50282 },
222 { -0.00370852, 9.02037, 0.100559, /*-*/42.9962,
223 -0.0537891, 35.5077, 71.4305, 1.05515 },
224 { -0.00427039, 7.86831, 0.118042, /*-*/45.9846,
225 -0.0634505, 38.6134, 70.3857, 0.240082 },
226 { -0.004514, 7.0728, 0.13464, /*-*/48.213,
227 -0.0723, 41.06, 69.38, -0.02 },
228 { -0.00488796, 5.87988, 0.159574, /*-*/51.5556,
229 -0.0855767, 44.7307, 69.0251, -0.414604 },
230 { -0.00504604, 4.56299, 0.201064, /*-*/54.8599,
231 -0.107153, 48.7016, 68.8212, -0.487699 }
233 double g1,g2,g3,g4,g5,ptheta;
235 g1 = myexp(-0.5*sqr((theta-ppp[Eindex][7])/ppp[Eindex][1]));
236 g2 = myexp(-0.5*sqr((theta-180+ppp[Eindex][7])/ppp[Eindex][1]));
237 g3 = myexp(-0.5*sqr((theta-90)/ppp[Eindex][3]));
238 g4 = myexp(-0.5*sqr((theta-ppp[Eindex][6])/ppp[Eindex][5]));
239 g5 = myexp(-0.5*sqr((theta-180+ppp[Eindex][6])/ppp[Eindex][5]));
241 ptheta = ppp[Eindex][0]*(g1+g2) + ppp[Eindex][2]*g3 + ppp[Eindex][4]*(g4+g5);
246 real rand_theta_incoh(int Eindex,int *seed)
250 static bool bFirst = TRUE;
252 static int i,j,cur=1;
253 real theta,sum,rrr,dx;
256 dx = 90.0/(real)NINTP;
258 /* Compute cumulative integrals of all probability distributions */
260 for(i=0; (i<NENER); i++) {
261 snew(intp[i],NINTP+1);
262 y[prev] = ptheta_incoh(i,0.0);
264 for(j=1; (j<=NINTP); j++) {
265 y[cur] = ptheta_incoh(i,j*dx);
267 intp[i][j] = intp[i][j-1] + (y[cur]+y[prev])*dx;
272 fprintf(debug,"Integrated probability functions for theta incoherent\n");
273 for(j=0; (j<NINTP); j++) {
274 fprintf(debug,"%10f",dx*j);
275 for(i=0; (i<NENER); i++)
276 fprintf(debug," %10f",intp[i][j]);
284 for(j=0; (j<NINTP) && (rrr > intp[Eindex][j]); j++)
287 return (j-1+(rrr-intp[Eindex][j-1])/(intp[Eindex][j]-intp[Eindex][j-1]))*dx;
290 static void polar2cart(real phi,real theta,rvec v)
292 v[XX] = cos(phi)*sin(theta);
293 v[YY] = sin(phi)*sin(theta);
297 void rand_vector(rvec v,int *seed)
301 theta = 180.0*rando(seed);
302 phi = 360.0*rando(seed);
303 polar2cart(phi,theta,v);
306 real electron_cross_section(FILE *fp,rvec v,real mass,int nelec)
308 /* Compute cross section for electrons */
309 real T,B,U,S,Q,R,N,t,u,lnt,sigma;
310 real a0 = 0.05292; /* nm */
312 /* Have to determine T (kinetic energy of electron) */
313 T = 0.5*mass*iprod(v,v);
315 /* R is the binding energy of the electron in hydrogen */
316 R = 13.61*ELECTRONVOLT;
318 /* Have to determine the binding energy B, differs per orbital of course */
321 /* Have to determine the orbital kinetic energy U */
324 /* Have to know number of electrons */
327 /* Magic constant Q */
330 /* Some help variables */
333 S = 4*M_PI*sqr(a0)*N*sqr(R/B);
336 /* Resulting variable */
337 sigma = (S/(t+u+1))*( 0.5*Q*lnt*(1-1/sqr(t)) + (2-Q)*(1-1/t-lnt/(t+1)) );
342 static bool analyze_electrons(FILE *fp,t_electron_db *edb,
343 int natom,char **atomname[])
348 cc = getenv("GENERATE_ELECTRONS");
349 if (sscanf(cc,"%d",&etp) == 1) {
350 for(i=0; (i<natom); i++) {
351 if (strcmp(*atomname[i],"EL") == 0)
356 edb->maxelec = natom-i;
357 edb->elmin_type = etp;
358 fprintf(fp,PREFIX"There are %d possible electrons\n",edb->maxelec);
363 fprintf(fp,PREFIX"No electron features today.\n");
368 void add_electron(FILE *fp,t_mdatoms *md,t_electron_db *edb,int ion,
369 rvec x[],rvec v[],rvec dv,real dt)
374 if (edb->nelec < edb->maxelec) {
375 ee = edb->elec0+edb->nelec++;
376 md->chargeA[ee] = md->chargeB[ee] = md->chargeT[ee] = -1;
377 md->typeA[ee] = md->typeB[ee] = edb->elmin_type;
380 svmul(-md->massA[ion]*md->invmass[ee],dv,v[ee]);
381 /* Do a first step to prevent the electron from being on top of the
382 * nucleus, move it 0.05 nm from the nucleus
384 nv = 1.0/norm(v[ee]);
385 for(m=0; (m<DIM); m++)
386 x[ee][m] = x[ion][m] + v[ee][m]*nv*0.05;
389 fatal_error(0,PREFIX"No more particles to turn into electrons\n");
392 bool khole_decay(FILE *fp,t_cross_atom *ca,rvec x[],rvec v[],int ion,
393 int *seed,real dt,bool bElectron,
394 t_mdatoms *md,t_electron_db *edb)
400 if ((ca->vAuger < 0) || (recoil[ca->z].tau == 0)) {
401 dump_ca(stderr,ca,ion,__FILE__,__LINE__);
404 if (rando(seed) < dt/recoil[ca->z].tau) {
406 fprintf(debug,"DECAY: Going to decay a k hole\n");
409 /* Generate random vector */
410 rand_vector(dv,seed);
414 fprintf(debug,"DECAY: factor=%10g, dv = (%8.3f, %8.3f, %8.3f)\n",
415 factor,dv[XX],dv[YY],dv[ZZ]);
419 /* Now put the electron in place */
421 add_electron(fp,md,edb,ion,x,v,dv,dt);
429 real electron_atom_interactions(FILE *fp,t_mdatoms *md,t_inputrec *ir,
431 rvec x[],rvec v[],rvec f[],matrix box)
433 /* Compute what the name says... */
436 real mindist2,vc,vtot,fscal,fc,dx2,dx_1,qi,*q;
438 mindist2 = sqr(0.05);
444 if (ir->ePBC != epbcNONE)
446 /* the end variable usually includes electrons */
447 e1 = min(end,edb.elec0);
448 for(i=start; (i<e1); i++) {
449 elec1 = edb.elec0 + edb.nelec;
450 qi = q[i]*ONE_4PI_EPS0;
451 for(j=edb.elec0; (j<elec1); j++) {
452 if (ir->ePBC == epbcNONE)
453 rvec_sub(x[i],x[j],dx);
455 pbc_dx(x[i],x[j],dx);
457 if (dx2 < mindist2) {
458 /* Model collision */
461 /* Do normal coulomb */
465 fscal = vc*dx_1*dx_1;
466 for(m=0; (m<DIM); m++) {
478 void ionize(FILE *fp,t_mdatoms *md,char **atomname[],real t,t_inputrec *ir,
479 rvec x[],rvec v[],int start,int end,matrix box,t_commrec *cr)
481 static FILE *xvg,*ion;
482 static char *leg[] = { "Probability", "Primary Ionization", "Integral over PI", "KHole-Decay", "Integral over KD" };
483 static bool bFirst = TRUE,bElectron = FALSE;
484 static real t0,imax,width,inv_nratoms,rho,nphot;
485 static real interval;
486 static int dq_tot,nkd_tot,ephot,mode;
487 static t_cross_atom *ca;
488 static int Eindex=-1;
490 real r,factor,ndv,E_lost=0,cross_atom,dvz,rrc;
491 real pt,ptot,pphot,pcoll[ecollNR],tmax;
492 real incoh,incoh_abs,sigmaPincoh,hboxx,hboxy,rho2;
494 bool bIonize=FALSE,bKHole,bL,bDOIT;
496 int i,j,k,kk,m,nK,nL,dq,nkh,nkdecay,elmin_type;
497 int *nionize,*nkhole,*ndecay,nbuf[2];
500 /* Get parameters for gaussian photon pulse from inputrec */
501 t0 = ir->userreal1; /* Peak of the gaussian pulse */
502 nphot = ir->userreal2; /* Intensity */
503 width = ir->userreal3; /* Width of the peak (in time) */
504 rho = ir->userreal4; /* Diameter of the focal spot (nm) */
505 ionize_seed = ir->userint1; /* Random seed for stochastic ionization */
506 ephot = ir->userint2; /* Energy of the photons */
507 mode = ir->userint3; /* Mode of ionizing */
508 interval = 0.001*ir->userint4; /* Interval between pulses (ps) */
510 if ((width <= 0) || (nphot <= 0))
511 fatal_error(0,"Your parameters for ionization are not set properly\n"
512 "width (userreal3) = %f, nphot (userreal2) = %f",
515 if ((mode < 0) || (mode >= eionNR))
516 fatal_error(0,"Ionization mode (userint3)"
517 " should be in the range 0 .. %d",eionNR-1);
521 imax = (nphot/(M_PI*sqr(rho/2)))*1e-10*1.0/(width*sqrt(2.0*M_PI));
524 imax = (nphot/(M_PI*sqr(rho/2)))*1e-10*1.0/(width*sqrt(2.0*M_PI));
527 if (ionize_seed == 0)
528 ionize_seed = make_seed();
530 for(i=0; (i<cr->nodeid); i++)
531 ionize_seed = INT_MAX*rando(&ionize_seed);
532 fprintf(fp,PREFIX"Modifying seed on parallel processor to %d\n",
536 for(Eindex=0; (Eindex < NENER) && (Energies[Eindex] != ephot); Eindex++)
539 fatal_error(0,PREFIX"Energy level of %d keV not supported",ephot);
541 /* Initiate cross section data etc. */
542 ca = mk_cross_atom(fp,md,atomname,Eindex);
546 inv_nratoms = 1.0/md->nr;
548 xvg = xvgropen("ionize.xvg","Ionization Events","Time (ps)","()");
549 xvgr_legend(xvg,asize(leg),leg);
550 ion = ffopen("ionize.log","w");
552 fprintf(fp,PREFIX"Parameters for ionization events:\n");
553 fprintf(fp,PREFIX"Imax = %g, t0 = %g, width = %g, seed = %d\n"
554 PREFIX"# Photons = %g, rho = %g, ephot = %d (keV), Electrons = %s\n",
555 imax,t0,width,ionize_seed,nphot,rho,ephot,yesno_names[bElectron]);
556 fprintf(fp,PREFIX"Electron_mass: %10.3e(keV) Atomic_mass: %10.3e(keV)\n"
557 PREFIX"Speed_of_light: %10.3e(nm/ps)\n",
558 ELECTRONMASS_keV,ATOMICMASS_keV,SPEED_OF_LIGHT);
559 fprintf(fp,PREFIX"Interval between shots: %g ps\n",interval);
560 fprintf(fp,PREFIX"Eindex = %d\n",Eindex);
561 fprintf(fp,PREFIX"Doing ionizations for atoms %d - %d\n",start,end);
563 bElectron = analyze_electrons(fp,&edb,md->nr,atomname);
570 /******************************************************
572 * H E R E S T A R T S I O N I Z A T I O N
574 ******************************************************/
576 /* Calculate probability */
579 while (t > (tmax+interval*0.5))
581 /* End when t <= t0 + (N+0.5) interval */
583 pt = imax*ir->delta_t*exp(-0.5*sqr((t-tmax)/width));
587 hboxx = 0.5*box[XX][XX];
588 hboxy = 0.5*box[YY][YY];
591 /* Width of gaussian for probability of incoherent scattering */
592 sigmaPincoh = 1/sqrt(44.0);
594 /* Arrays for ionization statistics */
595 snew(nionize,md->nr);
599 /* Loop over atoms */
600 for(i=start; (i<end); i++) {
601 /* Loop over collision types */
603 for(k=0; (k<ecollNR); k++)
604 /* Determine cross section for this collision type */
605 pcoll[k]= pt*xray_cross_section(k,&(ca[i]));
607 /* Total probability of ionisation */
608 ptot = 1 - (1-pcoll[ecollPHOTO])*(1-pcoll[ecollINELASTIC]);
610 fprintf(debug,PREFIX"Ptot = %g, t = %g\n",ptot,t);
612 /* Check whether to ionize this guy */
616 bDOIT = (((rando(&ionize_seed) < ptot) && (ca[i].n < ca[i].z)) &&
617 ((sqr(x[i][XX] - hboxx) + sqr(x[i][YY] - hboxy)) < rho2));
623 fatal_error(0,"Unknown ionization mode %d (%s, line %d)",mode,
630 /* The relative probability for a photoellastic event is given by: */
631 pphot = pcoll[ecollPHOTO]/(pcoll[ecollPHOTO]+pcoll[ecollINELASTIC]);
633 if (rando(&ionize_seed) < pphot)
638 /* If a random number is smaller than the probability for
639 * an L ionization than do that. Note that the probability
640 * may be zero (H, He), but the < instead of <= covers that.
642 nK = number_K(&ca[i]);
643 nL = number_L(&ca[i]);
644 bL = (nK == 0) || ( (nL > 0) && (rando(&ionize_seed) > prob_K(k,&(ca[i]))));
648 /* Select which one to take by yet another random numer */
651 /* Get parameters for photoelestic effect */
652 /* Note that in the article this is called 2 theta */
653 theta = DEG2RAD*gauss(70.0,26.0,&ionize_seed);
654 phi = 2*M_PI*rando(&ionize_seed);
657 E_lost = ephot-recoil[ca[i].z].E_L*(ca[i].n+1);
659 E_lost = ephot-recoil[ca[i].z].E_K;
660 if ((ca[i].z > 2) && (nL > 0))
664 fprintf(debug,"i = %d, nK = %d, nL = %d, bL = %s, bKHole = %s\n",
665 i,nK,nL,BOOL(bL),BOOL(bKHole));
672 /* Compute the components of the velocity vector */
673 factor = ((ELECTRONMASS_keV/(ATOMICMASS_keV*md->massT[i]))*
674 (SPEED_OF_LIGHT*sqrt(2*E_lost/ELECTRONMASS_keV)));
676 /* Subtract momentum of recoiling electron */
677 polar2cart(phi,theta,ddv);
678 for(m=0; (m<DIM); m++)
679 dv[m] -= factor*ddv[m];
681 add_electron(fp,md,&edb,i,x,v,dv,ir->delta_t);
684 pr_rvec(debug,0,"ELL",dv,DIM);
690 case ecollINELASTIC: {
691 real theta,phi,Ebind,Eelec;
694 Ebind = (ca[i].n+1)*recoil[ca[i].z].E_L;
696 Ebind = recoil[ca[i].z].E_K;
697 if ((ca[i].z > 2) && (nL > 0))
700 theta = DEG2RAD*rand_theta_incoh(Eindex,&ionize_seed);
701 Eelec = (sqr(ephot)/512)*(1-cos(2*theta));
702 bIonize = (Ebind <= Eelec);
703 bKHole = bKHole && bIonize;
705 fprintf(debug,PREFIX"Ebind: %g, Eelectron: %g\n",Ebind,Eelec);
707 /* Subtract momentum of recoiling photon */
708 /*phi = 2*M_PI*rando(&ionize_seed);
711 dv[XX] -= factor*cos(phi)*sin(theta);
712 dv[YY] -= factor*sin(phi)*sin(theta);
713 dv[ZZ] -= factor*cos(theta);
716 pr_rvec(debug,0,"INELL",dv,DIM);
721 fatal_error(0,"Ga direct naar de gevangenis. Ga niet langs start");
724 /* First increase the charge */
725 if (ca[i].n < ca[i].z) {
726 md->chargeA[i] += 1.0;
727 md->chargeB[i] += 1.0;
732 fprintf(debug,"Random-dv[%3d] = %10.3e,%10.3e,%10.3e,"
733 " ephot = %d, Elost=%10.3e\n",
734 i,dv[XX],dv[YY],dv[ZZ],ephot,E_lost);
737 /* Now actually add the impulse to the velocities */
738 for(m=0; (m<DIM); m++)
748 /* Now check old event: Loop over k holes! */
750 for (kk = 0; (kk < nkh); kk++)
751 if (khole_decay(fp,&(ca[i]),x,v,i,&ionize_seed,ir->delta_t,
752 bElectron,md,&edb)) {
757 if (debug && (ca[i].n > 0))
758 dump_ca(debug,&(ca[i]),i,__FILE__,__LINE__);
761 /* Sum events for statistics if necessary */
763 gmx_sumi(md->nr,nionize,cr);
764 gmx_sumi(md->nr,nkhole,cr);
765 gmx_sumi(md->nr,ndecay,cr);
766 nbuf[0] = dq; nbuf[1] = nkdecay;
768 dq = nbuf[0]; nkdecay = nbuf[1];
770 /* Now sum global events on this timestep to cumulative numbers */
776 /* Print data to the file that holds ionization events per atom */
777 fprintf(ion,"%12.8f",t);
778 for(i=0; (i<md->nr); i++) {
780 fprintf(ion," I:%d",i+1);
782 fprintf(ion," K:%d",i+1);
784 fprintf(ion," D:%d",i+1);
790 /* Print statictics to file */
791 fprintf(xvg,"%10.5f %10.3e %6d %6d %6d %6d",
792 t,pt,dq,dq_tot,nkdecay,nkd_tot);