Example #1
0
/* Get a complete list of the orientations of every lipid assuming a
   bilayer structure.  Requires grid*/
int get_lipid_orients(IntList* l_orient) {
  int i,gi,gj, atom;
  double zreflocal,zref;  
  double dir[3];
  double refdir[3] = {0,0,1};
  double grid_size[2];

  double* height_grid;

  if ( xdir + ydir + zdir == -3 || mode_grid_3d[xdir] <= 0 || mode_grid_3d[ydir] <= 0 ) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt,"{036 cannot calculate lipid orientations with uninitialized grid} ");
    return ES_ERROR;
  }

  /* Allocate memory for height grid arrays and initialize these arrays */
  height_grid = (double*) malloc((mode_grid_3d[xdir])*sizeof(double)*mode_grid_3d[ydir]);


  /* Calculate physical size of grid mesh */
  grid_size[xdir] = box_l[xdir]/(double)mode_grid_3d[xdir];
  grid_size[ydir] = box_l[ydir]/(double)mode_grid_3d[ydir];


  /* Update particles */
  updatePartCfg(WITHOUT_BONDS);
  //Make sure particles are sorted
  if (!sortPartCfg()) {
    fprintf(stderr,"%d,could not sort partCfg \n",this_node);
    return -1;
  }
  
  if ( !calc_fluctuations(height_grid, 1) ) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt,"{034 calculation of height grid failed } ");
    return -1;
  }

  zref = calc_zref( zdir );

  for ( i = 0 ; i < n_molecules ; i++) {
    atom = topology[i].part.e[0];
    gi = floor( partCfg[atom].r.p[xdir]/grid_size[xdir] );
    gj = floor( partCfg[atom].r.p[ydir]/grid_size[ydir] );
    zreflocal = height_grid[gj+gi*mode_grid_3d[xdir]] + zref;
    l_orient->e[i] = lipid_orientation(atom,partCfg,zreflocal,dir,refdir);
  }

  free(height_grid);

  return 1;
}
Example #2
0
int calc_fluctuations ( double* height_grid, int switch_fluc ) {
  if (switch_fluc == 1){
    STAT_TRACE(fprintf(stderr,"%d,calculating height grid \n",this_node));
  } else { if (switch_fluc == 0) {
    STAT_TRACE(fprintf(stderr,"%d,calculating thickness \n",this_node));
    } else {
       char *errtxt = runtime_error(128);
       ERROR_SPRINTF(errtxt,"{097 Wrong argument in calc_fluctuations function} ");
       return -1;
    }
  }
    
  int i, j, gi, gj;
  double grid_size[2];
  double direction[3];  
  double refdir[3] = {0,0,1};
  double* height_grid_up;
  double* height_grid_down;
  int* grid_parts;
  int* grid_parts_up;
  int* grid_parts_down;
  double zreflocal, zref;
  int nup;
  int ndown;
  int nstray;
  int nrealstray;
  int l_orient;
  double norm;
  int xi, yi;
  double meanval;
  int nonzerocnt, gapcnt;






  if ( xdir + ydir + zdir == -3 ) {
      char *errtxt = runtime_error(128);
      ERROR_SPRINTF(errtxt,"{092 attempt to calculate height grid / thickness with uninitialized grid} ");
      return -1;
  }
  

  if ( height_grid == NULL ) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt,"{093 you must allocate memory for the height grid / thickness first} ");
    return -1;
  }



  /* Allocate memory for height grid / thickness arrays and initialize these arrays */

  height_grid_up = (double*) malloc((mode_grid_3d[xdir])*sizeof(double)*mode_grid_3d[ydir]);
  height_grid_down = (double*) malloc((mode_grid_3d[xdir])*sizeof(double)*mode_grid_3d[ydir]);
  grid_parts_up = (int*) malloc((mode_grid_3d[xdir])*sizeof(int)*mode_grid_3d[ydir]);
  grid_parts_down = (int*) malloc((mode_grid_3d[xdir])*sizeof(int)*mode_grid_3d[ydir]);
  grid_parts = (int*) malloc((mode_grid_3d[xdir])*sizeof(int)*mode_grid_3d[ydir]);
  for ( i = 0 ; i < mode_grid_3d[xdir] ; i++) {
    for ( j = 0 ; j < mode_grid_3d[ydir] ; j++) {
      height_grid[j+i*mode_grid_3d[xdir]] = 0;
      grid_parts[j+i*mode_grid_3d[xdir]] = 0;
      height_grid_up[j+i*mode_grid_3d[xdir]] = 0;
      grid_parts_up[j+i*mode_grid_3d[xdir]] = 0;
      height_grid_down[j+i*mode_grid_3d[xdir]] = 0;
      grid_parts_down[j+i*mode_grid_3d[xdir]] = 0;
    }
  }
  
  /* Calculate physical size of grid mesh */
  grid_size[xdir] = box_l[xdir]/(double)mode_grid_3d[xdir];
  grid_size[ydir] = box_l[ydir]/(double)mode_grid_3d[ydir];
  
  /* Update particles */
  updatePartCfg(WITHOUT_BONDS);
  //Make sure particles are sorted
  if (!sortPartCfg()) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt,"{094 could not sort partCfg} ");
    return -1;
  }
  
  
  
  /* Find the mean z position of folded coordinates*/ 
  zref = calc_zref( zdir );
  
  /* Calculate an initial height function of all particles */
  for (i = 0 ; i < n_total_particles ; i++) {
    gi = floor( partCfg[i].r.p[xdir]/grid_size[xdir] );
    gj = floor( partCfg[i].r.p[ydir]/grid_size[ydir] );
    height_grid[gj + gi*mode_grid_3d[xdir]] += partCfg[i].r.p[zdir];
    grid_parts[gj + gi*mode_grid_3d[xdir]] += 1;
  }
  
  /* Normalise the initial height function */
  for ( i = 0 ; i < mode_grid_3d[xdir] ; i++) {
    for ( j = 0 ; j < mode_grid_3d[ydir] ; j++) {
      if ( grid_parts[j+i*mode_grid_3d[xdir]] > 0 ) {
	height_grid[j+i*mode_grid_3d[xdir]] = height_grid[j+i*mode_grid_3d[xdir]]/(double)(grid_parts[j+i*mode_grid_3d[xdir]]);
      } else {
	height_grid[j+i*mode_grid_3d[xdir]] = zref;
      }
    }
  }
  
  /* We now use this initial height function to calculate the
     lipid_orientation and thereby calculate populations in upper and
     lower leaflets */
  
  
  /* Calculate the non normalized height function based on all lipids */
  nup = ndown = nstray = nrealstray = 0;
  for (i = 0 ; i < n_total_particles ; i++) {
    gi = floor( partCfg[i].r.p[xdir]/grid_size[xdir] );
    gj = floor( partCfg[i].r.p[ydir]/grid_size[ydir] );
    
    zreflocal = height_grid[gj+gi*mode_grid_3d[xdir]];
    
    l_orient = lipid_orientation(i,partCfg,zreflocal,direction,refdir);
    
    if ( l_orient != LIPID_STRAY && l_orient != REAL_LIPID_STRAY) {
      if ( l_orient == LIPID_UP ) {
	nup++;
	height_grid_up[gj + gi*mode_grid_3d[xdir]] += partCfg[i].r.p[zdir] - zref;
	grid_parts_up[gj + gi*mode_grid_3d[xdir]] += 1;
      } else if ( l_orient == LIPID_DOWN ) {
	ndown++;
	height_grid_down[gj + gi*mode_grid_3d[xdir]] += partCfg[i].r.p[zdir] - zref;
	grid_parts_down[gj + gi*mode_grid_3d[xdir]] += 1;
      }
    } else {
      if ( l_orient == REAL_LIPID_STRAY ) {
	nrealstray++;
      }
    }
  }



  /*
    if ( nrealstray > 0 || nstray > 0) {
    printf("Warning: there were %d stray lipid particles in height calculation \n", nrealstray);
    }
    printf(" Lipid particles up = %d , Lipid particles down = %d \n",nup, ndown); */
  
  STAT_TRACE(fprintf(stderr,"%d, Lipids up = %d , Lipids down = %d \n",this_node, nup, ndown));
  
  /* Reinitialise the height grid */
  for ( i = 0 ; i < mode_grid_3d[xdir] ; i++) {
    for ( j = 0 ; j < mode_grid_3d[ydir] ; j++) {
      height_grid[j+i*mode_grid_3d[xdir]] = 0.0;
      grid_parts[j+i*mode_grid_3d[xdir]] = 0;
    }
  }
  
  /* Norm we normalize the height function according the number of
     points in each grid cell */
  norm = 1.0;
  for ( i = 0 ; i < mode_grid_3d[xdir] ; i++) {
    for ( j = 0 ; j < mode_grid_3d[ydir] ; j++) {
      
      if ( ( grid_parts_up[j + i*mode_grid_3d[xdir]] > 0 ) && ( grid_parts_down[j + i*mode_grid_3d[xdir]] > 0 ) ) {
	/* 
	   This is where we distinguish between height_grid and thickness:
	   h = .5*(h_up + h_down)
	   t = h_up - h_down
	*/
	if (switch_fluc == 1)
	  height_grid[j+i*mode_grid_3d[xdir]] = 
	    0.5*norm*((height_grid_up[j+i*mode_grid_3d[xdir]])/(double)(grid_parts_up[j + i*mode_grid_3d[xdir]]) + 
		      (height_grid_down[j+i*mode_grid_3d[xdir]])/(double)(grid_parts_down[j + i*mode_grid_3d[xdir]]));
	else
	  height_grid[j+i*mode_grid_3d[xdir]] = 
	    norm*((height_grid_up[j+i*mode_grid_3d[xdir]])/(double)(grid_parts_up[j + i*mode_grid_3d[xdir]]) - 
		  (height_grid_down[j+i*mode_grid_3d[xdir]])/(double)(grid_parts_down[j + i*mode_grid_3d[xdir]]));

	grid_parts[j+i*mode_grid_3d[xdir]] = grid_parts_up[j + i*mode_grid_3d[xdir]] + grid_parts_down[j + i*mode_grid_3d[xdir]];
      } else {
	// Either upper or lower layer has no lipids
	
	

	height_grid[j+i*mode_grid_3d[xdir]] = 0.0;
	grid_parts[j+i*mode_grid_3d[xdir]] = 0;
      }
    }
  }
  
  
  /* Check height grid for zero values and substitute mean of surrounding cells */
  gapcnt = 0;
  for ( i = 0 ; i < mode_grid_3d[xdir] ; i++) {
    for ( j = 0 ; j < mode_grid_3d[ydir] ; j++) {
      if ( grid_parts[j + i*mode_grid_3d[xdir]] ==  0) {
	meanval = 0.0;
	nonzerocnt = 0;
	for ( xi = (i-1) ; xi <= (i+1) ; xi++) {
	  for ( yi = (j-1) ; yi <= (j+1) ; yi++) {
	    if ( height_grid[yi+xi*mode_grid_3d[xdir]] != 0 ) {
	      meanval += height_grid[yi+xi*mode_grid_3d[xdir]];
	      nonzerocnt++;
	    }
	  }
	}
	if ( nonzerocnt == 0 ) { 
	  char *errtxt = runtime_error(128);
	  ERROR_SPRINTF(errtxt,"{095 hole in membrane} ");
	  return -1;
	}
	gapcnt++;
      }      
    }
  }
  if ( gapcnt != 0 ) { 
    fprintf(stderr,"Warning: %d, gridpoints with no particles \n",gapcnt);
    fflush(stdout);
  }
  
  free(grid_parts);
  free(height_grid_up);
  free(height_grid_down);
  free(grid_parts_up);
  free(grid_parts_down);
  
  return 1;
  
}
Example #3
0
/** This routine calculates density profiles for given bead types as a
    function of height relative to the bilayer midplane.

    \li First the height function is calculated

    \li The height value of each bead is then calculated relative to
    the overall height function and the population of the relevant bin
    is increased.

**/
int bilayer_density_profile ( IntList *beadids, double hrange , DoubleList *density_profile, int usegrid) {
  int i,j, gi,gj;
  double* tmp_height_grid, zref,zreflocal;
  int thisbin,nbins;
  double grid_size[2];
  double binwidth;
  int nbeadtypes,l_orient;
  double relativeheight;
  double direction[3];  
  double refdir[3] = {0,0,1};
  int tmpzdir;
  double binvolume;
  nbins = density_profile[0].max;
  nbeadtypes=beadids->max;

  /*        Check to see that there is a mode grid to work with    */
  if ( xdir + ydir + zdir == -3 ) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt,"{092 attempt to perform mode analysis with uninitialized grid} ");
    return -1;
  }
  
  /* Allocate memory for the grid if we are going to need it */
  tmp_height_grid = (double*) malloc((mode_grid_3d[xdir])*sizeof(double)*mode_grid_3d[ydir]);
  /* Calculate physical size of grid mesh */
  grid_size[xdir] = box_l[xdir]/(double)mode_grid_3d[xdir];
  grid_size[ydir] = box_l[ydir]/(double)mode_grid_3d[ydir];

  
  /* Calculate the height grid which also ensures that particle config is updated */
  if ( !calc_fluctuations(tmp_height_grid, 1) ) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt,"{034 calculation of height grid failed } ");
    return -1;
  } 
  
  tmpzdir = zdir;


  binwidth = hrange*2.0/(double)(nbins);

  if ( density_profile == NULL ) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt,"{095 density_profile not initialized in calc_bilayer_density_profile } ");
    return -1;
  }

  zref = calc_zref( tmpzdir );

  for (i = 0 ; i < n_total_particles ; i++) {
    for ( j = 0 ; j < nbeadtypes ; j++ ) {
      if ( beadids->e[j] == partCfg[i].p.type ) {

	if ( usegrid ) {
	  /* Where are we on the height grid */
	  gi = (int)(floor( partCfg[i].r.p[xdir]/grid_size[xdir] ));
	  gj = (int)(floor( partCfg[i].r.p[ydir]/grid_size[ydir] ));
	  zreflocal = tmp_height_grid[gj + gi*mode_grid_3d[xdir]] + zref;
	} else {
	  zreflocal = zref;
	}

	/* What is the relative height compared to the grid */
	relativeheight = partCfg[i].r.p[tmpzdir] - zreflocal;							       
	/* If the particle is within our zrange then add it to the profile */
	if ( (relativeheight*relativeheight - hrange*hrange) <= 0 ) {
	  thisbin = (int)(floor((relativeheight + hrange)/binwidth));
	  l_orient = lipid_orientation(i,partCfg,zreflocal,direction,refdir);
	  /* Distinguish between lipids that are in the top and bottom layers */
	  if ( l_orient == LIPID_UP ) {
	    density_profile[j].e[thisbin] += 1.0;
	  }
	  if ( l_orient == LIPID_DOWN ) {
	    density_profile[2*nbeadtypes-j-1].e[thisbin] += 1.0;	    
	  }
	}	    
      }
    }
  }

  /* Normalize the density profile */
  binvolume = binwidth*box_l[xdir]*box_l[ydir];
  for ( i = 0 ; i < 2*nbeadtypes ; i++ ) {
    for ( j = 0 ; j < nbins ; j++ ) {
      density_profile[i].e[j] = density_profile[i].e[j]/binvolume;
    }
  }


  free(tmp_height_grid);

  return 1;
}
Example #4
0
/**
   This routine calculates the orientational order parameter for a
   lipid bilayer.  
*/
int orient_order(double* result, double* stored_dirs)
{
  double dir[3];
  double refdir[3] = {0,0,1};
  double sumdir[3] = {0,0,0};
  double zref;
  int bilayer_cnt;
  int i,atom,tmpzdir;
  double dp;
  double len;

  IntList l_orient;
  init_intlist(&l_orient);
  realloc_intlist(&l_orient, n_molecules);

  bilayer_cnt = 0;
  *result = 0;


  // Check to see if the grid has been set and if not then interpret
  if ( xdir + ydir + zdir == -3 ) {
    tmpzdir = 2;
  } else { 
    tmpzdir = zdir;
  };

  /* Update particles */
  updatePartCfg(WITHOUT_BONDS);
  /* Make sure particles are sorted */
  if (!sortPartCfg()) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt, "{035 could not sort partCfg, particles have to start at 0 and have consecutive identities} ");
    return ES_ERROR;
  }

  /* Calculate the reference z position as its mean.*/
  zref = calc_zref( tmpzdir );
 

  /* Calculate the orientation of all the lipids in turn and include
   only UP or DOWN lipids in a calculation of the overall orientation
   direction of the bilayer .. ie the reference vector from which we
   can calculate the orientational order. */

  for ( i = 0 ; i < n_molecules ; i++) {
    atom = topology[i].part.e[0];
    l_orient.e[i] = lipid_orientation(atom,partCfg,zref,dir,refdir);
    stored_dirs[i*3] = dir[0];
    stored_dirs[i*3+1] = dir[1];
    stored_dirs[i*3+2] = dir[2];

    if ( l_orient.e[i] == LIPID_UP ) {
      sumdir[0] += dir[0];
      sumdir[1] += dir[1];
      sumdir[2] += dir[2];
      bilayer_cnt++;
    }
    if ( l_orient.e[i] == LIPID_DOWN ) {
      sumdir[0] -= dir[0];
      sumdir[1] -= dir[1];
      sumdir[2] -= dir[2];
      bilayer_cnt++;
    }
  }

  /* Normalise the bilayer normal vector */
  len = 0.0;
  for ( i = 0 ; i < 3 ; i++) {
    sumdir[i] = sumdir[i]/(double)(bilayer_cnt);
    len += sumdir[i]*sumdir[i];
  }
  for ( i = 0 ; i < 3 ; i++) {
    sumdir[i] = sumdir[i]/sqrt(len);
  }

  /* Calculate the orientational order */
  for ( i = 0 ; i < n_molecules ; i++ ) {
    dir[0] = stored_dirs[i*3];
    dir[1] = stored_dirs[i*3+1];
    dir[2] = stored_dirs[i*3+2];

    if ( l_orient.e[i] != LIPID_STRAY && l_orient.e[i] != REAL_LIPID_STRAY ) {
      dp = scalar(dir,sumdir);
      *result += dp*dp*1.5-0.5;      
    }

  }

  
  realloc_intlist(&l_orient, 0);

  *result = *result/(double)(bilayer_cnt);
  return ES_OK;
}
Example #5
0
/** This routine performs must of the work involved in the analyze
    modes2d command.  A breakdown of what the routine does is as
    follows

    \li fftw plans and in / out arrays are initialized as required

    \li calculate height function is called

    \li The height function is fourier transformed using the fftw library.

    Note: argument switch_fluc
    switch_fluc == 1 for height grid
    switch_fluc == 0 for thickness
*/
int modes2d(fftw_complex* modes, int switch_fluc) {
  /* All these variables need to be static so that the fftw3 plan can
     be initialised and reused */
  static  fftw_plan mode_analysis_plan; // height grid
  /** Input values for the fft */
  static  double* height_grid;
  /** Output values for the fft */
  static  fftw_complex* result;

  double zref;

  
/** 
    Every time a change is made to the grid calculate the fftw plan
    for the subsequent fft and destroy any existing plans
*/
  if ( mode_grid_changed ) {
    STAT_TRACE(fprintf(stderr,"%d,initializing fftw for mode analysis \n",this_node));
    if ( xdir + ydir + zdir == -3 ) {
      char *errtxt = runtime_error(128);
      ERROR_SPRINTF(errtxt,"{092 attempt to perform mode analysis with uninitialized grid} ");
      return -1;
    }

    STAT_TRACE(fprintf(stderr,"%d,destroying old fftw plan \n",this_node));

    /* Make sure all memory is free and old plan is destroyed. It's ok
       to call these functions on uninitialised pointers I think */
    fftw_free(result);
    fftw_free(height_grid);
    fftw_destroy_plan(mode_analysis_plan);
    fftw_cleanup(); 
    /* Allocate memory for input and output arrays */
    height_grid = malloc((mode_grid_3d[xdir])*sizeof(double)*mode_grid_3d[ydir]);
    result      = malloc((mode_grid_3d[ydir]/2+1)*(mode_grid_3d[xdir])*sizeof(fftw_complex)); 
    mode_analysis_plan = fftw_plan_dft_r2c_2d(mode_grid_3d[xdir],mode_grid_3d[ydir],height_grid, result,FFTW_ESTIMATE);

    STAT_TRACE(fprintf(stderr,"%d,created new fftw plan \n",this_node));
    mode_grid_changed = 0;  
    
  }

  /* Update particles */
  updatePartCfg(WITHOUT_BONDS);
  //Make sure particles are sorted
  if (!sortPartCfg()) {
    fprintf(stderr,"%d,could not sort partCfg \n",this_node);
    return -1;
  }
  
  zref = calc_zref( zdir );

  if ( !calc_fluctuations(height_grid, switch_fluc)) {
    char *errtxt = runtime_error(128);
    ERROR_SPRINTF(errtxt,"{034 calculation of height grid failed } ");
    return -1;
  }

  STAT_TRACE(fprintf(stderr,"%d,calling fftw \n",this_node));

  fftw_execute(mode_analysis_plan);
  /* Copy result to modes */
  memcpy(modes, result, mode_grid_3d[xdir]*(mode_grid_3d[ydir]/2 + 1)*sizeof(fftw_complex));
  
  
  STAT_TRACE(fprintf(stderr,"%d,called fftw \n",this_node));    
    
  return 1;
    
}