void MicrotubuleProcess::addCompVoxel(unsigned int protoIndex,
                                      unsigned int dimerIndex, Point& aPoint)
{
  unsigned int aCoord(startCoord+protoIndex*theDimerSize+dimerIndex);
  Voxel& aVoxel((*theLattice)[aCoord]);
  aVoxel.point = &thePoints[protoIndex*theDimerSize+dimerIndex];
  *aVoxel.point = aPoint;
  aVoxel.adjoiningCoords = new unsigned int[theAdjoiningCoordSize];
  aVoxel.diffuseSize = 2;
  for(unsigned int i(0); i != theAdjoiningCoordSize; ++i)
    {
      aVoxel.adjoiningCoords[i] = theNullCoord;
    }
  if(!dimerIndex)
    {
      theMinusSpecies->addCompVoxel(aCoord);
    }
  else if(dimerIndex == theDimerSize-1)
    { 
      thePlusSpecies->addCompVoxel(aCoord);
    }
  else
    {
      theVacantSpecies->addCompVoxel(aCoord);
    }
}
void MicrotubuleProcess::connectEastWest(unsigned int i, unsigned int j)
{
  unsigned int a(startCoord+j*theDimerSize+i);
  Voxel& aVoxel((*theLattice)[a]);
  unsigned int b(startCoord+(j-1)*theDimerSize+i); 
  Voxel& adjoin((*theLattice)[b]);
  aVoxel.adjoiningCoords[aVoxel.adjoiningSize++] = b;
  adjoin.adjoiningCoords[adjoin.adjoiningSize++] = a;
}
void MicrotubuleProcess::connectNwSw(unsigned int i)
{
  unsigned int a(startCoord+i);
  Voxel& aVoxel((*theLattice)[a]);
  unsigned int b(startCoord+(Protofilaments-1)*theDimerSize+(i-1)); 
  Voxel& adjoin((*theLattice)[b]);
  aVoxel.adjoiningCoords[aVoxel.adjoiningSize++] = b;
  adjoin.adjoiningCoords[adjoin.adjoiningSize++] = a;
}
void MicrotubuleProcess::connectNorthSouth(unsigned int i, unsigned int j)
{
  unsigned int a(startCoord+j*theDimerSize+(i-1));
  Voxel& aVoxel((*theLattice)[a]);
  unsigned int b(startCoord+j*theDimerSize+i);
  Voxel& adjoin((*theLattice)[b]);
  aVoxel.adjoiningCoords[NORTH] = b;
  adjoin.adjoiningCoords[SOUTH] = a;
  aVoxel.adjoiningSize = 2;
  adjoin.adjoiningSize = 2;
}
void MicrotubuleProcess::connectPeriodic(unsigned int j)
{
  unsigned int a(startCoord+j*theDimerSize+theDimerSize-1);
  Voxel& aVoxel((*theLattice)[a]);
  unsigned int b(startCoord+j*theDimerSize); 
  Voxel& adjoin((*theLattice)[b]);
  aVoxel.adjoiningCoords[NORTH] = b;
  adjoin.adjoiningCoords[SOUTH] = a;
  aVoxel.adjoiningSize = 2;
  adjoin.adjoiningSize = 2;
}
void MicroscopyTrackingProcess::incSpeciesLatticeCount()
{
  for(unsigned i(0); i != thePositiveSpecies.size(); ++i)
    {
      Species* aSpecies(thePositiveSpecies[i]);
      aSpecies->updateMols();
      unsigned aMolSize(aSpecies->size());
      for(unsigned j(0); j != aMolSize; ++j)
        { 
          unsigned aMol(aSpecies->getMol(j));
          Voxel& aVoxel((*theLattice)[aMol]);
          ++theFreqLattice[theLatticeSpeciesIndices[i][0]][aMol];
          for(unsigned k(1); k != theLatticeSpeciesIndices[i].size(); ++k)
            {
              ++theFreqLattice[theLatticeSpeciesIndices[i][k]][
                aVoxel.adjoins[k-1]];
            }
        }
    }
}
double PolymerizationProcess::setImmediateTargetVoxel(Subunit* aRefSubunit,
                                                      unsigned int aBendIndex) 
{
  Voxel* aRefVoxel(aRefSubunit->voxel);
  Point* aRefPoint(&aRefSubunit->targetPoints[aBendIndex]);
  double anImmediateDist(LARGE_DISTANCE);
  std::vector<unsigned int>& immedSurface((*aRefVoxel->surfaceCoords)[IMMED]);
  //Check the immediate 6 (usually) surface voxels adjoining the voxel of the
  //reference subunit:
  for(unsigned int i(0); i!=immedSurface.size(); ++i)
    {
      Voxel* aVoxel(&(*theLattice)[immedSurface[i]]);
      Subunit* aSubunit(aVoxel->subunit);
      //If the voxel does not already occupy a protomer
      //(A protomer has at least one contPoint -- its subunitPoint)
      //and it is not a shared voxel:
      if(aSubunit->contPoints.empty())
        {
          double aDist(getDistance(aRefPoint, &aSubunit->surfacePoint));
          if(aDist < anImmediateDist)
            {
              anImmediateDist = aDist;
              aRefSubunit->targetVoxels[aBendIndex] = aVoxel;
            }
        }
    }
  if(anImmediateDist < 0.7)
    {
      //We are definitely going to use the targetVoxel[aBendIndex] since
      //anImmediateDist is less than the cut off, so add the calculated
      //contPoint of the target protomer to its subunit:
      addContPoint(aRefSubunit->targetVoxels[aBendIndex]->subunit, aRefPoint);
      return 0;
    }
  //Note that at this point, aRefSubunit->targetVoxels[aBendIndex] is not set
  //to NULL, unless anImmediateDist == LARGE_DISTANCE:
  return anImmediateDist;
}
void MicrotubuleProcess::enlistLatticeVoxels()
{
  for(unsigned int n(startCoord); n != endCoord; ++n)
    {
      Voxel& offVoxel((*theLattice)[n]);
      offVoxel.diffuseSize = offVoxel.adjoiningSize;
      double rA(theSpatiocyteStepper->getMinLatticeSpace());
      if(rA < offLatticeRadius)
        {
         rA = offLatticeRadius;
        } 
      Point center(*offVoxel.point);
      unsigned int aCoord(theSpatiocyteStepper->point2coord(center));
      Point cl(theSpatiocyteStepper->coord2point(aCoord));
      //theSpecies[3]->addMolecule(aVoxel.coord);
      Point bottomLeft(*offVoxel.point);
      Point topRight(*offVoxel.point);
      bottomLeft.x -= rA+center.x-cl.x+theSpatiocyteStepper->getColLength();
      bottomLeft.y -= rA+center.y-cl.y+theSpatiocyteStepper->getLayerLength();
      bottomLeft.z -= rA+center.z-cl.z+theSpatiocyteStepper->getRowLength();
      topRight.x += rA+cl.x-center.x+theSpatiocyteStepper->getColLength()*1.5;
      topRight.y += rA+cl.y-center.y+theSpatiocyteStepper->getLayerLength()*1.5;
      topRight.z += rA+cl.z-center.z+theSpatiocyteStepper->getRowLength()*1.5;
      unsigned int blRow(0);
      unsigned int blLayer(0);
      unsigned int blCol(0);
      theSpatiocyteStepper->point2global(bottomLeft, blRow, blLayer, blCol);
      unsigned int trRow(0);
      unsigned int trLayer(0);
      unsigned int trCol(0);
      theSpatiocyteStepper->point2global(topRight, trRow, trLayer, trCol);
      std::vector<unsigned int> checkedAdjoins;
      for(unsigned int i(blRow); i < trRow; ++i)
        {
          for(unsigned int j(blLayer); j < trLayer; ++j)
            {
              for(unsigned int k(blCol); k < trCol; ++k)
                {
                  unsigned int lat(theSpatiocyteStepper->global2coord(i, j, k));
                  Voxel& latVoxel((*theLattice)[lat]);
                  if(latVoxel.id != theSpatiocyteStepper->getNullID())
                    {
                      //theSpecies[3]->addMolecule(latVoxel);
                      Point aPoint(theSpatiocyteStepper->coord2point(lat));
                      if(inMTCylinder(aPoint))
                        {
                          for(unsigned int l(0); l != theAdjoiningCoordSize;
                              ++l)
                            {
                              unsigned adj(latVoxel.adjoiningCoords[l]);
                              Voxel& adjoin((*theLattice)[adj]);
                              if(adjoin.id == theComp->vacantSpecies->getID())
                                {
                                  checkedAdjoins.push_back(adj);
                                  addDirect(offVoxel, n, adjoin, adj);
                                }
                            }
                        }
                    }
                }
            }
        }
      for(unsigned int i(0); i != checkedAdjoins.size(); ++i)
        {
          (*theLattice)[checkedAdjoins[i]].id = theComp->vacantSpecies->getID();
        }
    }
  for(unsigned int i(0); i != occCoords.size(); ++i)
    {
      Voxel& aVoxel((*theLattice)[occCoords[i]]);
      unsigned int* temp = aVoxel.initAdjoins;
      aVoxel.initAdjoins = aVoxel.adjoiningCoords;
      aVoxel.adjoiningCoords = temp;
      aVoxel.diffuseSize = aVoxel.adjoiningSize;
    }
  for(unsigned int i(0); i != occCoords.size(); ++i)
    {
      Voxel& aVoxel((*theLattice)[occCoords[i]]);
      for(unsigned int i(0); i != aVoxel.adjoiningSize; ++i)
        {
          unsigned int aCoord(aVoxel.adjoiningCoords[i]);
          Voxel& adjoin((*theLattice)[aCoord]);
          if(adjoin.id == theComp->vacantSpecies->getID())
            {
              Point adPoint(theSpatiocyteStepper->coord2point(aCoord));
              if(inMTCylinder(adPoint))
                {
                  std::cout << "error in MT Process" << std::endl;
                }
            }
          else if(adjoin.id != theVacantSpecies->getID() &&
                  adjoin.id != theMinusSpecies->getID() &&
                  adjoin.id != thePlusSpecies->getID() &&
                  adjoin.id != theSpatiocyteStepper->getNullID())
            {
              std::cout << "species error in MT Process" << std::endl;
            }
        }
    }
}
void MoleculePopulateProcess::populateUniformRanged(Species* aSpecies)
{
  Comp* aComp(aSpecies->getComp());
  double delta(0);
  // Increase the compartment dimensions by delta if it is a surface 
  // compartment:
  if(aComp->dimension == 2)
    {
      delta = 0.1;
    }
  double maxX(std::min(1.0, OriginX+UniformRadiusX));
  double minX(std::max(-1.0, OriginX-UniformRadiusX));
  double maxY(std::min(1.0, OriginY+UniformRadiusY));
  double minY(std::max(-1.0, OriginY-UniformRadiusY));
  double maxZ(std::min(1.0, OriginZ+UniformRadiusZ));
  double minZ(std::max(-1.0, OriginZ-UniformRadiusZ)); 
  maxX = aComp->centerPoint.x + maxX*aComp->lengthX/2*(1+delta);
  minX = aComp->centerPoint.x + minX*aComp->lengthX/2*(1+delta);
  maxY = aComp->centerPoint.y + maxY*aComp->lengthY/2*(1+delta);
  minY = aComp->centerPoint.y + minY*aComp->lengthY/2*(1+delta);
  maxZ = aComp->centerPoint.z + maxZ*aComp->lengthZ/2*(1+delta);
  minZ = aComp->centerPoint.z + minZ*aComp->lengthZ/2*(1+delta);
  std::vector<unsigned int> aCoords;
  for(std::vector<unsigned int>::iterator i(aComp->coords.begin());
      i != aComp->coords.end(); ++i)
    {
      Voxel* aVoxel(theSpatiocyteStepper->coord2voxel(*i));
      Point aPoint(theSpatiocyteStepper->coord2point(aVoxel->coord));
      if(aVoxel->id == aSpecies->getVacantID() &&
         aPoint.x < maxX && aPoint.x > minX &&
         aPoint.y < maxY && aPoint.y > minY &&
         aPoint.z < maxZ && aPoint.z > minZ)
        {
          aCoords.push_back(*i);
        }
    }
  unsigned int aSize(aSpecies->getPopulateMoleculeSize());
  if(aCoords.size() < aSize)
    {
      THROW_EXCEPTION(ValueError, String(
                      getPropertyInterface().getClassName()) +
                      "[" + getFullID().asString() + "]: There are " +
                      int2str(aSize) + " " + getIDString(aSpecies) +
                      " molecules that must be uniformly populated in a " +
                      "given range,\n but there are only " +
                      int2str(aCoords.size()) + " vacant voxels of " +
                      getIDString(aSpecies->getVacantSpecies()) +
                      " that can be populated.");
    }
  unsigned int aCoordsArray[aCoords.size()]; 
  for(unsigned int i(0); i != aCoords.size(); ++i)
    {
      aCoordsArray[i] = aCoords[i];
    }
  gsl_ran_shuffle(getStepper()->getRng(), aCoordsArray, aCoords.size(),
                  sizeof(unsigned int));
  for(unsigned int i(0); i != aSize; ++i)
    {
      aSpecies->addMolecule(theSpatiocyteStepper->coord2voxel(aCoordsArray[i]));
    }
}
bool PolymerizationProcess::setExtendedTargetVoxel(Subunit* aRefSubunit,
                                                   unsigned int aBendIndex,
                                                   double extDist) 
{
  Voxel* aRefVoxel(aRefSubunit->voxel);
  Point* aRefPoint(&aRefSubunit->targetPoints[aBendIndex]);
  std::vector<unsigned int>& extendSurface((*aRefVoxel->surfaceCoords)[EXTEND]);
  int extIndex(-1);
  //Check the immediate surface voxels adjoining the immediate surface voxels
  //of the reference subunit, defined as the extended surface voxels:
  for(unsigned int i(0); i != extendSurface.size(); ++i)
    { 
      Voxel* aVoxel(&(*theLattice)[extendSurface[i]]);
      Subunit* aSubunit(aVoxel->subunit);
      //If the voxel does not already occupy a protomer
      //(A protomer has at least one contPoint -- its subunitPoint)
      //and it is not a shared voxel:
      if(aSubunit->contPoints.empty())
        {
          double aDist(getDistance(aRefPoint, &aSubunit->surfacePoint));
          if(aDist < extDist)
            { 
              //Find the shared voxel which connects the reference voxel
              //to the extended voxel:
              std::vector<unsigned int>& 
                aSharedList((*aRefVoxel->surfaceCoords)[SHARED+i]);
              //Check if there is an existing shared voxel or a voxel
              //that is unoccupied by a protomer, which connects
              //the reference voxel to the extended voxel:
              for(unsigned int j(0); j!=aSharedList.size(); ++j)
                { 
                  Voxel* aSharedVoxel(&(*theLattice)[aSharedList[j]]);
                  if(aSharedVoxel->subunit->contPoints.empty() ||
                     aSharedVoxel->subunit->voxel == aRefVoxel)
                    {
                      extDist = aDist;
                      extIndex = i;
                      break;
                    } 
                }
            }
        }
    }
  //If the distance is within cut off:
  //(Note that this distance could also be from an immediate voxel)
  if(extDist < 1.25)
    {
      //If we found an extended voxel, let us select the best shared voxel:
      if(extIndex != -1)
        {
          Voxel* aVoxel(&(*theLattice)[extendSurface[extIndex]]);
          std::vector<unsigned int>& 
            aSharedList((*aRefVoxel->surfaceCoords)[SHARED+extIndex]);
          double aSharedDist(LARGE_DISTANCE);
          Voxel* aSelectedSharedVoxel(NULL);
          for(unsigned int i(0); i!=aSharedList.size(); ++i)
            { 
              Voxel* aSharedVoxel(&(*theLattice)[aSharedList[i]]);
              Subunit* aSubunit(aVoxel->subunit);
              //First find an existing shared voxel which connects
              //the reference voxel to the extended voxel:
              if(aSubunit->voxel == aRefVoxel)
                {
                  aSelectedSharedVoxel = aSharedVoxel;
                  break;
                }
              //Otherwise find a shared voxel that is unoccupied by a protomer:
              else if(aSubunit->contPoints.empty())
                {
                  double aDist(getDistance(aRefPoint, &aSubunit->surfacePoint));
                  if(aDist < aSharedDist)
                    {
                      aSharedDist = aDist;
                      aSelectedSharedVoxel = aSharedVoxel;
                    }
                }
            }
          //If the selected shared voxel is not an existing shared voxel nor
          //a lipid:
          if(!theSpatiocyteStepper->id2species(
                            aSelectedSharedVoxel->id)->getIsLipid() &&
             aSelectedSharedVoxel->subunit->voxel != aRefVoxel)
            {
              return false;
            }
          if(aSelectedSharedVoxel->subunit->voxel != aRefVoxel)
            {
              aSelectedSharedVoxel->subunit->voxel = aRefVoxel;
              //Add the subunitPoint of the reference protomer to the 
              //list of contPoints of the selected shared subunit:
              addContPoint(aSelectedSharedVoxel->subunit,
                           &aRefSubunit->subunitPoint);
            }
          aRefSubunit->sharedLipids[aBendIndex] = aSelectedSharedVoxel;
          aRefSubunit->targetVoxels[aBendIndex] = aVoxel;
        }
      addContPoint(aRefSubunit->targetVoxels[aBendIndex]->subunit, aRefPoint);
      return true;
    }
  return false;
}