void free_particle(Particle *part) {
  realloc_intlist(&(part->bl), 0);
#ifdef EXCLUSIONS
  realloc_intlist(&(part->el), 0);
#endif
}
void freePartCfg()
{
  free(partCfg);
  partCfg = NULL;
  realloc_intlist(&partCfg_bl, 0);
}
void recv_particles(ParticleList *particles, int node)
{
  int transfer=0, read, pc;
  IntList local_dyn;

  PART_TRACE(fprintf(stderr, "%d: recv_particles from %d\n", this_node, node));

  MPI_Recv(&transfer, 1, MPI_INT, node,
	   REQ_SNDRCV_PART, comm_cart, MPI_STATUS_IGNORE);

  PART_TRACE(fprintf(stderr, "%d: recv_particles get %d\n", this_node, transfer));

  realloc_particlelist(particles, particles->n + transfer);
  MPI_Recv(&particles->part[particles->n], transfer*sizeof(Particle), MPI_BYTE, node,
	   REQ_SNDRCV_PART, comm_cart, MPI_STATUS_IGNORE);
  particles->n += transfer;

  init_intlist(&local_dyn);
  for (pc = particles->n - transfer; pc < particles->n; pc++) {
    Particle *p = &particles->part[pc];
    local_dyn.n += p->bl.n;
#ifdef EXCLUSIONS
    local_dyn.n += p->el.n;
#endif

    PART_TRACE(fprintf(stderr, "%d: recv_particles got particle %d\n", this_node, p->p.identity));
#ifdef ADDITIONAL_CHECKS
    if (local_particles[p->p.identity] != NULL) {
      fprintf(stderr, "%d: transmitted particle %d is already here...\n", this_node, p->p.identity);
      errexit();
    }
#endif
  }

  update_local_particles(particles);

  PART_TRACE(fprintf(stderr, "%d: recv_particles expecting %d bond ints\n", this_node, local_dyn.n));
  if (local_dyn.n > 0) {
    alloc_intlist(&local_dyn, local_dyn.n);
    MPI_Recv(local_dyn.e, local_dyn.n*sizeof(int), MPI_BYTE, node,
	     REQ_SNDRCV_PART, comm_cart, MPI_STATUS_IGNORE);
  }
  read = 0;
  for (pc = particles->n - transfer; pc < particles->n; pc++) {
    Particle *p = &particles->part[pc];
    if (p->bl.n > 0) {
      alloc_intlist(&p->bl, p->bl.n);
      memcpy(p->bl.e, &local_dyn.e[read], p->bl.n*sizeof(int));
      read += p->bl.n;
    }
    else
      p->bl.e = NULL;
#ifdef EXCLUSIONS
    if (p->el.n > 0) {
      alloc_intlist(&p->el, p->el.n);
      memcpy(p->el.e, &local_dyn.e[read], p->el.n*sizeof(int));
      read += p->el.n;
    }
    else
      p->el.e = NULL;
#endif
  }
  if (local_dyn.n > 0)
    realloc_intlist(&local_dyn, 0);
}
void auto_exclusion(int distance)
{
  int count, p, i, j, p1, p2, p3, dist1, dist2;
  Bonded_ia_parameters *ia_params;
  Particle *part1;
  /* partners is a list containing the currently found excluded particles for each particle,
     and their distance, as a interleaved list */
  IntList *partners;

  updatePartCfg(WITH_BONDS);

  /* setup bond partners and distance list. Since we need to identify particles via their identity,
     we use a full sized array */
  partners    = (IntList*)malloc((max_seen_particle + 1)*sizeof(IntList));
  for (p = 0; p <= max_seen_particle; p++)
    init_intlist(&partners[p]);

  /* determine initial connectivity */
  for (p = 0; p < n_part; p++) {
    part1 = &partCfg[p];
    p1    = part1->p.identity;
    for (i = 0; i < part1->bl.n;) {
      ia_params = &bonded_ia_params[part1->bl.e[i++]];
      if (ia_params->num == 1) {
	p2 = part1->bl.e[i++];
	/* you never know what the user does, may bond a particle to itself...? */
	if (p2 != p1) {
	  add_partner(&partners[p1], p1, p2, 1);
	  add_partner(&partners[p2], p2, p1, 1);
	}
      }
      else
	i += ia_params->num;
    }
  }

  /* calculate transient connectivity. For each of the current neighbors,
     also exclude their close enough neighbors.
  */
  for (count = 1; count < distance; count++) {
    for (p1 = 0; p1 <= max_seen_particle; p1++) {
      for (i = 0; i < partners[p1].n; i += 2) {
	p2 = partners[p1].e[i];
	dist1 = partners[p1].e[i + 1];
	if (dist1 > distance) continue;
	/* loop over all partners of the partner */
	for (j = 0; j < partners[p2].n; j += 2) {
	  p3 = partners[p2].e[j];
	  dist2 = dist1 + partners[p2].e[j + 1];
	  if (dist2 > distance) continue;
	  add_partner(&partners[p1], p1, p3, dist2);
	  add_partner(&partners[p3], p3, p1, dist2);
	}
      }
    }
  }

  /* setup the exclusions and clear the arrays. We do not setup the exclusions up there,
     since on_part_change clears the partCfg, so that we would have to restore it
     continously. Of course this could be optimized by bundling the exclusions, but this
     is only done once and the overhead is as much as for setting the bonds, which
     the user apparently accepted.
  */
  for (p = 0; p <= max_seen_particle; p++) {
    for (j = 0; j < partners[p].n; j++)
      if (p < partners[p].e[j]) change_exclusion(p, partners[p].e[j], 0);
    realloc_intlist(&partners[p], 0);
  }
  free(partners);
}
/* parser for hole cluster analyzation:
   analyze holes <prob_part_type_number> <mesh_size>.
   Needs feature LENNARD_JONES compiled in. */
int tclcommand_analyze_parse_holes(Tcl_Interp *interp, int argc, char **argv)
{
  int i,j;
  int probe_part_type;
  int mesh_size=1, meshdim[3];
  double freevol=0.0;
  char buffer[TCL_INTEGER_SPACE+TCL_DOUBLE_SPACE];

  IntList mesh;

  int n_holes;
  int **holes;
  int max_size=0;
  int *surface;

#ifndef LENNARD_JONES
   Tcl_AppendResult(interp, "analyze holes needs feature LENNARD_JONES compiled in.\n", (char *)NULL);
    return TCL_ERROR;
#endif

  /* check # of parameters */
  if (argc < 2) {
    Tcl_AppendResult(interp, "analyze holes needs 2 parameters:\n", (char *)NULL);
    Tcl_AppendResult(interp, "<prob_part_type_number> <mesh_size>", (char *)NULL);
    return TCL_ERROR;
  }

  /* check parameter types */
  if( (! ARG_IS_I(0, probe_part_type)) ||
      (! ARG_IS_I(1, mesh_size))  ) {
    Tcl_AppendResult(interp, "analyze holes needs 2 parameters of type and meaning:\n", (char *)NULL);
    Tcl_AppendResult(interp, "INT INT\n", (char *)NULL);
    Tcl_AppendResult(interp, "<prob_part_type_number> <mesh_size>", (char *)NULL);
    return TCL_ERROR;
  }

  /* check parameter values */
  if( probe_part_type > n_particle_types || probe_part_type < 0 ) {
    Tcl_AppendResult(interp, "analyze holes: probe particle type number does not exist", (char *)NULL);
    return TCL_ERROR;
  }
  if( mesh_size < 1  ) {
    Tcl_AppendResult(interp, "analyze holes: mesh size must be positive (min=1)", (char *)NULL);
    return TCL_ERROR;
  }

  /* preparation */
  updatePartCfg(WITHOUT_BONDS);
  meshdim[0]=mesh_size;
  meshdim[1]=mesh_size;
  meshdim[2]=mesh_size;
  alloc_intlist(&mesh, (meshdim[0]*meshdim[1]*meshdim[2]));

  /* perform free space identification*/
  create_free_volume_grid(mesh, meshdim, probe_part_type);
  /* perfrom hole cluster algorithm */
  n_holes = cluster_free_volume_grid(mesh, meshdim, &holes);
  /* surface to volume ratio */
  surface = (int *) malloc(sizeof(int)*(n_holes+1));
  cluster_free_volume_surface(mesh, meshdim, n_holes, holes, surface);
  /* calculate accessible volume / max size*/
  for ( i=0; i<=n_holes; i++ ) { 
    freevol += holes[i][0];
    if ( holes[i][0]> max_size ) max_size = holes[i][0];
  }

  /* Append result to tcl interpreter */
  Tcl_AppendResult(interp, "{ n_holes mean_hole_size max_hole_size free_volume_fraction { sizes } { surfaces }  { element_lists } } ", (char *)NULL);

  Tcl_AppendResult(interp, "{", (char *)NULL);

  /* number of holes */
  sprintf(buffer,"%d ",n_holes+1); Tcl_AppendResult(interp, buffer, " ", (char *)NULL);
  /* mean hole size */
  sprintf(buffer,"%f ",freevol/(n_holes+1.0)); Tcl_AppendResult(interp, buffer, " ", (char *)NULL);
  /* max hole size */
  sprintf(buffer,"%d ",max_size); Tcl_AppendResult(interp, buffer, " ", (char *)NULL);
  /* free volume fraction */
  sprintf(buffer,"%f ",freevol/(meshdim[0]*meshdim[1]*meshdim[2]));
  Tcl_AppendResult(interp, buffer, " ", (char *)NULL);
  /* hole sizes */
  Tcl_AppendResult(interp, "{ ", (char *)NULL);
  for ( i=0; i<=n_holes; i++ ) { 
    sprintf(buffer,"%d ",holes[i][0]); Tcl_AppendResult(interp, buffer, " ", (char *)NULL);
  }
  Tcl_AppendResult(interp, "} ", (char *)NULL);
  /* hole surfaces */
  Tcl_AppendResult(interp, "{ ", (char *)NULL);
  for ( i=0; i<=n_holes; i++ ) { 
    sprintf(buffer,"%d ",surface[i]); Tcl_AppendResult(interp, buffer, " ", (char *)NULL);
  }
  Tcl_AppendResult(interp, "} ", (char *)NULL);
  /* hole elements */ 
  Tcl_AppendResult(interp, "{ ", (char *)NULL);
  for ( i=0; i<=n_holes; i++ ) { 
    Tcl_AppendResult(interp, "{ ", (char *)NULL);
    for ( j=1; j <= holes[i][0]; j++ ) {
      sprintf(buffer,"%d",holes[i][j]);
      Tcl_AppendResult(interp, buffer, " ",(char *)NULL);
    }
    Tcl_AppendResult(interp, "} ", (char *)NULL);
  }
  Tcl_AppendResult(interp, "} ", (char *)NULL);
  
  Tcl_AppendResult(interp, "}", (char *)NULL);

  /* free allocated memory */
  realloc_intlist(&mesh, 0);
  free(surface);
  for ( i=0; i<=n_holes; i++ ) { free(holes[i]); }
  free(holes);

  return (TCL_OK);
}
int parse_trapmol(Tcl_Interp *interp, int argc, char **argv)
{

#ifdef MOLFORCES
#ifdef EXTERNAL_FORCES
  int trap_flag = 0;
  int noforce_flag =0;
  int i;
#endif
#endif
  int mol_num;
  double spring_constant;
  double drag_constant;
  int isrelative;
  DoubleList trap_center;
  IntList trap_coords;
  IntList noforce_coords;
  char usage[] = "trapmol usage: <mol_id> { <xpos> <ypos> <zpos> } <isrelative> <spring_constant> <drag_constant> coords   { <trapped_coord> <trapped_coord> <trapped_coord> } noforce_coords {<noforce_coord> <noforce_coord> <noforce_coord>}";

  init_doublelist(&trap_center);
  init_intlist(&trap_coords);
  alloc_intlist(&trap_coords,3);
  init_intlist(&noforce_coords);
  alloc_intlist(&noforce_coords,3);
  /* Unless coords are specified the default is just to trap it completely */
  trap_coords.e[0] = 1;
  trap_coords.e[1] = 1;
  trap_coords.e[2] = 1;

  Tcl_ResetResult(interp);
  /* The first argument should be a molecule number */
  if (!ARG0_IS_I(mol_num)) {
    Tcl_AppendResult(interp, "first argument should be a molecule id", (char *)NULL);
    Tcl_AppendResult(interp, usage, (char *)NULL); 
    return TCL_ERROR;
  } else {
    /* Sanity checks */
    if (mol_num > n_molecules) {
      Tcl_AppendResult(interp, "trapmol: cannot trap mol %d because it does not exist",mol_num , (char *)NULL);
    return TCL_ERROR;
    }
    argc--;
    argv++;
  }

  /* The next argument should be a double list specifying the trap center */
  if (!ARG0_IS_DOUBLELIST(trap_center)) {
    Tcl_AppendResult(interp, "second argument should be a double list", (char *)NULL);
    Tcl_AppendResult(interp, usage , (char *)NULL);
    return TCL_ERROR;
  } else {
    argc -= 1;
    argv += 1;
  }

  /* The next argument should be an integer specifying whether the trap is relative (fraction of box_l) or absolute */
  if (!ARG0_IS_I(isrelative)) {
    Tcl_AppendResult(interp, "third argument should be an integer", (char *)NULL);
    Tcl_AppendResult(interp, usage, (char *)NULL);
    return TCL_ERROR;
  } else {
    argc -= 1;
    argv += 1;
  }

  /* The next argument should be the spring constant for the trap */
  if (!ARG0_IS_D(spring_constant)) {
    Tcl_AppendResult(interp, "fourth argument should be a double", (char *)NULL);
    Tcl_AppendResult(interp, usage, (char *)NULL);
    return TCL_ERROR;
  } else {
    argc -= 1;
    argv += 1;
  }

  /* The next argument should be the drag constant for the trap */
  if (!ARG0_IS_D(drag_constant)) {
    Tcl_AppendResult(interp, "fifth argument should be a double", (char *)NULL);
    Tcl_AppendResult(interp, usage, (char *)NULL);
    return TCL_ERROR;
  } else {
    argc -= 1;
    argv += 1;
  }

  /* Process optional arguments */
  while ( argc > 0 ) {    
    if ( ARG0_IS_S("coords") ) {
      if ( !ARG_IS_INTLIST(1,trap_coords) ) {
	Tcl_AppendResult(interp, "an intlist is required to specify coords", (char *)NULL);
	Tcl_AppendResult(interp, usage, (char *)NULL);
	return TCL_ERROR;
      }
      argc -= 2;
      argv += 2;
    } else if ( ARG0_IS_S("noforce_coords")) {
      if ( !ARG_IS_INTLIST(1,noforce_coords) ) {
	Tcl_AppendResult(interp, "an intlist is required to specify coords", (char *)NULL);
	Tcl_AppendResult(interp, usage, (char *)NULL);
	return TCL_ERROR;
      }
      argc -= 2;
      argv += 2;
    } else {
      Tcl_AppendResult(interp, "an option is not recognised", (char *)NULL);
      Tcl_AppendResult(interp, usage, (char *)NULL);
      return TCL_ERROR;
    }      
  }

#ifdef MOLFORCES 
#ifdef EXTERNAL_FORCES 
  for (i = 0; i < 3; i++) {
    if (trap_coords.e[i])
      trap_flag |= COORD_FIXED(i);
  
    if (noforce_coords.e[i])
      noforce_flag |= COORD_FIXED(i);
  }
  if (set_molecule_trap(mol_num, trap_flag,&trap_center,spring_constant, drag_constant, noforce_flag, isrelative) == TCL_ERROR) {
    Tcl_AppendResult(interp, "set topology first", (char *)NULL);
    return TCL_ERROR;
  }
#else
    Tcl_AppendResult(interp, "Error: EXTERNAL_FORCES not defined ", (char *)NULL);
    return TCL_ERROR;
#endif
#endif

  realloc_doublelist(&trap_center,0);
  realloc_intlist(&trap_coords,0);
  realloc_intlist(&noforce_coords,0);
  return TCL_OK;
  
}
Beispiel #7
0
void cell_cell_transfer(GhostCommunication *gc, int data_parts)
{
  int pl, p, offset;
  Particle *part1, *part2, *pt1, *pt2;

  GHOST_TRACE(fprintf(stderr, "%d: local_transfer: type %d data_parts %d\n", this_node,gc->type,data_parts));

  /* transfer data */
  offset = gc->n_part_lists/2;
  for (pl = 0; pl < offset; pl++) {
    Cell *src_list = gc->part_lists[pl];
    Cell *dst_list = gc->part_lists[pl + offset];

    if (data_parts & GHOSTTRANS_PARTNUM) {
        prepare_ghost_cell(dst_list, src_list->n);
    }
    else {
      int np = src_list->n;
      part1 = src_list->part;
      part2 = dst_list->part;
      for (p = 0; p < np; p++) {
	pt1 = &part1[p];
	pt2 = &part2[p];
	if (data_parts & GHOSTTRANS_PROPRTS) {
	  memcpy(&pt2->p, &pt1->p, sizeof(ParticleProperties));
#ifdef GHOSTS_HAVE_BONDS
          realloc_intlist(&(pt2->bl), pt2->bl.n = pt1->bl.n);
	  memcpy(&pt2->bl.e, &pt1->bl.e, pt1->bl.n*sizeof(int));
#ifdef EXCLUSIONS
          realloc_intlist(&(pt2->el), pt2->el.n = pt1->el.n);
	  memcpy(&pt2->el.e, &pt1->el.e, pt1->el.n*sizeof(int));
#endif
#endif
        }
	if (data_parts & GHOSTTRANS_POSSHFTD) {
	  /* ok, this is not nice, but perhaps fast */
	  int i;
	  memcpy(&pt2->r, &pt1->r, sizeof(ParticlePosition));
	  for (i = 0; i < 3; i++)
	    pt2->r.p[i] += gc->shift[i];
#ifdef LEES_EDWARDS
      /* special wrapping conditions for x component of y LE shift */
      if( gc->shift[1] != 0.0 ){
        /* LE transforms are wrapped */
         if(   pt2->r.p[0]
            - (my_left[0] + dst_list->myIndex[0]*dd.cell_size[0]) >  2*dd.cell_size[0] ) 
               pt2->r.p[0]-=box_l[0];
         if( pt2->r.p[0]
            - (my_left[0] + dst_list->myIndex[0]*dd.cell_size[0]) < -2*dd.cell_size[0] ) 
               pt2->r.p[0]+=box_l[0];
      }
#endif
	}
	else if (data_parts & GHOSTTRANS_POSITION)
	  memcpy(&pt2->r, &pt1->r, sizeof(ParticlePosition));
	if (data_parts & GHOSTTRANS_MOMENTUM) {
	  memcpy(&pt2->m, &pt1->m, sizeof(ParticleMomentum));
#ifdef LEES_EDWARDS
            /* special wrapping conditions for x component of y LE shift */
            if( gc->shift[1] > 0.0 )
                pt2->m.v[0] += lees_edwards_rate;
            else if( gc->shift[1] < 0.0 )
                pt2->m.v[0] -= lees_edwards_rate;
#endif
    }
	if (data_parts & GHOSTTRANS_FORCE)
	  add_force(&pt2->f, &pt1->f);
#ifdef LB
	if (data_parts & GHOSTTRANS_COUPLING)
	  memcpy(&pt2->lc, &pt1->lc, sizeof(ParticleLatticeCoupling));
#endif
#ifdef ENGINE
	if (data_parts & GHOSTTRANS_SWIMMING)
	  memcpy(&pt2->swim, &pt1->swim, sizeof(ParticleParametersSwimming));
#endif
      }
    }
  }
}
Beispiel #8
0
void put_recv_buffer(GhostCommunication *gc, int data_parts)
{
  /* put back data */
  char *retrieve = r_buffer;

  std::vector<int>::const_iterator bond_retrieve = r_bondbuffer.begin();

  for (int pl = 0; pl < gc->n_part_lists; pl++) {
    ParticleList *cur_list = gc->part_lists[pl];
    if (data_parts & GHOSTTRANS_PARTNUM) {
      GHOST_TRACE(fprintf(stderr, "%d: reallocating cell %p to size %d, assigned to node %d\n",
			  this_node, cur_list, *(int *)retrieve, gc->node));
      prepare_ghost_cell(cur_list, *(int *)retrieve);
      retrieve += sizeof(int);
    }
    else {
      int np   = cur_list->n;
      Particle *part = cur_list->part;
      for (int p = 0; p < np; p++) {
	Particle *pt = &part[p];
	if (data_parts & GHOSTTRANS_PROPRTS) {
	  memcpy(&pt->p, retrieve, sizeof(ParticleProperties));
	  retrieve +=  sizeof(ParticleProperties);
#ifdef GHOSTS_HAVE_BONDS
          int n_bonds;
	  memcpy(&n_bonds, retrieve, sizeof(int));
	  retrieve +=  sizeof(int);
          if (n_bonds) {
            realloc_intlist(&pt->bl, pt->bl.n = n_bonds);
            std::copy(bond_retrieve, bond_retrieve + n_bonds, pt->bl.e);
            bond_retrieve += n_bonds;
          }
#ifdef EXCLUSIONS
	  memcpy(&n_bonds, retrieve, sizeof(int));
	  retrieve +=  sizeof(int);
          if (n_bonds) {
            realloc_intlist(&pt->el, pt->el.n = n_bonds);
            std::copy(bond_retrieve, bond_retrieve + n_bonds, pt->el.e);
            bond_retrieve += n_bonds;
          }
#endif
#endif
	  if (local_particles[pt->p.identity] == NULL) {
	    local_particles[pt->p.identity] = pt;
	  }
	}
	if (data_parts & GHOSTTRANS_POSITION) {
	  memcpy(&pt->r, retrieve, sizeof(ParticlePosition));
	  retrieve +=  sizeof(ParticlePosition);
#ifdef LEES_EDWARDS
      /* special wrapping conditions for x component of y LE shift */
      if( gc->shift[1] != 0.0 ){
               /* LE transforms are wrapped
                  ---Using this method because its a shortcut to getting a neat-looking verlet list. */
               if( pt->r.p[0]
                - (my_left[0] + cur_list->myIndex[0]*dd.cell_size[0]) >  2*dd.cell_size[0] )
                   pt->r.p[0]-=box_l[0];
               if( pt->r.p[0]
                - (my_left[0] + cur_list->myIndex[0]*dd.cell_size[0]) < -2*dd.cell_size[0] )
                   pt->r.p[0]+=box_l[0];
      }
#endif 
	}
	if (data_parts & GHOSTTRANS_MOMENTUM) {
	  memcpy(&pt->m, retrieve, sizeof(ParticleMomentum));
	  retrieve +=  sizeof(ParticleMomentum);
#ifdef LEES_EDWARDS
     /* give ghost particles correct velocity for the main
      * non-ghost LE reference frame */
      if( gc->shift[1] > 0.0 )
                pt->m.v[0] += lees_edwards_rate;
      else if( gc->shift[1] < 0.0 )
                pt->m.v[0] -= lees_edwards_rate;
#endif
	}
	if (data_parts & GHOSTTRANS_FORCE) {
	  memcpy(&pt->f, retrieve, sizeof(ParticleForce));
	  retrieve +=  sizeof(ParticleForce);
	}
#ifdef LB
	if (data_parts & GHOSTTRANS_COUPLING) {
	  memcpy(&pt->lc, retrieve, sizeof(ParticleLatticeCoupling));
	  retrieve +=  sizeof(ParticleLatticeCoupling);
	}
#endif
#ifdef ENGINE
	if (data_parts & GHOSTTRANS_SWIMMING) {
          memcpy(&pt->swim, retrieve, sizeof(ParticleParametersSwimming));
          retrieve +=  sizeof(ParticleParametersSwimming);
        }
#endif
      }
    }
  }

  if (data_parts & GHOSTTRANS_PROPRTS) {
    // skip the final information on bonds to be sent in a second round
    retrieve += sizeof(int);
  }

  if (retrieve - r_buffer != n_r_buffer) {
    fprintf(stderr, "%d: recv buffer size %d differs "
            "from what I read out (%ld)\n",
            this_node, n_r_buffer, retrieve - r_buffer);
    errexit();
  }
  if (bond_retrieve != r_bondbuffer.end()) {
    fprintf(stderr, "%d: recv bond buffer was not used up, %ld elements remain\n",
            this_node, r_bondbuffer.end() - bond_retrieve );
    errexit();
  }
  r_bondbuffer.resize(0);
}
Beispiel #9
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;
}