/*
  ljbond.cpp
  by Wei Cai  caiwei@mit.edu
  Last Modified : Fri Mar  2 18:51:39 2007

  FUNCTION  :  MD simulation package of Lennard-Jones (LJ) potential
               LJ parameters depend on species
               Atoms can also form covalent bond with neighbors

  Test cases: scripts/work/ar/lj2-md.script, ljbond.tcl
*/

#include "ljbond.h"

void LJBONDFrame::initparser()
{
    int i, j;
    char s[100];
    MDPARALLELFrame::initparser();

    /* input */
    for(i=0;i<MAXSP;i++)
       for(j=i;j<MAXSP;j++)
       {
           sprintf(s,"C12_%d%d",i,j);
           bindvar(s,&(_C12[i][j]),DOUBLE);
           sprintf(s,"C6_%d%d",i,j);
           bindvar(s,&(_C6[i][j]),DOUBLE);
           sprintf(s,"C9_%d%d",i,j);
           bindvar(s,&(_C9[i][j]),DOUBLE);
       }

    bindvar("BOND_R0",&BOND_R0,DOUBLE);
    bindvar("BOND_K", &BOND_K, DOUBLE);

    //bindvar("WALL_X0",&WALL_X0,DOUBLE);
    //bindvar("WALL_K", &WALL_K, DOUBLE);
    //bindvar("ATTRAC_R0",&ATTRAC_R0,DOUBLE);
    //bindvar("ATTRAC_K", &ATTRAC_K, DOUBLE);
    //bindvar("WALL2_X0",&WALL2_X0,DOUBLE);
    //bindvar("WALL2_K",&WALL2_K,DOUBLE);
    //bindvar("ATTRAC2_Y0",&ATTRAC2_Y0,DOUBLE);
    //bindvar("ATTRAC2_K",&ATTRAC2_K,DOUBLE);

    bindvar("ATTRAC_W",&ATTRAC_W,DOUBLE);
    bindvar("ATTRAC_K",&ATTRAC_K,DOUBLE);
    bindvar("PROBE1_WX",&PROBE1_WX,DOUBLE);
    bindvar("PROBE1_WY",&PROBE1_WY,DOUBLE);
    bindvar("PROBE1_DY",&PROBE1_DY,DOUBLE);
    bindvar("PROBE1_SY0",&PROBE1_SY0,DOUBLE);
    bindvar("PROBE1_K",&PROBE1_K,DOUBLE);
    bindvar("PROBE2_WX",&PROBE2_WX,DOUBLE);
    bindvar("PROBE2_WY",&PROBE2_WY,DOUBLE);
    bindvar("PROBE2_DY",&PROBE2_DY,DOUBLE);
    bindvar("PROBE2_SY0",&PROBE2_SY0,DOUBLE);
    bindvar("PROBE2_K",&PROBE2_K,DOUBLE);

    bindvar("LMAX",&LMAX,DOUBLE);
    bindvar("LAMBDA",&LAMBDA,DOUBLE);

    bindvar("dUdLAM_WALL",&dUdLAM_WALL,DOUBLE);
    bindvar("dUdLAM_ATT", &dUdLAM_ATT, DOUBLE);
    bindvar("dUdLAM_WALL2",&dUdLAM_WALL2,DOUBLE);
    bindvar("dUdLAM_ATT2",&dUdLAM_ATT2,DOUBLE);
    bindvar("dUdLAM_L",&dUdLAM_L,DOUBLE);
    bindvar("dUdLAM",&dUdLAM,DOUBLE);

    bindvar("Rcut",&LJ_RC,DOUBLE);
    bindvar("usrfile",usrfile,STRING);
}

int LJBONDFrame::exec(const char *name)
{
    if(MDPARALLELFrame::exec(name)==0) return 0;
    bindcommand(name,"initLJ",initLJ());
    bindcommand(name,"makelipids",makelipids());
    bindcommand(name,"linklipids",linklipids());
    bindcommand(name,"makealkanes",makealkanes());
    bindcommand(name,"linkalkanes",linkalkanes());
    bindcommand(name,"makeproteins",makeproteins());
    bindcommand(name,"linkproteins",linkproteins());
    bindcommand(name,"writeatomeyeusr",writeatomeyeusrfile(usrfile));
    return -1;
}

void LJBONDFrame::Alloc()
{
    int size;
    MDPARALLELFrame::Alloc();

    Alloc1();
}

void LJBONDFrame::Alloc1()
{
    /* from ljbond2.cpp */
    int size;

    size = _NP*allocmultiple;
    Realloc(num_bonds, int,size);
    Realloc(bond_index,int,size*MAXNUMBOND);

    memset(num_bonds, 0,sizeof(int)*size);
    memset(bond_index,0,sizeof(int)*size*MAXNUMBOND);
}


void LJBONDFrame::initvars()
{
    int i, j;
    for(i=0;i<MAXSP;i++)
       for(j=i;j<MAXSP;j++)
       {
           _C12[i][j] = 4;
           _C6 [i][j] = 4;
           _C9 [i][j] = 0;
       }

    BOND_R0 = LJ_LENGTH;
    BOND_K  = 2;
    LJ_RC = 2.37343077641 * LJ_LENGTH; /* initial value, 4th neighbor */
    _RLIST=LJ_RC+1.1;
    _SKIN=_RLIST-LJ_RC;
    MDPARALLELFrame::initvars();
}

void LJBONDFrame::initLJ()
{
    int i, j;

    for(i=0;i<MAXSP;i++)
       for(j=i;j<MAXSP;j++)
       {
	     C12[i][j]=_C12[i][j]*LJ_ENERGY*POW12(LJ_LENGTH);
	     C6 [i][j]=_C6 [i][j]*LJ_ENERGY*POW6(LJ_LENGTH);

             /* 1.05 is here because sigma_SC = 1.05 * sigma
                Ref: Nanoscale, 3, 391-400 (2011)
                     J. Chem. Phys. 108, 7397-7409 (1998)
             */
	     C9 [i][j]=_C9 [i][j]*LJ_ENERGY*CUBE(CUBE((1.05*LJ_LENGTH)));

	     Uc[i][j] = (C12[i][j]*POW6(1/LJ_RC)-C6[i][j])*POW6(1/LJ_RC) + C9[i][j]*CUBE(CUBE(1/LJ_RC));
	     DUDRc[i][j] = -(12*C12[i][j]/POW6(LJ_RC)-6*C6[i][j])/POW6(LJ_RC)/LJ_RC
                           -9*C9[i][j]/CUBE(CUBE(LJ_RC))/LJ_RC;

       }
    /* symmetrize LJ parameter matrix */
    for(i=1;i<MAXSP;i++)
       for(j=0;j<i;j++)
       {
	   _C12[i][j] = _C12[j][i];
           _C6 [i][j] = _C6 [j][i];
           _C9 [i][j] = _C9 [j][i];
	    C12[i][j] =  C12[j][i];
            C6 [i][j] =  C6 [j][i];
            C9 [i][j] =  C9 [j][i];
             Uc[i][j] =   Uc[j][i];
          DUDRc[i][j] =DUDRc[j][i];
       }

    _RLIST=LJ_RC+1.1;
    _SKIN=_RLIST-LJ_RC;

}

void LJBONDFrame::SWITCHpotential_user(double lambda)
{
    /* from ljbond2.cpp */
    LAMBDA = lambda;
    //WALL3_X0 = LAMBDA * WALL3_X0MAX;

    LJBONDFrame::potential();
}
    
void LJBONDFrame::calcprop()
{
    MDPARALLELFrame::calcprop();

    /* from ljbond2.cpp */
    /* extend box in x direction accorrding to lambda */ 
    /* _H[0][0] = _H0[0][0] + LAMBDA*2.0*WALL3_X0MAX; */

    //dUdLAM_L=LMAX*_TOTSTRESS[0][0]*_H[1][1]*_H[2][2];
    //dUdLAM=dUdLAM+dUdLAM_L;
}

void LJBONDFrame::lennard_jones_bond()
{
    int i,j,ipt,jpt,k, bonded;
    double U,r,r2,ri6, R0,U0,K0,ri02,ri06;
    double C12_local,C6_local,C9_local,Uc_local,DUDRc_local;   
    Vector3 sij, rij, fij;
    Matrix33 hinv;
    
    DUMP(HIG"Lennard Jones"NOR);
        
    refreshneighborlist();
    
    _EPOT=0;
    hinv = _H.inv();

    for(i=0;i<_NP;i++)
    {_F[i].clear(); _EPOT_IND[i]=0;}
    _VIRIAL.clear();

    for(ipt=0;ipt<_NP;ipt++)
    {
        for(j=0;j<nn[ipt];j++)
        {
            jpt=nindex[ipt][j];
            if(ipt>jpt) continue;

            /* test if atoms ipt and jpt have a covalent bond */
            bonded = 0;
            for(k=0;k<num_bonds[ipt];k++)
            {
                if(bond_index[ipt*MAXNUMBOND+k] == jpt)
                {
                    bonded = 1;
                    break;
                }
            }
            /* exclude covalently bonded pairs from LJ interaction */
            if(bonded) continue;

            sij=_SR[jpt]-_SR[ipt];
            sij.subint();
            rij=_H*sij;
            r2=rij.norm2();
            r=sqrt(r2);
            if(r<=LJ_RC)
            {
                C12_local =   C12[species[ipt]][species[jpt]];
                C6_local  =   C6 [species[ipt]][species[jpt]];
                C9_local  =   C9 [species[ipt]][species[jpt]];
                Uc_local =    Uc[species[ipt]][species[jpt]];
		DUDRc_local = DUDRc[species[ipt]][species[jpt]];

                R0 = 0.8;  /* short range cut-off */
                if(r<R0)
                {
                  ri02  = 1./(R0*R0);
                  ri06 = ri02*ri02*ri02;
                  U0 = (7*C12_local*ri06 - 4*C6_local)*ri06 + 5.5*C9_local*ri06*ri02/R0; 
                  K0 = (6*C12_local*ri06 - 3*C6_local)*ri06*ri02 + 4.5*C9_local*ri06*ri02*ri02/R0;
                  U = U0 - K0*r2 - r*DUDRc_local + (LJ_RC*DUDRc_local-Uc_local);
                  fij = rij*(2*K0 + DUDRc_local/r);
                }
                else
		{
		    ri6 = 1./(r2*r2*r2);
		    U = (C12_local*ri6-C6_local)*ri6 + C9_local*ri6/CUBE(r)
                        -r*DUDRc_local+(LJ_RC*DUDRc_local-Uc_local);
		    fij=rij*((12*C12_local*ri6-6*C6_local)*ri6/r2 + 9*C9_local*ri6*ri6*r +DUDRc_local/r);
                }

                _F[ipt]-=fij;
                _F[jpt]+=fij;
                _EPOT_IND[ipt]+=U*0.5;
                _EPOT_IND[jpt]+=U*0.5;
                _EPOT+=U;
                _VIRIAL.addnvv(1.,fij,rij);
            }
        }
    }

    /* covalently bonded interaction */
  if(BOND_K != 0)
  {
    for(ipt=0;ipt<_NP;ipt++)
    {
       //INFO_Printf("ljbond: ipt=%d num_bonds = %d\n",ipt,num_bonds[ipt]);
       for(j=0;j<num_bonds[ipt];j++)
       {
          jpt = bond_index[ipt*MAXNUMBOND + j];
          //INFO_Printf("ljbond: ipt=%d jpt=%d\n",ipt,jpt);

          if(ipt>jpt) continue;

          sij=_SR[jpt]-_SR[ipt];
          sij.subint();
          rij=_H*sij;
          r2=rij.norm2();
          r=sqrt(r2);
                
          U = BOND_K * SQR(r-BOND_R0);
          fij = rij * (-2*BOND_K*(1-BOND_R0/r)); /* bug fix from old ljbond.cpp */

          _F[ipt]-=fij;
          _F[jpt]+=fij;
          _EPOT_IND[ipt]+=U*0.5;
          _EPOT_IND[jpt]+=U*0.5;
          _EPOT+=U;
          _VIRIAL.addnvv(1.,fij,rij);
       }
       //INFO_Printf("ljbond: F[%d] = (%e %e %e)\n",ipt,_F[ipt].x,_F[ipt].y,_F[ipt].z);       
    }
  }

  /* add external potential */
  Vector3 si, ri, fi;
  double x, y, e_attrac, fy_attrac;
  double Ycut, dYcutdy, sgn_y, e_probe, fx_probe, fy_probe;

  /* Attractive potential for tail particles */ 
  if ((ATTRAC_W > 0 ) && (ATTRAC_K > 0 )) {
   for (ipt=0;ipt<_NP;ipt++)
   {
       /* Attractive (confining) potential only applied to tail particles */
       if (species[ipt]!=1) continue; 
       si=_SR[ipt]; si.subint();
       ri=_H*si;
       y=ri.y;

    if (fabs(y) < ATTRAC_W)
    {
       e_attrac  = -1.0 * ATTRAC_K * SQR( 1.0 - SQR(y/ATTRAC_W) );
       fy_attrac = -4.0 * ATTRAC_K *    ( 1.0 - SQR(y/ATTRAC_W) ) * y/ SQR(ATTRAC_W);

       _F[ipt].y += fy_attrac;
       _EPOT_IND[ipt] += e_attrac;
       _EPOT += e_attrac;
       _VIRIAL[1][1] += fy_attrac * y;

       //if (LAMBDA>0)
       //du_att2=(e_attrac2)/LAMBDA;
       //else
       //du_att2=0;
       //dUdLAM_ATT2=dUdLAM_ATT2+du_att2;
    }
   }
  }

  /* Repulsive potential representing the probe 1 */ 
  if ((PROBE1_WX > 0) && (PROBE1_K >0)) {
   for (ipt=0;ipt<_NP;ipt++)
   {
       /* multiply a factor depending on group ID */
       double fact;
       fact = 1.0;
       //if (group[ipt]!=0) fact = pow(0.3, group[ipt]);
       //else               fact = 1.0;
       si=_SR[ipt]; si.y-=PROBE1_SY0; si.subint();
       ri=_H*si;    x=ri.x;   y=ri.y;
  
    if (fabs(x) < PROBE1_WX) 
    {
       Ycut = 1.0 / (1.0 + exp( (fabs(y) - PROBE1_WY)/PROBE1_DY ) );
       if (y>0) sgn_y = 1.0; else if (y<0) sgn_y = -1.0; else sgn_y = 0.0;
       dYcutdy = -1.0 * SQR(Ycut) * exp ( (fabs(y) - PROBE1_WY)/PROBE1_DY ) / PROBE1_DY * sgn_y;

       //Ycut = 1.0; dYcutdy = 0.0;

       e_probe  = PROBE1_K * SQR( SQR(PROBE1_WX)-SQR(x) ) / SQR(PROBE1_WX) * Ycut;
       fx_probe = PROBE1_K*4.0*( SQR(PROBE1_WX)-SQR(x) ) * x / SQR(PROBE1_WX) * Ycut;
       fy_probe = -1.0 * PROBE1_K * SQR( SQR(PROBE1_WX)-SQR(x) ) / SQR(PROBE1_WX) * dYcutdy;

       if ( (((group[ipt]==2) && (x<0)) || ((group[ipt]==1) && (x>0))) 
            && ((species[ipt]==1)||(species[ipt]==2)) && (fabs(y) < PROBE1_WY+PROBE1_DY*3.0) )
       {
          e_probe = PROBE1_K * (SQR( SQR(PROBE1_WX)-SQR(0) ) / SQR(PROBE1_WX)+0.5*SQR(x)) * Ycut;
          fx_probe = -PROBE1_K * x * Ycut; 
          fy_probe = -1.0 * PROBE1_K * (SQR( SQR(PROBE1_WX)-SQR(0) ) / SQR(PROBE1_WX)+0.5*SQR(x)) * dYcutdy;
          INFO_Printf("PROBE1: atom %d group = %d  x = %g  fx_probe = %g\n",ipt,group[ipt],x,fx_probe);
       }

       /* multiply a factor depending on group ID */
       e_probe *= fact;
       fx_probe*= fact;
       fy_probe*= fact;

       _F[ipt].x += fx_probe;
       _F[ipt].y += fy_probe;
       _EPOT_IND[ipt] += e_probe;
       _EPOT += e_probe;

       _VIRIAL[0][0] += fx_probe * x;
       _VIRIAL[1][1] += fy_probe * y;

       //++TNPT_WALL3;

       //if ((LAMBDA>0) && (species[ipt]!=3)) 
       //du_wall3=fwall3*pow(WALL3_X0,2)/(x*LAMBDA)-2*ewall3/LAMBDA;
       //else
       //du_wall3=0;

       //dUdLAM_WALL3=dUdLAM_WALL3+du_wall3;
       //EWALL3=EWALL3+ewall3;
    }

   }
  }

  /* Repulsive potential representing the probe 2 */ 
  if ((PROBE2_WX > 0) && (PROBE2_K >0)) {
   for (ipt=0;ipt<_NP;ipt++)
   {
       /* multiply a factor depending on group ID */
       double fact;
       fact = 1.0;
       //if (group[ipt]!=0) fact = pow(0.3, group[ipt]);
       //else               fact = 1.0;
       si=_SR[ipt]; si.y-=PROBE2_SY0; si.subint();
       ri=_H*si;    x=ri.x;   y=ri.y;
  
    if (fabs(x) < PROBE2_WX) 
    {
       Ycut = 1.0 / (1.0 + exp( (fabs(y) - PROBE2_WY)/PROBE2_DY ) );
       if (y>0) sgn_y = 1.0; else if (y<0) sgn_y = -1.0; else sgn_y = 0.0;
       dYcutdy = -1.0 * SQR(Ycut) * exp ( (fabs(y) - PROBE2_WY)/PROBE2_DY ) / PROBE2_DY * sgn_y;

       //Ycut = 1.0; dYcutdy = 0.0;

       e_probe  = PROBE2_K * SQR( SQR(PROBE2_WX)-SQR(x) ) / SQR(PROBE2_WX) * Ycut;
       fx_probe = PROBE2_K*4.0*( SQR(PROBE2_WX)-SQR(x) ) * x / SQR(PROBE2_WX) * Ycut;
       fy_probe = -1.0 * PROBE2_K * SQR( SQR(PROBE2_WX)-SQR(x) ) / SQR(PROBE2_WX) * dYcutdy;

       if ( (((group[ipt]==2) && (x<0)) || ((group[ipt]==1) && (x>0))) 
            && ((species[ipt]==1)||(species[ipt]==2)) && (fabs(y) < PROBE2_WY+PROBE2_DY*3.0) )
       {
          e_probe = PROBE2_K * (SQR( SQR(PROBE2_WX)-SQR(0) ) / SQR(PROBE2_WX)+0.5*SQR(x)) * Ycut;
          fx_probe = -PROBE2_K * x * Ycut; 
          fy_probe = -1.0 * PROBE2_K * (SQR( SQR(PROBE2_WX)-SQR(0) ) / SQR(PROBE2_WX)+0.5*SQR(x)) * dYcutdy;
          INFO_Printf("PROBE2: atom %d group = %d  x = %g  fx_probe = %g\n",ipt,group[ipt],x,fx_probe);
       }

       /* multiply a factor depending on group ID */
       e_probe *= fact;
       fx_probe*= fact;
       fy_probe*= fact;

       _F[ipt].x += fx_probe;
       _F[ipt].y += fy_probe;
       _EPOT_IND[ipt] += e_probe;
       _EPOT += e_probe;

       _VIRIAL[0][0] += fx_probe * x;
       _VIRIAL[1][1] += fy_probe * y;

       //++TNPT_WALL3;

       //if ((LAMBDA>0) && (species[ipt]!=3)) 
       //du_wall3=fwall3*pow(WALL3_X0,2)/(x*LAMBDA)-2*ewall3/LAMBDA;
       //else
       //du_wall3=0;

       //dUdLAM_WALL3=dUdLAM_WALL3+du_wall3;
       //EWALL3=EWALL3+ewall3;
    }

   }
  }

  //dUdLAM=dUdLAM_ATT2+dUdLAM_WALL3;
  //dUdLAM=dUdLAM_WALL+dUdLAM_ATT+dUdLAM_WALL2+dUdLAM_ATT2;

}

void LJBONDFrame::linklipids()
{
    int nsolvent, nlipid, chainlen, headid;
    int ipt, i, j;
    double bond_len;
    Vector3 dr, dr1, ds;
    Matrix33 hinv;

    nsolvent = (int) input[3];
    nlipid   = (int) input[4];
    chainlen = (int) input[5];
    headid   = (int) input[6];
    bond_len =       input[7];

    ipt = 0;
    for(i=0;i<nlipid;i++)
    {
        for(j=0;j<chainlen;j++)
        {
           if(j==0)
           {
               /* only one bond */
               num_bonds[ipt] = 1;
               bond_index[ipt*MAXNUMBOND + 0] = ipt+1;
               
           } else if (j==(chainlen-1))
           {   /* only one bond */
               num_bonds[ipt]=1;
               bond_index[ipt*MAXNUMBOND + 0] = ipt-1;
           } else
           {   /* two bonds */
               num_bonds[ipt]=2;
               bond_index[ipt*MAXNUMBOND + 0] = ipt-1;
               bond_index[ipt*MAXNUMBOND + 1] = ipt+1;
           }
           ipt ++;
        }
    }
}

void LJBONDFrame::linkalkanes()
{
    int nsolvent, nlipid, nalkane, chainlen, alkanelen, headid;
    int ipt, i, j;
    double bond_len;
    Vector3 dr, dr1, ds;
    Matrix33 hinv;

    nsolvent = (int) input[3];
    nlipid   = (int) input[4];
    chainlen = (int) input[5];
    headid   = (int) input[6];
    bond_len =       input[7];
    nalkane  = (int) input[8];
    alkanelen= (int) input[9];
    ipt = nlipid*chainlen+nsolvent;
   
    for(i=0;i<nalkane;i++)
    {
        for(j=0;j<alkanelen;j++)
        {
           if(j==0)
           {
               /* only one bond */
               num_bonds[ipt] = 1;
               bond_index[ipt*MAXNUMBOND + 0] = ipt+1;
               
           } else if (j==(alkanelen-1))
           {   /* only one bond */
               num_bonds[ipt]=1;
               bond_index[ipt*MAXNUMBOND + 0] = ipt-1;
           } else
           {   /* two bonds */
               num_bonds[ipt]=2;
               bond_index[ipt*MAXNUMBOND + 0] = ipt-1;
               bond_index[ipt*MAXNUMBOND + 1] = ipt+1;
           }
           ipt ++;
        }
    }
}

void LJBONDFrame::linkproteins()
{
    int nsolvent, nlipid, nalkane, chainlen, alkanelen, headid;
    int nprotein, top_len, center_len, end_len;
    int ipt, i, j;
    double bond_len;
    Vector3 dr, dr1, ds;
    Matrix33 hinv;

    nsolvent = (int) input[3];
    nlipid   = (int) input[4];
    chainlen = (int) input[5];
    headid   = (int) input[6];
    bond_len =       input[7];
    nalkane  = (int) input[8];
    alkanelen= (int) input[9];
    nprotein = (int) input[10];
    top_len  = (int) input[11];
    center_len=(int) input[12];
    end_len  = (int) input[13];

    ipt = nlipid*chainlen+nsolvent+nalkane*alkanelen;
   
    for(i=0;i<nprotein;i++)
    {
        for(j=0;j<top_len+center_len+end_len;j++)
        {
           if(j==0)
           {
               /* only one bond */
               num_bonds[ipt] = 1;
               bond_index[ipt*MAXNUMBOND + 0] = ipt+1;
               
           } else if (j==(top_len+center_len+end_len-1))
           {   /* only one bond */
               num_bonds[ipt]=1;
               bond_index[ipt*MAXNUMBOND + 0] = ipt-1;
           } else
           {   /* two bonds */
               num_bonds[ipt]=2;
               bond_index[ipt*MAXNUMBOND + 0] = ipt-1;
               bond_index[ipt*MAXNUMBOND + 1] = ipt+1;
           }
           ipt ++;
        }
    }
}

void LJBONDFrame::makelipids()
{
    int nsolvent, nlipid, nalkane, chainlen, alkanelen, headid;
    int ipt, i, j;
    double bond_len,d_by_two;
    Vector3 dr, dr1, ds;
    Matrix33 hinv;

    /* Note format change of input[] */
    _H.clear();
    _H[0][0] = input[0];
    _H[1][1] = input[1];
    _H[2][2] = input[2];

    nsolvent = (int) input[3];
    nlipid   = (int) input[4];
    chainlen = (int) input[5];
    headid   = (int) input[6];
    bond_len =       input[7];

    /* from ljbond2.cpp */
    nalkane =   (int) input[8];
    alkanelen = (int) input[9];
    d_by_two=0.025;

    _NP = nlipid*chainlen + nsolvent;
    Alloc();

    hinv = _H.inv();
    ipt = 0;
    for(i=0;i<nlipid;i++)
    {
        for(j=0;j<chainlen;j++)
        {
           if(j==0)
           {
               /* randomly position the first atom */
               _SR[ipt].set(drand48()-0.5,drand48()-0.5,drand48()-0.5);

               /* randomly choose a growth direction */
               dr.set(drand48()-0.5,drand48()-0.5,drand48()-0.5);
               dr/=dr.norm();  dr*=bond_len; ds = hinv*dr;

           } else {
               /* add a new atom in the randomly chosen direction */
               _SR[ipt] = _SR[ipt-1] + ds;
           }

           if(j==headid)
           {
               species[ipt] = 2; /* head particle (hydrophilic) */

               /* choose a slightly different growth direction */
               dr1.set(drand48()-0.5,drand48()-0.5,drand48()-0.5);
               dr1/=dr1.norm(); dr1*=(bond_len*0.5); dr*=-1; dr+=dr1;
               dr/=dr.norm();  dr*=bond_len; ds = hinv*dr;

           } else {
               species[ipt] = 1; /* tail particle (hydrophobic) */
           }

           ipt ++;
        }
    }

    linklipids();
     
    for(i=0;i<nsolvent;i++)
    {
        /* randomly position the solvent particle */
        _SR[ipt].set(drand48()-0.5,drand48()-0.5,drand48()-0.5);
        species[ipt] = 0;     /* solvent particle (water) */
        ipt ++;
    }             
}

void LJBONDFrame::makealkanes()
{
    int nsolvent, nlipid, nalkane, chainlen, alkanelen, headid;
    int ipt, i, j;
    double bond_len,d_by_two,offset;
    Vector3 dr, dr1, ds;
    Matrix33 hinv;

    nsolvent = (int) input[3];
    nlipid   = (int) input[4];
    chainlen = (int) input[5];
    headid   = (int) input[6];
    bond_len =       input[7];
    nalkane  = (int) input[8];
    alkanelen= (int) input[9];
    d_by_two=0.032;

    offset=0.2;

    INFO_Printf("old NP=%d",_NP);
    _NP = nlipid*chainlen + nalkane*alkanelen + nsolvent;
    INFO_Printf("old NP=%d",_NP);
    Alloc1();


    hinv = _H.inv();
    ipt = nlipid*chainlen+nsolvent;
  
    for(i=0;i<nalkane;i++)
    //for(i=0;i<(nalkane/4);i++)
    {
        for(j=0;j<alkanelen;j++)
        {
           if(j==0)
           {
               /* randomly position the first atom */
               if (i<(nalkane/4)) 
                  _SR[ipt].set(0.158,d_by_two, 0.5-0.0973*i);
               else if (i<(nalkane/4)*2)
                  _SR[ipt].set(0.158,-d_by_two, 0.5-0.0973*i);
               else if (i<(nalkane/4)*3)
                  _SR[ipt].set(-0.158,d_by_two, 0.45-0.0973*i);
               else
                  _SR[ipt].set(-0.158,-d_by_two, 0.45-0.0973*i);

               /* randomly choose a growth direction */
               dr.set(1,0,0);
               dr/=dr.norm();  dr*=bond_len; ds = hinv*dr;

           } else {
               /* add a new atom in the randomly chosen direction */
               _SR[ipt] = _SR[ipt-1] + ds;
           }

           if(j==0)
           {
               species[ipt] = 3; /* head particle (hydrophilic) */
	       fixed[ipt]=1; /*fix head particle*/

           } else {
               species[ipt] = 3; /* tail particle (hydrophobic) */
           }

           ipt ++;
        }
    }

    linkalkanes();
              
}
void LJBONDFrame::makeproteins()
{
    int nsolvent, nlipid, nalkane, chainlen, alkanelen, headid;
    int nprotein, top_len, center_len, end_len;
    int ipt, i, j;
    double bond_len,d_by_two,offset;
    Vector3 dr, dr1, ds;
    Matrix33 hinv;

    nsolvent = (int) input[3];
    nlipid   = (int) input[4];
    chainlen = (int) input[5];
    headid   = (int) input[6];
    bond_len =       input[7];
    nalkane  = (int) input[8];
    alkanelen= (int) input[9];
    nprotein = (int) input[10];
    top_len  = (int) input[11];
    center_len=(int) input[12];
    end_len  = (int) input[13];

    d_by_two=0.032;

    offset=0.2;

    INFO_Printf("old NP=%d",_NP);
    _NP = nlipid*chainlen + nalkane*alkanelen + nsolvent;
    INFO_Printf("old NP=%d",_NP);
    Alloc1();


    hinv = _H.inv();
    ipt = nlipid*chainlen+nsolvent+nalkane*alkanelen;
  
    for(i=0;i<nprotein;i++)
    {
        for(j=0;j<top_len+center_len+end_len;j++)
        {
           if(j==0)
           {
               /* randomly position the first atom */
               _SR[ipt].set(drand48()-0.5,drand48()-0.5,drand48()-0.5);

               /* randomly choose a growth direction */
               dr.set(1,0,0);
               dr/=dr.norm();  dr*=bond_len; ds = hinv*dr;

           } else {
               /* add a new atom in the randomly chosen direction */
               _SR[ipt] = _SR[ipt-1] + ds;
           }

           if(j<top_len)
           {
               species[ipt] = 4; /* top section of protein */

           } 
           else if (j>top_len + center_len)
           {
               species[ipt] = 5; /* center section of protein */
           } 
           else 
           {
               species[ipt] = 6; /* end section of protein */
           }

           ipt ++;
        }
    }
    linkproteins();
}

void LJBONDFrame::potential()
{
    lennard_jones_bond();
}

/* defined in namecolor.c */
int Str2RGB(const char *name, int *r, int *g, int *b);

void LJBONDFrame::writeatomeyeusrfile(char *fname)
{
    FILE *fp;
    int i, j, ipt, jpt, r, g, b;
    
    INFO("MDFrame::writeatomeyeusrfile "<<fname);
    
    fp=fopen(fname,"w");
    if(fp==NULL)
    {
        FATAL("writeatomeyeusrfile: open file failure");
    }

    /* Draw Bonds (from connectivity matrix) */
    for(ipt=0;ipt<_NP;ipt++)
    {
        /* atom color and radius */
        Str2RGB(atomcolor[species[ipt]],&r,&g,&b);
        fprintf(fp, "%d  %g %g %g  %g\n",ipt, r/255.0, g/255.0, b/255.0, atomradius[species[ipt]]);
    }

    /* Draw Bonds (from connectivity matrix) */
    for(ipt=0;ipt<_NP;ipt++)
    {
       for(j=0;j<num_bonds[ipt];j++)
       {
          jpt = bond_index[ipt*MAXNUMBOND + j];
          if(ipt>jpt) continue;

          Str2RGB(bondcolor,&r,&g,&b);
          fprintf(fp, "%d %d  %g %g %g  %g\n", ipt, jpt, r/255.0, g/255.0, b/255.0, bondradius);
       }
    }
}

#ifdef _TEST

/* Main Program Begins */
class LJBONDFrame sim;

/* The main program is defined here */
#include "main.cpp"

#endif//_TEST

