ESPResSo 3.2.0-11-g9950804-git
Extensible Simulation Package for Soft Matter Research
statistics.c
Go to the documentation of this file.
00001 /*
00002   Copyright (C) 2010,2011,2012,2013 The ESPResSo project
00003   Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 
00004     Max-Planck-Institute for Polymer Research, Theory Group
00005   
00006   This file is part of ESPResSo.
00007   
00008   ESPResSo is free software: you can redistribute it and/or modify
00009   it under the terms of the GNU General Public License as published by
00010   the Free Software Foundation, either version 3 of the License, or
00011   (at your option) any later version.
00012   
00013   ESPResSo is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016   GNU General Public License for more details.
00017   
00018   You should have received a copy of the GNU General Public License
00019   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
00020 */
00021 /** \file statistics.c
00022     This is the place for analysis (so far...).
00023     Implementation of statistics.h
00024 */
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include "utils.h"
00028 #include "statistics.h"
00029 #include "statistics_chain.h"
00030 #include "statistics_molecule.h"
00031 #include "statistics_cluster.h"
00032 #include "statistics_fluid.h"
00033 //#include "statistics_correlation.h"
00034 #include "energy.h"
00035 #include "modes.h"
00036 #include "pressure.h"
00037 #include "communication.h"
00038 #include "grid.h"
00039 #include "particle_data.h"
00040 #include "interaction_data.h"
00041 #include "domain_decomposition.h"
00042 #include "verlet.h"
00043 #include "lb.h"
00044 #include "virtual_sites.h"
00045 #include "initialize.h"
00046 
00047 /** Previous particle configurations (needed for offline analysis and
00048     correlation analysis in \ref tclcommand_analyze) */
00049 double **configs = NULL; int n_configs = 0; int n_part_conf = 0;
00050 
00051 /****************************************************************************************
00052  *                                 helper functions
00053  ****************************************************************************************/
00054 
00055 double min_distance2(double pos1[3], double pos2[3])
00056 {
00057   double diff[3];
00058   get_mi_vector(diff, pos1, pos2);
00059   return sqrlen(diff);
00060 }
00061 
00062 
00063 /****************************************************************************************
00064  *                                 basic observables calculation
00065  ****************************************************************************************/
00066 
00067 double mindist(IntList *set1, IntList *set2)
00068 {
00069   double mindist, pt[3];
00070   int i, j, in_set;
00071 
00072   mindist = SQR(box_l[0] + box_l[1] + box_l[2]);
00073 
00074   updatePartCfg(WITHOUT_BONDS);
00075   for (j=0; j<n_total_particles-1; j++) {
00076     pt[0] = partCfg[j].r.p[0];
00077     pt[1] = partCfg[j].r.p[1];
00078     pt[2] = partCfg[j].r.p[2];
00079     /* check which sets particle j belongs to
00080        bit 0: set1, bit1: set2
00081     */
00082     in_set = 0;
00083     if (!set1 || intlist_contains(set1, partCfg[j].p.type))
00084       in_set = 1;
00085     if (!set2 || intlist_contains(set2, partCfg[j].p.type))
00086       in_set |= 2;
00087     if (in_set == 0)
00088       continue;
00089 
00090     for (i=j+1; i<n_total_particles; i++)
00091       /* accept a pair if particle j is in set1 and particle i in set2 or vice versa. */
00092       if (((in_set & 1) && (!set2 || intlist_contains(set2, partCfg[i].p.type))) ||
00093           ((in_set & 2) && (!set1 || intlist_contains(set1, partCfg[i].p.type))))
00094         mindist = dmin(mindist, min_distance2(pt, partCfg[i].r.p));
00095   }
00096   mindist = sqrt(mindist);
00097   return mindist;
00098 }
00099 
00100 void merge_aggregate_lists(int *head_list, int *agg_id_list, int p1molid, int p2molid, int *link_list)
00101 {
00102     int target1, target2, head_p1;
00103     /* merge list containing p2molid into list containing p1molid*/
00104     target1=head_list[agg_id_list[p2molid]];
00105     head_list[agg_id_list[p2molid]]=-2;
00106     head_p1=head_list[agg_id_list[p1molid]];
00107     head_list[agg_id_list[p1molid]]=target1;
00108     agg_id_list[target1]=agg_id_list[p1molid];
00109     target2=link_list[target1];
00110     while(target2 != -1) {
00111         target1=target2;
00112         target2=link_list[target1];
00113         agg_id_list[target1]=agg_id_list[p1molid];
00114     }
00115     agg_id_list[target1]=agg_id_list[p1molid];
00116     link_list[target1]=head_p1;
00117 }
00118 
00119 int aggregation(double dist_criteria2, int min_contact, int s_mol_id, int f_mol_id, int *head_list, int *link_list, int *agg_id_list, int *agg_num, int *agg_size, int *agg_max, int *agg_min, int *agg_avg, int *agg_std, int charge)
00120 {
00121   int c, np, n, i;
00122   Particle *p1, *p2, **pairs;
00123   double dist2;
00124   int target1;
00125   int p1molid, p2molid;
00126   int *contact_num, ind;
00127 
00128   if (min_contact > 1) {
00129     contact_num = (int *) malloc(n_molecules*n_molecules *sizeof(int));
00130     for (i = 0; i < n_molecules *n_molecules; i++) contact_num[i]=0;
00131   } else {
00132     contact_num = (int *) 0; /* Just to keep the compiler happy */
00133   }
00134 
00135   on_observable_calc();
00136   build_verlet_lists();
00137 
00138   for (i = s_mol_id; i <= f_mol_id; i++) {
00139     head_list[i]=i;
00140     link_list[i]=-1;
00141     agg_id_list[i]=i;
00142     agg_size[i]=0;
00143   }
00144   
00145   /* Loop local cells */
00146   for (c = 0; c < local_cells.n; c++) {
00147     /* Loop cell neighbors */
00148     for (n = 0; n < dd.cell_inter[c].n_neighbors; n++) {
00149       pairs = dd.cell_inter[c].nList[n].vList.pair;
00150       np    = dd.cell_inter[c].nList[n].vList.n;
00151       /* verlet list loop */
00152       for(i=0; i<2*np; i+=2) {
00153         p1 = pairs[i];                    /* pointer to particle 1 */
00154         p2 = pairs[i+1];                  /* pointer to particle 2 */
00155         p1molid = p1->p.mol_id;
00156         p2molid = p2->p.mol_id;
00157         if (((p1molid <= f_mol_id) && (p1molid >= s_mol_id)) && ((p2molid <= f_mol_id) && (p2molid >= s_mol_id))) {
00158           if (agg_id_list[p1molid] != agg_id_list[p2molid]) {
00159             dist2 = min_distance2(p1->r.p, p2->r.p);
00160 
00161 #ifdef ELECTROSTATICS
00162             if (charge && (p1->p.q * p2->p.q >= 0)) {continue;}
00163 #endif
00164             if (dist2 < dist_criteria2) {
00165               if ( p1molid > p2molid ) { ind=p1molid*n_molecules + p2molid;} 
00166               else { ind=p2molid*n_molecules +p1molid;}
00167               if (min_contact > 1) {
00168                 contact_num[ind] ++;
00169                 if (contact_num[ind] >= min_contact) {
00170                     merge_aggregate_lists( head_list, agg_id_list, p1molid, p2molid, link_list);                                    
00171                 }
00172               } else {
00173                   merge_aggregate_lists( head_list, agg_id_list, p1molid, p2molid, link_list);                              
00174               }
00175             }
00176           }
00177         }
00178       }
00179     }
00180   }
00181   
00182   /* count number of aggregates 
00183      find aggregate size
00184      find max and find min size, and std */
00185   for (i = s_mol_id ; i <= f_mol_id ; i++) {
00186     if (head_list[i] != -2) {
00187       (*agg_num)++;
00188       agg_size[*agg_num -1]++;
00189       target1= head_list[i];
00190       while( link_list[target1] != -1) {
00191         target1= link_list[target1];
00192         agg_size[*agg_num -1]++;
00193       }
00194     }
00195   }
00196   
00197   for (i = 0 ; i < *agg_num; i++) {
00198     *agg_avg += agg_size[i];
00199     *agg_std += agg_size[i] * agg_size[i];
00200     if (*agg_min > agg_size[i]) { *agg_min = agg_size[i]; }
00201     if (*agg_max < agg_size[i]) { *agg_max = agg_size[i]; }
00202   }
00203   
00204   return 0;
00205 }
00206 
00207 /** Calculate momentum of all particles in the local domain
00208  * @param result Result for this processor (Output)
00209  */
00210 void predict_momentum_particles(double *result)
00211 {
00212   Cell *cell;
00213   Particle *p;
00214   int i, c, np;
00215 
00216   double momentum[3] = { 0.0, 0.0, 0.0 };
00217 
00218   for (c = 0; c < local_cells.n; c++) {
00219     cell = local_cells.cell[c];
00220     np = cell->n;
00221     p  = cell->part;
00222 
00223     for(i=0; i < np; i++) {
00224          momentum[0] +=  p[i].m.v[0] + p[i].f.f[0];
00225          momentum[1] +=  p[i].m.v[1] + p[i].f.f[1];
00226          momentum[2] +=  p[i].m.v[2] + p[i].f.f[2];
00227     }
00228   }
00229 
00230   momentum[0] /= time_step;
00231   momentum[1] /= time_step;
00232   momentum[2] /= time_step;
00233 
00234   MPI_Reduce(momentum, result, 3, MPI_DOUBLE, MPI_SUM, 0, comm_cart);
00235 }
00236 
00237 /** Calculate total momentum of the system (particles & LB fluid)
00238  * @param momentum Rsult for this processor (Output)
00239  */
00240 void momentum_calc(double *momentum) 
00241 {
00242     double momentum_fluid[3] = { 0., 0., 0. };
00243     double momentum_particles[3] = { 0., 0., 0. };
00244 
00245     mpi_gather_stats(4, momentum_particles, NULL, NULL, NULL);
00246 #ifdef LB
00247     mpi_gather_stats(6, momentum_fluid, NULL, NULL, NULL);
00248 #endif
00249 
00250     momentum[0] = momentum_fluid[0] + momentum_particles[0];
00251     momentum[1] = momentum_fluid[1] + momentum_particles[1];
00252     momentum[2] = momentum_fluid[2] + momentum_particles[2];
00253 
00254 }
00255 
00256 void centermass(int type, double *com)
00257 {
00258   int i, j;
00259   double M = 0.0;
00260   com[0]=com[1]=com[2]=0.;
00261         
00262   updatePartCfg(WITHOUT_BONDS);
00263   for (j=0; j<n_total_particles; j++) {
00264     if ((partCfg[j].p.type == type) || (type == -1)) {
00265       for (i=0; i<3; i++) {
00266         com[i] += partCfg[j].r.p[i]*PMASS(partCfg[j]);
00267       }
00268       M += PMASS(partCfg[j]);
00269     }
00270   }
00271   
00272   for (i=0; i<3; i++) {
00273     com[i] /= M;
00274   }
00275   return;
00276 }
00277 
00278 void centermass_vel(int type, double *com)
00279 {
00280   /*center of mass velocity scaled with time_step*/
00281   int i, j;
00282   int count = 0;
00283   com[0]=com[1]=com[2]=0.;
00284 
00285   updatePartCfg(WITHOUT_BONDS);
00286   for (j=0; j<n_total_particles; j++) {
00287     if (type == partCfg[j].p.type) {
00288       for (i=0; i<3; i++) {
00289         com[i] += partCfg[j].m.v[i];
00290       }
00291       count++;
00292     }
00293   }
00294 
00295   for (i=0; i<3; i++) {
00296     com[i] /= count;
00297   }
00298   return;
00299 }
00300 
00301 void angularmomentum(int type, double *com)
00302 {
00303   int i, j;
00304   double tmp[3];
00305   double pre_factor;
00306   com[0]=com[1]=com[2]=0.;
00307 
00308   updatePartCfg(WITHOUT_BONDS);
00309   for (j=0; j<n_total_particles; j++) 
00310   {
00311     if (type == partCfg[j].p.type) 
00312     {
00313       vector_product(partCfg[j].r.p,partCfg[j].m.v,tmp);
00314       pre_factor=PMASS(partCfg[j]);
00315       for (i=0; i<3; i++) {
00316         com[i] += tmp[i]*pre_factor;
00317       }
00318     }
00319   }
00320   return;
00321 }
00322 
00323 void  momentofinertiamatrix(int type, double *MofImatrix)
00324 {
00325   int i,j,count;
00326   double p1[3],com[3],massi;
00327 
00328   count=0;
00329   updatePartCfg(WITHOUT_BONDS);
00330   for(i=0;i<9;i++) MofImatrix[i]=0.;
00331   centermass(type, com);
00332   for (j=0; j<n_total_particles; j++) {
00333     if (type == partCfg[j].p.type) {
00334       count ++;
00335       for (i=0; i<3; i++) {
00336         p1[i] = partCfg[j].r.p[i] - com[i];
00337       }
00338       massi= PMASS(partCfg[j]);
00339       MofImatrix[0] += massi * (p1[1] * p1[1] + p1[2] * p1[2]) ; 
00340       MofImatrix[4] += massi * (p1[0] * p1[0] + p1[2] * p1[2]);
00341       MofImatrix[8] += massi * (p1[0] * p1[0] + p1[1] * p1[1]);
00342       MofImatrix[1] -= massi * (p1[0] * p1[1]);
00343       MofImatrix[2] -= massi * (p1[0] * p1[2]); 
00344       MofImatrix[5] -= massi * (p1[1] * p1[2]);
00345     }
00346   }
00347   /* use symmetry */
00348   MofImatrix[3] = MofImatrix[1]; 
00349   MofImatrix[6] = MofImatrix[2]; 
00350   MofImatrix[7] = MofImatrix[5];
00351   return;
00352 }
00353 
00354 void calc_gyration_tensor(int type, double **_gt)
00355 {
00356   int i, j, count;
00357   double com[3];
00358   double eva[3],eve0[3],eve1[3],eve2[3];
00359   double *gt=NULL, tmp;
00360   double Smatrix[9],p1[3];
00361 
00362   for (i=0; i<9; i++) Smatrix[i] = 0;
00363   *_gt = gt = realloc(gt,16*sizeof(double)); /* 3*ev, rg, b, c, kappa, eve0[3], eve1[3], eve2[3]*/
00364 
00365   updatePartCfg(WITHOUT_BONDS);
00366 
00367   /* Calculate the position of COM */
00368   centermass(type,com);
00369 
00370   /* Calculate the gyration tensor Smatrix */
00371   count=0;
00372   for (i=0;i<n_total_particles;i++) {
00373     if ((partCfg[i].p.type == type) || (type == -1)) {
00374       for ( j=0; j<3 ; j++ ) { 
00375         p1[j] = partCfg[i].r.p[j] - com[j];
00376       }
00377       count ++;
00378       Smatrix[0] += p1[0]*p1[0];
00379       Smatrix[1] += p1[0]*p1[1];
00380       Smatrix[2] += p1[0]*p1[2];
00381       Smatrix[4] += p1[1]*p1[1];
00382       Smatrix[5] += p1[1]*p1[2];
00383       Smatrix[8] += p1[2]*p1[2];
00384     }
00385   }
00386   /* use symmetry */
00387   Smatrix[3]=Smatrix[1];
00388   Smatrix[6]=Smatrix[2];
00389   Smatrix[7]=Smatrix[5];
00390   for (i=0;i<9;i++){
00391     Smatrix[i] /= count;
00392   }
00393 
00394   /* Calculate the eigenvalues of Smatrix */
00395   i=calc_eigenvalues_3x3(Smatrix, eva);
00396   tmp=0.0;
00397   for (i=0;i<3;i++) {
00398     /* Eigenvalues */
00399     gt[i] = eva[i];
00400     tmp += eva[i];
00401   }
00402   
00403   i=calc_eigenvector_3x3(Smatrix,eva[0],eve0); 
00404   i=calc_eigenvector_3x3(Smatrix,eva[1],eve1); 
00405   i=calc_eigenvector_3x3(Smatrix,eva[2],eve2); 
00406   gt[3] = tmp; /* Squared Radius of Gyration */
00407   gt[4] = eva[0]-0.5*(eva[1]+eva[2]);  /* Asphericity */
00408   gt[5] = eva[1]-eva[2];  /* Acylindricity */
00409   gt[6] = (gt[4]*gt[4]+0.75*gt[5]*gt[5])/(gt[3]*gt[3]); /* Relative shape anisotropy */
00410   /* Eigenvectors */
00411   for (j=0;j<3;j++) {
00412     gt[7+j]=eve0[j]; 
00413     gt[10+j]=eve1[j];
00414     gt[13+j]=eve2[j];
00415   }
00416 }
00417 
00418 
00419 void nbhood(double pt[3], double r, IntList *il, int planedims[3] )
00420 {
00421   double d[3];
00422   int i,j;
00423   double r2;
00424 
00425   r2 = r*r;
00426 
00427   init_intlist(il);
00428  
00429   updatePartCfg(WITHOUT_BONDS);
00430 
00431   for (i = 0; i<n_total_particles; i++) {
00432     if ( (planedims[0] + planedims[1] + planedims[2]) == 3 ) {
00433       get_mi_vector(d, pt, partCfg[i].r.p);
00434     } else {
00435       /* Calculate the in plane distance */
00436       for ( j= 0 ; j < 3 ; j++ ) {
00437         d[j] = planedims[j]*(partCfg[i].r.p[j]-pt[j]);
00438       }
00439     }
00440 
00441     if (sqrlen(d) < r2) {
00442       realloc_intlist(il, il->n + 1);
00443       il->e[il->n] = partCfg[i].p.identity;
00444       il->n++;
00445     }
00446   }
00447 }
00448 
00449 double distto(double p[3], int pid)
00450 {
00451   int i;
00452   double d[3];
00453   double mindist;
00454 
00455   updatePartCfg(WITHOUT_BONDS);
00456 
00457   /* larger than possible */
00458   mindist=SQR(box_l[0] + box_l[1] + box_l[2]);
00459   for (i=0; i<n_total_particles; i++) {
00460     if (pid != partCfg[i].p.identity) {
00461       get_mi_vector(d, p, partCfg[i].r.p);
00462       mindist = dmin(mindist, sqrlen(d));
00463     }
00464   }
00465   return sqrt(mindist);
00466 }
00467 
00468 void calc_cell_gpb(double xi_m, double Rc, double ro, double gacc, int maxtry, double *result) {
00469   double LOG,xi_min, RM, gamma,g1,g2,gmid=0,dg,ig, f,fmid, rtb;
00470   int i;
00471   LOG    = log(Rc/ro);
00472   xi_min = LOG/(1+LOG);
00473   if(maxtry < 1) maxtry = 1;
00474 
00475   /* determine which of the regimes we are in: */
00476   if(xi_m > 1) {
00477     ig = 1.0;
00478     g1 = PI / LOG;
00479     g2 = PI / (LOG + xi_m/(xi_m-1.0)); }
00480   else if(xi_m == 1) {
00481     ig = 1.0;
00482     g1 = (PI/2.0) / LOG;
00483     g2 = (PI/2.0) / (LOG + 1.0); }
00484   else if(xi_m == xi_min) {
00485     ig = 1.0;
00486     g1 = g2 = 0.0; }
00487   else if(xi_m > xi_min) {
00488     ig = 1.0;
00489     g1 = (PI/2.0) / LOG;
00490     g2 = sqrt(3.0*(LOG-xi_m/(1.0-xi_m))/(1-pow((1.0-xi_m),-3.0))); }
00491   else if(xi_m > 0.0) {
00492     ig = -1.0;
00493     g1 = 1-xi_m;
00494     g2 = xi_m*(6.0-(3.0-xi_m)*xi_m)/(3.0*LOG); }
00495   else if(xi_m == 0.0) {
00496     ig = -1.0;
00497     g1 = g2 = 1-xi_m; }
00498   else {
00499     result[2]=-5.0; return;
00500   }
00501 
00502   /* decide which method to use (if any): */
00503   if(xi_m == xi_min) {
00504     gamma = 0.0;
00505     RM    = 0.0; }
00506   else if(xi_m == 0.0) {
00507     gamma = 1-xi_m;
00508     RM    = -1.0; }
00509   else if(ig == 1.0) {
00510     /* determine gamma via a bisection-search: */
00511     f    = atan(1.0/g1) + atan( (xi_m-1.0) / g1 ) - g1 * LOG;
00512     fmid = atan(1.0/g2) + atan( (xi_m-1.0) / g2 ) - g2 * LOG;
00513     if (f*fmid >= 0.0) {
00514       /* failed to bracket function value with intial guess - abort: */
00515       result[0]=f; result[1]=fmid; result[2]=-3.0; return;  }
00516 
00517     /* orient search such that the positive part of the function lies to the right of the zero */
00518     rtb = f < 0.0 ? (dg=g2-g1,g1) : (dg=g1-g2,g2);
00519     for (i = 1; i <= maxtry; i++) {
00520       gmid = rtb + (dg *= 0.5);
00521       fmid = atan(1.0/gmid) + atan((xi_m-1.0)/gmid) - gmid*LOG;
00522       if (fmid <= 0.0) rtb = gmid;
00523       if (fabs(dg) < gacc || fmid == 0.0) break;
00524     }
00525 
00526     if (fabs(dg) > gacc) {
00527       /* too many iterations without success - abort: */
00528       result[0]=gmid; result[1]=dg; result[2]=-2.0; return;  }
00529 
00530     /* So, these are the values for gamma and Manning-radius: */
00531     gamma = gmid;
00532     RM    = Rc * exp( -(1.0/gamma) * atan(1.0/gamma) ); }
00533   else if(ig == -1.0) {
00534     /* determine -i*gamma: */
00535     f = -1.0*(atanh(g2) + atanh(g2/(xi_m-1))) - g2*LOG;
00536 
00537     /* modified orient search, this time starting from the upper bound backwards: */
00538     if (f < 0.0) {
00539       rtb = g1;  dg = g1-g2; }
00540     else {
00541       fprintf(stderr,"WARNING: Lower boundary is actually larger than l.h.s, flipping!\n");
00542       rtb = g1;  dg = g1;    }
00543     for (i = 1; i <= maxtry; i++) {
00544       gmid = rtb - (dg *= 0.5);
00545       fmid = -1.0*(atanh(gmid) + atanh(gmid/(xi_m-1))) - gmid*LOG;
00546       if (fmid >= 0.0) rtb = gmid;
00547       if (fabs(dg) < gacc || fmid == 0.0) break;
00548     }
00549     
00550     if (fabs(dg) > gacc) {
00551       /* too many iterations without success - abort: */
00552       result[0]=gmid; result[1]=dg; result[2]=-2.0; return;  }
00553 
00554     /* So, these are the values for -i*gamma and Manning-radius: */
00555     gamma = gmid;
00556     RM    = Rc * exp( atan(1.0/gamma)/gamma ); }
00557   else {
00558     result[2]=-5.0; return;
00559   }
00560 
00561   result[0]=gamma;
00562   result[1]=RM;
00563   result[2]=ig;
00564   return;
00565 }
00566 
00567 void calc_part_distribution(int *p1_types, int n_p1, int *p2_types, int n_p2, 
00568                             double r_min, double r_max, int r_bins, int log_flag, 
00569                             double *low, double *dist)
00570 {
00571   int i,j,t1,t2,ind,cnt=0;
00572   double inv_bin_width=0.0;
00573   double min_dist,min_dist2=0.0,start_dist2,act_dist2;
00574 
00575   start_dist2 = SQR(box_l[0] + box_l[1] + box_l[2]);
00576   /* bin preparation */
00577   *low = 0.0;
00578   for(i=0;i<r_bins;i++) dist[i] = 0.0;
00579   if(log_flag == 1) inv_bin_width = (double)r_bins/(log(r_max)-log(r_min));
00580   else              inv_bin_width = (double)r_bins / (r_max-r_min);
00581 
00582   /* particle loop: p1_types*/
00583   for(i=0; i<n_total_particles; i++) {
00584     for(t1=0; t1<n_p1; t1++) {
00585       if(partCfg[i].p.type == p1_types[t1]) {
00586         min_dist2 = start_dist2;
00587         /* particle loop: p2_types*/
00588         for(j=0; j<n_total_particles; j++) {
00589           if(j != i) {
00590             for(t2=0; t2<n_p2; t2++) {
00591               if(partCfg[j].p.type == p2_types[t2]) {
00592                 act_dist2 =  min_distance2(partCfg[i].r.p, partCfg[j].r.p);
00593                 if(act_dist2 < min_dist2) { min_dist2 = act_dist2; }
00594               }
00595             }
00596           }
00597         }
00598         min_dist = sqrt(min_dist2);
00599         if(min_dist <= r_max) {
00600           if(min_dist >= r_min) {
00601             /* calculate bin index */
00602             if(log_flag == 1) ind = (int) ((log(min_dist) - log(r_min))*inv_bin_width);
00603             else              ind = (int) ((min_dist - r_min)*inv_bin_width);
00604             if(ind >= 0 && ind < r_bins) {
00605               dist[ind] += 1.0;
00606             }
00607           }
00608           else {
00609             *low += 1.0;
00610           }
00611         }
00612         cnt++;    
00613       }
00614     }
00615   }
00616   
00617   /* normalization */
00618   *low /= (double)cnt;
00619   for(i=0;i<r_bins;i++) dist[i] /= (double)cnt;
00620 }
00621 
00622 
00623 void calc_rdf(int *p1_types, int n_p1, int *p2_types, int n_p2, 
00624               double r_min, double r_max, int r_bins, double *rdf)
00625 {
00626   long int cnt=0;
00627   int i,j,t1,t2,ind;
00628   int mixed_flag=0,start;
00629   double inv_bin_width=0.0,bin_width=0.0, dist;
00630   double volume, bin_volume, r_in, r_out;
00631 
00632   if(n_p1 == n_p2) {
00633     for(i=0;i<n_p1;i++) 
00634       if( p1_types[i] != p2_types[i] ) mixed_flag=1;
00635   }
00636   else mixed_flag=1;
00637 
00638   bin_width     = (r_max-r_min) / (double)r_bins;
00639   inv_bin_width = 1.0 / bin_width;
00640   for(i=0;i<r_bins;i++) rdf[i] = 0.0;
00641   /* particle loop: p1_types*/
00642   for(i=0; i<n_total_particles; i++) {
00643     for(t1=0; t1<n_p1; t1++) {
00644       if(partCfg[i].p.type == p1_types[t1]) {
00645         /* distinguish mixed and identical rdf's */
00646         if(mixed_flag == 1) start = 0;
00647         else                start = (i+1);
00648         /* particle loop: p2_types*/
00649         for(j=start; j<n_total_particles; j++) {
00650           for(t2=0; t2<n_p2; t2++) {
00651             if(partCfg[j].p.type == p2_types[t2]) {
00652               dist = min_distance(partCfg[i].r.p, partCfg[j].r.p);
00653               if(dist > r_min && dist < r_max) {
00654                 ind = (int) ( (dist - r_min)*inv_bin_width );
00655                 rdf[ind]++;
00656               }
00657               cnt++;
00658             }
00659           }
00660         }
00661       }
00662     }
00663   }
00664 
00665   /* normalization */
00666   volume = box_l[0]*box_l[1]*box_l[2];
00667   for(i=0; i<r_bins; i++) {
00668     r_in       = i*bin_width + r_min; 
00669     r_out      = r_in + bin_width;
00670     bin_volume = (4.0/3.0) * PI * ((r_out*r_out*r_out) - (r_in*r_in*r_in));
00671     rdf[i] *= volume / (bin_volume * cnt);
00672   }
00673 }
00674 
00675 void calc_rdf_av(int *p1_types, int n_p1, int *p2_types, int n_p2,
00676                  double r_min, double r_max, int r_bins, double *rdf, int n_conf)
00677 {
00678   long int cnt=0;
00679   int i,j,k,l,t1,t2,ind,cnt_conf=1;
00680   int mixed_flag=0,start;
00681   double inv_bin_width=0.0,bin_width=0.0, dist;
00682   double volume, bin_volume, r_in, r_out;
00683   double *rdf_tmp, p1[3],p2[3];
00684 
00685   rdf_tmp = malloc(r_bins*sizeof(double));
00686 
00687   if(n_p1 == n_p2) {
00688     for(i=0;i<n_p1;i++)
00689       if( p1_types[i] != p2_types[i] ) mixed_flag=1;
00690   }
00691   else mixed_flag=1;
00692   bin_width     = (r_max-r_min) / (double)r_bins;
00693   inv_bin_width = 1.0 / bin_width;
00694   volume = box_l[0]*box_l[1]*box_l[2];
00695   for(l=0;l<r_bins;l++) rdf_tmp[l]=rdf[l] = 0.0;
00696 
00697   while(cnt_conf<=n_conf) {
00698     for(l=0;l<r_bins;l++) rdf_tmp[l]=0.0;
00699     cnt=0;
00700     k=n_configs-cnt_conf;
00701     for(i=0; i<n_total_particles; i++) {
00702       for(t1=0; t1<n_p1; t1++) {
00703         if(partCfg[i].p.type == p1_types[t1]) {
00704           // distinguish mixed and identical rdf's
00705           if(mixed_flag == 1) start = 0;
00706           else                start = (i+1);
00707           //particle loop: p2_types
00708           for(j=start; j<n_total_particles; j++) {
00709             for(t2=0; t2<n_p2; t2++) {
00710               if(partCfg[j].p.type == p2_types[t2]) {
00711                 p1[0]=configs[k][3*i  ];p1[1]=configs[k][3*i+1];p1[2]=configs[k][3*i+2];
00712                 p2[0]=configs[k][3*j  ];p2[1]=configs[k][3*j+1];p2[2]=configs[k][3*j+2];
00713                 dist =min_distance(p1, p2);
00714                 if(dist > r_min && dist < r_max) {
00715                   ind = (int) ( (dist - r_min)*inv_bin_width );
00716                   rdf_tmp[ind]++;
00717                 }
00718                 cnt++;
00719               }
00720             }
00721           }
00722         }
00723       }
00724     }
00725     // normalization
00726   
00727     for(i=0; i<r_bins; i++) {
00728       r_in       = i*bin_width + r_min;
00729       r_out      = r_in + bin_width;
00730       bin_volume = (4.0/3.0) * PI * ((r_out*r_out*r_out) - (r_in*r_in*r_in));
00731       rdf[i] += rdf_tmp[i]*volume / (bin_volume * cnt);
00732     }
00733 
00734     cnt_conf++;
00735   } //cnt_conf loop
00736   for(i=0; i<r_bins; i++) {
00737     rdf[i] /= (cnt_conf-1);
00738   }
00739   free(rdf_tmp);
00740 
00741 }
00742 
00743 void calc_rdf_intermol_av(int *p1_types, int n_p1, int *p2_types, int n_p2,
00744                           double r_min, double r_max, int r_bins, double *rdf, int n_conf)
00745 {
00746   int i,j,k,l,t1,t2,ind,cnt=0,cnt_conf=1;
00747   int mixed_flag=0,start;
00748   double inv_bin_width=0.0,bin_width=0.0, dist;
00749   double volume, bin_volume, r_in, r_out;
00750   double *rdf_tmp, p1[3],p2[3];
00751 
00752   rdf_tmp = malloc(r_bins*sizeof(double));
00753 
00754   if(n_p1 == n_p2) {
00755     for(i=0;i<n_p1;i++)
00756       if( p1_types[i] != p2_types[i] ) mixed_flag=1;
00757   }
00758   else mixed_flag=1;
00759   bin_width     = (r_max-r_min) / (double)r_bins;
00760   inv_bin_width = 1.0 / bin_width;
00761   volume = box_l[0]*box_l[1]*box_l[2];
00762   for(l=0;l<r_bins;l++) rdf_tmp[l]=rdf[l] = 0.0;
00763 
00764   while(cnt_conf<=n_conf) {
00765     for(l=0;l<r_bins;l++) rdf_tmp[l]=0.0;
00766     cnt=0;
00767     k=n_configs-cnt_conf;
00768     for(i=0; i<n_total_particles; i++) {
00769       for(t1=0; t1<n_p1; t1++) {
00770         if(partCfg[i].p.type == p1_types[t1]) {
00771           // distinguish mixed and identical rdf's
00772           if(mixed_flag == 1) start = 0;
00773           else                start = (i+1);
00774           //particle loop: p2_types
00775           for(j=start; j<n_total_particles; j++) {
00776             for(t2=0; t2<n_p2; t2++) {
00777               if(partCfg[j].p.type == p2_types[t2]) {
00778                 /*see if particles i and j belong to different molecules*/
00779                 if(partCfg[i].p.mol_id!=partCfg[j].p.mol_id) {
00780                   p1[0]=configs[k][3*i  ];p1[1]=configs[k][3*i+1];p1[2]=configs[k][3*i+2];
00781                   p2[0]=configs[k][3*j  ];p2[1]=configs[k][3*j+1];p2[2]=configs[k][3*j+2];
00782                   dist =min_distance(p1, p2);
00783                   if(dist > r_min && dist < r_max) {
00784                     ind = (int) ( (dist - r_min)*inv_bin_width );
00785                     rdf_tmp[ind]++;
00786                   }
00787                   cnt++;
00788                 }
00789               }
00790             }
00791           }
00792         }
00793       }
00794     }
00795     // normalization
00796 
00797     for(i=0; i<r_bins; i++) {
00798       r_in       = i*bin_width + r_min;
00799       r_out      = r_in + bin_width;
00800       bin_volume = (4.0/3.0) * PI * ((r_out*r_out*r_out) - (r_in*r_in*r_in));
00801       rdf[i] += rdf_tmp[i]*volume / (bin_volume * cnt);
00802     }
00803 
00804     cnt_conf++;
00805   } //cnt_conf loop
00806   for(i=0; i<r_bins; i++) {
00807     rdf[i] /= (cnt_conf-1);
00808   }
00809   free(rdf_tmp);
00810 
00811 }
00812 
00813 /*addes this line*/
00814 void calc_rdf_adress(int *p1_types, int n_p1, int *p2_types, int n_p2,
00815                            double x_min, double x_max, double r_min, double r_max, int r_bins, double *rdf, int n_conf)
00816 {
00817   int i,j,k,l,t1,t2,ind,cnt=0,cnt_conf=1;
00818   int mixed_flag=0,start;
00819   double inv_bin_width=0.0,bin_width=0.0, dist;
00820   double volume, bin_volume, r_in, r_out;
00821   double *rdf_tmp, p1[3],p2[3];
00822 
00823   rdf_tmp = malloc(r_bins*sizeof(double));
00824 
00825   if(n_p1 == n_p2) {
00826     for(i=0;i<n_p1;i++)
00827       if( p1_types[i] != p2_types[i] ) mixed_flag=1;
00828   }
00829   else mixed_flag=1;
00830   bin_width     = (r_max-r_min) / (double)r_bins;
00831   inv_bin_width = 1.0 / bin_width;
00832   volume = (x_max-x_min)*box_l[1]*box_l[2];
00833   //volume = box_l[0]*box_l[1]*box_l[2];
00834   for(l=0;l<r_bins;l++) rdf_tmp[l]=rdf[l] = 0.0;
00835 
00836   while(cnt_conf<=n_conf) {
00837     for(l=0;l<r_bins;l++) rdf_tmp[l]=0.0;
00838     cnt=0;
00839     k=n_configs-cnt_conf;
00840     for(i=0; i<n_total_particles; i++) {
00841       for(t1=0; t1<n_p1; t1++) {
00842         if(partCfg[i].p.type == p1_types[t1]) {
00843           //accepts particles i's contained in explicit region 
00844           if(configs[k][3*i]<x_max && configs[k][3*i]>=x_min) {
00845           // distinguish mixed and identical rdf's
00846           if(mixed_flag == 1) start = 0;
00847           else                start = (i+1);
00848           //particle loop: p2_types
00849           for(j=start; j<n_total_particles; j++) {
00850             for(t2=0; t2<n_p2; t2++) {
00851               if(partCfg[j].p.type == p2_types[t2]) {
00852                 //accepts particles j's contained in explicit region 
00853                 if(configs[k][3*j]<x_max && configs[k][3*j]>=x_min) {
00854                 /*see if particles i and j belong to different molecules*/
00855                 if(partCfg[i].p.mol_id!=partCfg[j].p.mol_id) {
00856                   p1[0]=configs[k][3*i  ];p1[1]=configs[k][3*i+1];p1[2]=configs[k][3*i+2];
00857                   p2[0]=configs[k][3*j  ];p2[1]=configs[k][3*j+1];p2[2]=configs[k][3*j+2];
00858                   dist =min_distance(p1, p2);
00859                   if(dist > r_min && dist < r_max) {
00860                     ind = (int) ( (dist - r_min)*inv_bin_width );
00861                     rdf_tmp[ind]++;
00862                   }
00863                   cnt++;
00864                 }
00865               }
00866              }
00867             }
00868           }
00869         }
00870         }
00871       }
00872     }
00873     // normalization
00874 
00875     for(i=0; i<r_bins; i++) {
00876       r_in       = i*bin_width + r_min;
00877       r_out      = r_in + bin_width;
00878       bin_volume = (4.0/3.0) * PI * ((r_out*r_out*r_out) - (r_in*r_in*r_in));
00879       rdf[i] += rdf_tmp[i]*volume / (bin_volume * cnt);
00880     }
00881 
00882     cnt_conf++;
00883   } //cnt_conf loop
00884   for(i=0; i<r_bins; i++) {
00885     rdf[i] /= (cnt_conf-1);
00886   }
00887   free(rdf_tmp);
00888 
00889 }
00890 /*Up to here*/
00891 
00892 void calc_structurefactor(int type, int order, double **_ff) {
00893   int i, j, k, n, qi, p, order2;
00894   double qr, twoPI_L, C_sum, S_sum, *ff=NULL;
00895   
00896   order2 = order*order;
00897   *_ff = ff = realloc(ff,2*order2*sizeof(double));
00898   twoPI_L = 2*PI/box_l[0];
00899   
00900   if ((type < 0) || (type > n_particle_types)) { fprintf(stderr,"WARNING: Type %i does not exist!",type); fflush(NULL); errexit(); }
00901   else if (order < 1) { fprintf(stderr,"WARNING: parameter \"order\" has to be a whole positive number"); fflush(NULL); errexit(); }
00902   else {
00903     for(qi=0; qi<2*order2; qi++) {
00904       ff[qi] = 0.0;
00905     }
00906     for(i=0; i<=order; i++) {
00907       for(j=-order; j<=order; j++) {
00908         for(k=-order; k<=order; k++) {
00909           n = i*i + j*j + k*k;
00910           if ((n<=order2) && (n>=1)) {
00911             C_sum = S_sum = 0.0;
00912             for(p=0; p<n_total_particles; p++) {
00913               if (partCfg[p].p.type == type) {
00914                 qr = twoPI_L * ( i*partCfg[p].r.p[0] + j*partCfg[p].r.p[1] + k*partCfg[p].r.p[2] );
00915                 C_sum+= cos(qr);
00916                 S_sum+= sin(qr);
00917               }
00918             }
00919             ff[2*n-2]+= C_sum*C_sum + S_sum*S_sum;
00920             ff[2*n-1]++;
00921           }
00922         }
00923       }
00924     }
00925     n = 0;
00926     for(p=0; p<n_total_particles; p++) {
00927       if (partCfg[p].p.type == type) n++;
00928     }
00929     for(qi=0; qi<order2; qi++) 
00930       if (ff[2*qi+1]!=0) ff[2*qi]/= n*ff[2*qi+1];
00931   }
00932 }
00933 
00934 //calculates average density profile in dir direction over last n_conf configurations
00935 void density_profile_av(int n_conf, int n_bin, double density, int dir, double *rho_ave, int type)
00936 {
00937   int i,j,k,m,n;
00938   double r;
00939   double r_bin;
00940   double pos[3];
00941   int  image_box[3];
00942   
00943   //calculation over last n_conf configurations  
00944   
00945   //bin width
00946   r_bin = box_l[dir]/(double)(n_bin);
00947   
00948   for (i=0; i<n_bin; i++)
00949     rho_ave[i]=0;
00950   
00951   k=n_configs-n_conf;
00952   
00953   while(k<n_configs) {
00954     r = 0;
00955     j = 0;
00956     while (r < box_l[dir]) { 
00957       n = 0;
00958       for(i=0; i<n_total_particles; i++) {
00959         //com particles
00960         if(partCfg[i].p.type == type) {
00961           for(m=0; m<3; m++) {
00962             pos[m] = configs[k][3*i+m];
00963             image_box[m] = 0;
00964           }
00965           fold_coordinate(pos, image_box, dir);
00966           if (pos[dir] <= r+r_bin && pos[dir] > r)
00967             n++;
00968         }
00969       }
00970       
00971       rho_ave[j] += (double)(n)/(box_l[1]*box_l[2]*r_bin)/density;
00972       j++;
00973       r += r_bin;
00974     }     
00975     k++;
00976   } //k loop
00977   
00978   // normalization
00979   for (i=0; i<n_bin; i++)
00980     rho_ave[i]/=n_conf;
00981 }
00982 
00983 void calc_diffusion_profile(int dir, double xmin, double xmax, int nbins, int n_part, int n_conf, int time, int type, double *bins) 
00984 {
00985   int i,t, count,index;
00986   double tcount=0;
00987   double xpos;
00988   double tpos[3];
00989   int img_box[3] = {0,0,0};
00990   //double delta_x = (box_l[0])/((double) nbins);
00991   
00992   /* create and initialize the array of bins */
00993   
00994   // double *bins;
00995   
00996   int *label;
00997   label = malloc(n_part*sizeof(int));
00998   
00999   /* calculation over last n_conf configurations */
01000   t=n_configs-n_conf;
01001   
01002   while (t<n_configs-time) {
01003     /* check initial condition */
01004     count = 0;
01005     
01006     for (i=0;i<n_total_particles;i++) {
01007       if(partCfg[i].p.type == type) {
01008         tpos[0] = configs[t][3*i];
01009         tpos[1] = configs[t][3*i+1];
01010         tpos[2] = configs[t][3*i+2];
01011         fold_coordinate(tpos, img_box,dir);
01012         xpos = tpos[dir];
01013         if(xpos > xmin && xpos < xmax) {
01014           label[count] = i;
01015         }
01016         else label[count] = -1;
01017         count ++;
01018       }
01019     }
01020     
01021     /* check at time 'time' */
01022     for (i=0;i<n_part;i++) {
01023       if (label[i]>0) {
01024         tpos[0] = configs[t+time][3*label[i]];
01025         tpos[1] = configs[t+time][3*label[i]+1];
01026         tpos[2] = configs[t+time][3*label[i]+2];
01027         fold_coordinate(tpos, img_box,dir);
01028         xpos = tpos[dir];
01029         
01030         index = (int)(xpos/box_l[dir]*nbins);
01031         bins[index]++;
01032       }
01033     }
01034     t++;
01035     tcount++;
01036   }
01037   
01038   /* normalization */
01039   for (i=0;i<nbins;i++) {
01040     bins[i]=bins[i]/(tcount);
01041   }
01042   free(label);
01043 }
01044 
01045 
01046 int calc_radial_density_map (int xbins,int ybins,int thetabins,double xrange,double yrange, double axis[3], double center[3], IntList *beadids, DoubleList *density_map, DoubleList *density_profile) {
01047   int i,j,t;
01048   int pi,bi;
01049   int nbeadtypes;
01050   int beadcount;
01051   double vectprod[3];
01052   double pvector[3];
01053   double xdist,ydist,rdist,xav,yav,theta;
01054   double xbinwidth,ybinwidth,binvolume;
01055   double thetabinwidth;
01056   double *thetaradii;
01057   int *thetacounts;
01058   int xindex,yindex,tindex;
01059   xbinwidth = xrange/(double)(xbins);
01060   ybinwidth = yrange/(double)(ybins);
01061 
01062   nbeadtypes = beadids->n;
01063   /* Update particles */
01064   updatePartCfg(WITHOUT_BONDS);
01065 
01066   /*Make sure particles are folded  */
01067   for (i = 0 ; i < n_total_particles ; i++) {
01068     fold_coordinate(partCfg[i].r.p,partCfg[i].l.i,0);
01069     fold_coordinate(partCfg[i].r.p,partCfg[i].l.i,1);
01070     fold_coordinate(partCfg[i].r.p,partCfg[i].l.i,2);
01071   }
01072 
01073   beadcount = 0;
01074   xav = 0.0;
01075   yav = 0.0;
01076   for ( pi = 0 ; pi < n_total_particles ; pi++ ) {
01077     for ( bi = 0 ; bi < nbeadtypes ; bi++ ) {
01078       if ( beadids->e[bi] == partCfg[pi].p.type ) {
01079 
01080 
01081         /* Find the vector from the point to the center */
01082         vecsub(center,partCfg[pi].r.p,pvector);
01083 
01084         /* Work out x and y coordinates with respect to rotation axis */
01085         
01086         /* Find the minimum distance of the point from the axis */
01087         vector_product(axis,pvector,vectprod);
01088         xdist = sqrt(sqrlen(vectprod)/sqrlen(axis));
01089 
01090         /* Find the projection of the vector from the point to the center
01091            onto the axis vector */
01092         ydist = scalar(axis,pvector)/sqrt(sqrlen(axis));
01093         
01094     
01095         /* Work out relevant indices for x and y */
01096         xindex = (int)(floor(xdist/xbinwidth));
01097         yindex = (int)(floor((ydist+yrange*0.5)/ybinwidth));
01098         /*
01099         printf("x %d y %d \n",xindex,yindex);
01100         printf("p %f %f %f \n",partCfg[pi].r.p[0],partCfg[pi].r.p[1],partCfg[pi].r.p[2]);
01101         printf("pvec %f %f %f \n",pvector[0],pvector[1],pvector[2]);
01102         printf("axis %f %f %f \n",axis[0],axis[1],axis[2]);
01103         printf("dists %f %f \n",xdist,ydist);
01104         fflush(stdout);
01105         */
01106         /* Check array bounds */
01107         if ( (xindex < xbins && xindex > 0) && (yindex < ybins && yindex > 0) ) {
01108           density_map[bi].e[ybins*xindex+yindex] += 1;
01109           xav += xdist;
01110           yav += ydist;
01111           beadcount += 1;
01112         } else {
01113           //        fprintf(stderr,"ERROR: outside array bounds in calc_radial_density_map"); fflush(NULL); errexit(); 
01114         }
01115       }
01116 
01117     }
01118   }
01119 
01120 
01121   /* Now turn counts into densities for the density map */
01122   for ( bi = 0 ; bi < nbeadtypes ; bi++ ) {
01123     for ( i = 0 ; i < xbins ; i++ ) {
01124       /* All bins are cylinders and therefore constant in yindex */
01125       binvolume = PI*(2*i*xbinwidth + xbinwidth*xbinwidth)*yrange;
01126       for ( j = 0 ; j < ybins ; j++ ) {
01127         density_map[bi].e[ybins*i+j] /= binvolume;
01128       }
01129     }
01130   }
01131 
01132 
01133   /* if required calculate the theta density profile */
01134   if ( thetabins > 0 ) {
01135     /* Convert the center to an output of the density center */
01136     xav = xav/(double)(beadcount);
01137     yav = yav/(double)(beadcount);
01138     thetabinwidth = 2*PI/(double)(thetabins);
01139     thetaradii = malloc(thetabins*nbeadtypes*sizeof(double));
01140     thetacounts = malloc(thetabins*nbeadtypes*sizeof(int));
01141     for ( bi = 0 ; bi < nbeadtypes ; bi++ ) {
01142       for ( t = 0 ; t < thetabins ; t++ ) {
01143         thetaradii[bi*thetabins+t] = 0.0;
01144         thetacounts[bi*thetabins+t] = 0.0;
01145       }
01146     }
01147     /* Maybe there is a nicer way to do this but now I will just repeat the loop over all particles */
01148       for ( pi = 0 ; pi < n_total_particles ; pi++ ) {
01149         for ( bi = 0 ; bi < nbeadtypes ; bi++ ) {
01150           if ( beadids->e[bi] == partCfg[pi].p.type ) {
01151             vecsub(center,partCfg[pi].r.p,pvector);
01152             vector_product(axis,pvector,vectprod);
01153             xdist = sqrt(sqrlen(vectprod)/sqrlen(axis));
01154             ydist = scalar(axis,pvector)/sqrt(sqrlen(axis));
01155             /* Center the coordinates */
01156 
01157             xdist = xdist - xav;
01158             ydist = ydist - yav;
01159             rdist = sqrt(xdist*xdist+ydist*ydist);
01160             if ( ydist >= 0 ) {
01161               theta = acos(xdist/rdist);
01162             } else {
01163               theta = 2*PI-acos(xdist/rdist);
01164             }
01165             tindex = (int)(floor(theta/thetabinwidth));
01166             thetaradii[bi*thetabins+tindex] += xdist + xav;
01167             thetacounts[bi*thetabins+tindex] += 1;
01168             if ( tindex >= thetabins ) {
01169               fprintf(stderr,"ERROR: outside density_profile array bounds in calc_radial_density_map"); fflush(NULL); errexit(); 
01170             } else {
01171               density_profile[bi].e[tindex] += 1;
01172             }
01173           }       
01174         }
01175       }
01176 
01177 
01178 
01179       /* normalize the theta densities*/
01180       for ( bi = 0 ; bi < nbeadtypes ; bi++ ) {
01181         for ( t = 0 ; t < thetabins ; t++ ) {
01182           rdist = thetaradii[bi*thetabins+t]/(double)(thetacounts[bi*thetabins+t]);
01183           density_profile[bi].e[t] /= rdist*rdist;
01184         }
01185       }
01186        
01187 
01188 
01189       free(thetaradii);
01190       free(thetacounts);
01191 
01192   }
01193   
01194 
01195 
01196 
01197 
01198 
01199 
01200   //  printf("done \n");
01201   return ES_OK;
01202 }
01203 
01204 double calc_vanhove(int ptype, double rmin, double rmax, int rbins, int tmax, double *msd, double **vanhove) 
01205 {
01206   int i, c1, c3, c3_max, ind, np=0;
01207   double p1[3],p2[3],dist;
01208   double bin_width, inv_bin_width;
01209   IntList p;
01210 
01211   /* create particle list */
01212   init_intlist(&p);
01213   for(i=0; i<n_total_particles; i++) { if( partCfg[i].p.type == ptype ) { np ++; } }
01214   if(np==0) { return 0; }
01215   alloc_intlist(&p,np);
01216   for(i=0; i<n_total_particles; i++) { if( partCfg[i].p.type == ptype ) { p.e[p.n]=i; p.n++; } }
01217 
01218   /* preparation */
01219   bin_width     = (rmax-rmin) / (double)rbins;
01220   inv_bin_width = 1.0 / bin_width;
01221  
01222   /* calculate msd and store distribution in vanhove */
01223   for(c1=0; c1<n_configs; c1++) { 
01224     c3_max=(c1+tmax+1)>n_configs ? n_configs : c1+tmax+1;
01225     for(c3=(c1+1); c3<c3_max; c3++) { 
01226       for(i=0; i<p.n; i++) {
01227         p1[0]=configs[c1][3*p.e[i] ]; p1[1]=configs[c1][3*p.e[i]+1]; p1[2]=configs[c1][3*p.e[i]+2];
01228         p2[0]=configs[c3][3*p.e[i]  ]; p2[1]=configs[c3][3*p.e[i]+1]; p2[2]=configs[c3][3*p.e[i]+2];
01229         dist = distance(p1, p2);
01230         if(dist > rmin && dist < rmax) {
01231           ind = (int) ( (dist - rmin)*inv_bin_width );
01232           vanhove[(c3-c1-1)][ind]++;
01233         }
01234         msd[(c3-c1-1)] += dist*dist;
01235       }
01236     }
01237   }
01238 
01239   /* normalize */
01240   for(c1=0; c1<(tmax); c1++) { 
01241     for(i=0; i<rbins; i++) { vanhove[c1][i] /= (double) (n_configs-c1-1)*p.n; }
01242     msd[c1] /= (double) (n_configs-c1-1)*p.n;
01243   }
01244 
01245   realloc_intlist(&p,0);
01246   return np;
01247 }
01248 
01249 /****************************************************************************************
01250  *                                 config storage functions
01251  ****************************************************************************************/
01252 
01253 void analyze_append() {
01254   int i;
01255   n_part_conf = n_total_particles;
01256   configs = realloc(configs,(n_configs+1)*sizeof(double *));
01257   configs[n_configs] = (double *) malloc(3*n_part_conf*sizeof(double));
01258   for(i=0; i<n_part_conf; i++) {
01259     configs[n_configs][3*i]   = partCfg[i].r.p[0];
01260     configs[n_configs][3*i+1] = partCfg[i].r.p[1];
01261     configs[n_configs][3*i+2] = partCfg[i].r.p[2];
01262   }
01263   n_configs++;
01264 }
01265 
01266 void analyze_push() {
01267   int i;
01268   n_part_conf = n_total_particles;
01269   free(configs[0]);
01270   for(i=0; i<n_configs-1; i++) {
01271     configs[i]=configs[i+1];
01272   }
01273   configs[n_configs-1] = (double *) malloc(3*n_part_conf*sizeof(double));
01274   for(i=0; i<n_part_conf; i++) {
01275     configs[n_configs-1][3*i]   = partCfg[i].r.p[0];
01276     configs[n_configs-1][3*i+1] = partCfg[i].r.p[1];
01277     configs[n_configs-1][3*i+2] = partCfg[i].r.p[2];
01278   }
01279 }
01280 
01281 void analyze_replace(int ind) {
01282   int i;
01283   n_part_conf = n_total_particles;
01284   for(i=0; i<n_part_conf; i++) {
01285     configs[ind][3*i]   = partCfg[i].r.p[0];
01286     configs[ind][3*i+1] = partCfg[i].r.p[1];
01287     configs[ind][3*i+2] = partCfg[i].r.p[2];
01288   }
01289 }
01290 
01291 void analyze_remove(int ind) {
01292   int i;
01293   free(configs[ind]);
01294   for(i=ind; i<n_configs-1; i++) {
01295     configs[i]=configs[i+1];
01296   }
01297   n_configs--;
01298   configs = realloc(configs,n_configs*sizeof(double *));
01299   if (n_configs == 0) n_part_conf = 0;
01300 }
01301 
01302 void analyze_configs(double *tmp_config, int count) {
01303   int i;
01304   n_part_conf = count;
01305   configs = realloc(configs,(n_configs+1)*sizeof(double *));
01306   configs[n_configs] = (double *) malloc(3*n_part_conf*sizeof(double));
01307   for(i=0; i<n_part_conf; i++) {
01308     configs[n_configs][3*i]   = tmp_config[3*i];
01309     configs[n_configs][3*i+1] = tmp_config[3*i+1];
01310     configs[n_configs][3*i+2] = tmp_config[3*i+2];
01311   }
01312   n_configs++;
01313 }
01314 
01315 void analyze_activate(int ind) {
01316   int i;
01317   double pos[3];
01318   n_part_conf = n_total_particles;
01319 
01320   for(i=0; i<n_part_conf; i++) {
01321     pos[0] = configs[ind][3*i];
01322     pos[1] = configs[ind][3*i+1];
01323     pos[2] = configs[ind][3*i+2];
01324     if (place_particle(i, pos)==ES_ERROR) {
01325       char *errtxt = runtime_error(128 + ES_INTEGER_SPACE);
01326       ERROR_SPRINTF(errtxt, "{057 failed upon replacing particle %d in Espresso} ", i); 
01327     }
01328   }
01329 }
01330 
01331 
01332 /****************************************************************************************
01333  *                                 Observables handling
01334  ****************************************************************************************/
01335 
01336 void obsstat_realloc_and_clear(Observable_stat *stat, int n_pre, int n_bonded, int n_non_bonded,
01337                                int n_coulomb, int n_dipolar, int c_size)
01338 {
01339   int i, total = c_size*(n_pre + n_bonded_ia + n_non_bonded + n_coulomb + n_dipolar);
01340 
01341   realloc_doublelist(&(stat->data), stat->data.n = total);
01342   stat->chunk_size = c_size;
01343   stat->n_coulomb    = n_coulomb;
01344   stat->n_dipolar    = n_dipolar;
01345   stat->n_non_bonded = n_non_bonded;
01346   stat->bonded     = stat->data.e + c_size*n_pre;
01347   stat->non_bonded = stat->bonded + c_size*n_bonded_ia;
01348   stat->coulomb    = stat->non_bonded + c_size*n_non_bonded;
01349   stat->dipolar    = stat->coulomb    + c_size*n_coulomb;
01350 
01351   for(i = 0; i < total; i++)
01352     stat->data.e[i] = 0.0;
01353 }
01354 
01355 void obsstat_realloc_and_clear_non_bonded(Observable_stat_non_bonded *stat_nb, int n_nonbonded, int c_size)
01356 {
01357   int i, total = c_size*(n_nonbonded + n_nonbonded);
01358 
01359   realloc_doublelist(&(stat_nb->data_nb), stat_nb->data_nb.n = total);
01360   stat_nb->chunk_size_nb = c_size;
01361   stat_nb->n_nonbonded = n_nonbonded;
01362   stat_nb->non_bonded_intra = stat_nb->data_nb.e;
01363   stat_nb->non_bonded_inter = stat_nb->non_bonded_intra + c_size*n_nonbonded;
01364   
01365   for(i = 0; i < total; i++)
01366     stat_nb->data_nb.e[i] = 0.0;
01367 }
01368 
01369 void invalidate_obs()
01370 {
01371   total_energy.init_status = 0;
01372   total_pressure.init_status = 0;
01373 }
01374 
01375 
01376   //subfunction: mark all neighbors of a particle and their neighbors (recursiv!)
01377 void mark_neighbours(int type,int pa_nr,double dist,int *list){
01378   int k;
01379   for (k=0;k<n_total_particles;k++){
01380      //only unmarked and particles with right distance
01381      if ( (partCfg[k].p.type == type) && (list[k] == 0) && (min_distance(partCfg[pa_nr].r.p,partCfg[k].r.p) < dist) ){
01382         //mark particle with same number as calling particle
01383         list[k]=list[pa_nr];
01384         mark_neighbours(type,k,dist,list);
01385      }
01386   }
01387 }
01388 
01389 
01390 void centermass_conf(int k, int type_1, double *com)
01391 {
01392   int i, j;
01393   double M = 0.0;
01394   com[0]=com[1]=com[2]=0.;
01395 
01396   for (j=0; j<n_total_particles; j++) {
01397     if ((partCfg[j].p.type == type_1) || (type_1 == -1))
01398     {
01399       for (i=0; i<3; i++)
01400       {
01401          com[i] += configs[k][3*j+i]*PMASS(partCfg[j]);
01402       }
01403       M += PMASS(partCfg[j]);
01404     }
01405   }
01406   for (i=0; i<3; i++) 
01407   {
01408     com[i] /= M;
01409   }
01410   return;
01411 }