void replace_coordinates(struct atomgrp* ag, const char* pdb_path) { struct atomgrp* ag_new = read_pdb_nopar(pdb_path); if (ag_new->natoms != ag->natoms) { _mol_error("new atomgroup has %d atoms, old has %d atoms", ag_new->natoms, ag->natoms); exit(EXIT_FAILURE); } int list[ag->natoms]; for (int i=0; i<ag->natoms; i++) { list[i] = i; } setup_subag(ag, ag_new, ag->natoms, list); free_atomgrp(ag_new); }
void accs2(struct atomgrp* ag, float r_solv, short cont_acc, float* as) { const int NAC=5000; /* max number of atoms in a cube */ /* integration increment */ const float P=0.01; int i, sint=sizeof(int), sflo=sizeof(float); int n_at1=ag->natoms; float xmin, xmax, ymin, ymax, zmin, zmax; float rmax=0; float pi=acos(-1.0); float pix2=2.0*pi; float ri, xi, yi, zi; float *x; float *y; float *z; float *r; float *r2; float *dx; float *dy; float *d; float *dsq; float *arcif; int *inov; float dmax; int idim; int jidim; int kjidim; int *itab; int *natm; int* cube; int j, k, l, m, n, kji; int ir, io, in, mkji, nm, nzp, karc; float area, xr, yr, zr, rr, rrx2, rr2, b, zres, zgrid; float rsec2r, rsecr, rsec2n, rsecn; float calpha, alpha, beta, ti, tf, arcsum, parea, t, tt; /* eliminate atoms with zero radii */ int n_at=0; int *restat; i=n_at1*sint; restat=_mol_malloc(i); for(i=0; i<n_at1; i++) { as[i]=0.0; ri=ag->atoms[i].rminh; if(ri>0.0)restat[n_at++]=i; } /* initialize boundary constants */ xmin=ag->atoms[restat[0]].X; xmax=xmin; ymin=ag->atoms[restat[0]].Y; ymax=ymin; zmin=ag->atoms[restat[0]].Z; zmax=zmin; /* allocate general atom related arrays */ i=n_at*sflo; x=_mol_malloc(i); y=_mol_malloc(i); z=_mol_malloc(i); r=_mol_malloc(i); r2=_mol_malloc(i); /* allocate arrays for neighbouring atoms */ dx=_mol_malloc(i); dy=_mol_malloc(i); d=_mol_malloc(i); dsq=_mol_malloc(i); arcif=_mol_malloc(2*2*i); i=n_at*sint; inov=_mol_malloc(i); /* calculate sizes and dimensions*/ for(i=0; i<n_at; i++) { ri=ag->atoms[restat[i]].rminh; ri=ri+r_solv; r[i]=ri; r2[i]=ri*ri; if(ri>rmax)rmax=ri; x[i]=ag->atoms[restat[i]].X; if(xmin>x[i])xmin=x[i]; if(xmax<x[i])xmax=x[i]; y[i]=ag->atoms[restat[i]].Y; if(ymin>y[i])ymin=y[i]; if(ymax<y[i])ymax=y[i]; z[i]=ag->atoms[restat[i]].Z; if(zmin>z[i])zmin=z[i]; if(zmax<z[i])zmax=z[i]; } dmax=rmax*2.0; i=(xmax-xmin)/dmax+1; idim=i<3?3:i; i=(ymax-ymin)/dmax+1; jidim=i<3?3:i; jidim*=idim; i=(zmax-zmin)/dmax+1; kjidim=i<3?3:i; kjidim*=jidim; /* total number of cubes */ /* map atoms to adjacent cubes */ /* allocate cubical arrays */ i=kjidim*sint; itab=_mol_malloc(i); /* number of atoms in each cube */ for(i=0; i<kjidim; i++)itab[i]=0; i=NAC*kjidim*sint; natm=_mol_malloc(i); /* atom index in each cube */ i=n_at*sint; cube=_mol_malloc(i); /* cube number for each atom */ for(l=0; l<n_at; l++) { i=(x[l]-xmin)/dmax; j=(y[l]-ymin)/dmax; k=(z[l]-zmin)/dmax; kji=k*jidim+j*idim+i; /* cube number */ n=itab[kji]+1; if(n>NAC) { _mol_error("number of atoms in a cube %d is above the maximum NAC= %d\n", n, NAC); exit(EXIT_FAILURE); } itab[kji]=n; natm[kji*NAC+n-1]=l; cube[l]=kji; } /* main loop over atoms */ zi=1.0/P+0.5; nzp=zi; /* number of z planes */ for (ir=0; ir<n_at; ir++) { kji=cube[ir]; io=0; /* number of neighbouring atoms */ area=0.0; xr=x[ir]; yr=y[ir]; zr=z[ir]; rr=r[ir]; rrx2=rr*2; rr2=r2[ir]; /* loops over neighbouring cubes */ for (k=-1; k<2; k++) { for(j=-1; j<2; j++) { for(i=-1; i<2; i++) { mkji=kji+k*jidim+j*idim+i; if(mkji<0)continue; if(mkji>=kjidim)goto esc_cubes; nm=itab[mkji]; if(nm<1)continue; for(m=0; m<nm; m++) { in=natm[mkji*NAC+m]; if(in!=ir) { xi=xr-x[in]; yi=yr-y[in]; dx[io]=xi; dy[io]=yi; ri=xi*xi+yi*yi; dsq[io]=ri; d[io]=sqrtf(ri); inov[io]=in; io++; } } } } } esc_cubes: if(io!=0) { zres=rrx2/nzp; /* separation between planes */ zgrid=z[ir]-rr-zres/2.0; /* z level */ for(i=0; i<nzp; i++) { zgrid+=zres; /* radius of the circle intersection with a z-plane */ zi=zgrid-zr; rsec2r=rr2-zi*zi; rsecr=sqrtf(rsec2r); karc=0; for(j=0; j<io; j++) { in=inov[j]; /* radius of the circle for a neighbour */ zi=zgrid-z[in]; rsec2n=r2[in]-zi*zi; if(rsec2n<=0.0)continue; rsecn=sqrtf(rsec2n); /* are they close? */ if(d[j]>=rsecr+rsecn)continue; /* do they intersect? */ b=rsecr-rsecn; if(b<=0.0) { if(d[j]<=-b)goto next_plane; } else { if(d[j]<=b)continue; } calpha=(dsq[j]+rsec2r-rsec2n)/(2.0*d[j]*rsecr); if(calpha>=1.0)continue; /* yes, they do */ alpha=acosf(calpha); beta=atan2f(dy[j],dx[j])+pi; ti=beta-alpha; tf=beta+alpha; if(ti<0.0)ti+=pix2; if(tf>pix2)tf-=pix2; arcif[karc]=ti; if(tf<ti) { arcif[karc+1]=pix2; karc+=2; arcif[karc]=0.0; } arcif[karc+1]=tf; karc+=2; } /* find the atom accessible surface increment in z-plane */ karc/=2; if(karc==0) arcsum=pix2; else { qsort(arcif, karc, 2*sizeof(arcif[0]), accs_comp); arcsum=arcif[0]; t=arcif[1]; if(karc>1) { for(k=2; k<karc*2; k+=2) { if(t<arcif[k])arcsum+=(arcif[k]-t); tt=arcif[k+1]; if(tt>t)t=tt; } } arcsum+=(pix2-t); } parea=arcsum*zres; area+=parea; next_plane:; } } else { area=pix2*rrx2; } ri=rr-r_solv; if(cont_acc) b=area*ri*ri/rr; else b=area*rr; as[restat[ir]]=b; } /* free all */ free(x); free(y); free(z); free(r); free(r2); free(dx); free(dy); free(d); free(dsq); free(arcif); free(inov); free(itab); free(natm); free(cube); free(restat); }