/*  Attempt to trace main chain on bones
NOTE : NEED TO FIX addc for contraint = 0
SEE:  trace.notes
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
*/
      
#include "drawwindow.h"
#include "math.h"
#include "trace.h"
#include "peptide.h"
#include "tordyn.h"
#include "sphere.h"
#include "pdbtolev.h"
#include "assignseq.h"
#include "bone.h"
#include "extendfit.h"
#include "checkfit.h"
#include "fittopdb.h"

#include "string.h"
#include "stdlib.h" 
#define srand48 srand 

#if 1
extern struct tordyn tordata;
extern struct maiddatafile maidfile;
extern struct pepfit fit[NFIT]; // defined in peptide.h, see trace.c++ for definitin
extern int fitnum[NFIT];// see trace.c++ for definition
extern struct spheredata sp[NSPHERES];
//extern struct screenvalue  sc;
#endif

#define MAXREPEAT 5000 // max number of points with lenth = savlen-1
int repeatpt[MAXREPEAT];  //global - keeps track of pts with fit lengty = savlen-1
int savrepeat; // if = 1 then save repeat pt

int nhelfits = 0;// counts attempts to fit helix
int nshfits = 0;// counts attempts to fit sheet
int idebug = 0;  // global variable used to send message during deguging
extern int verbose; // if = 1,print some stuff;  = 2 print a lot of stuff
extern FILE *fpout; // = stdout or logfile, depending whether batch or screen version
extern int writelog; /* if =1 write to logfile, otherwise, to screen */
extern float fminden[10]; // defined in bone.c++ and  mapmenu.c++

#define PLANERR 0.2 // error allowed (radians) for 3 vectors to be in same plane

// These variables are defined globally so can be used by pfunc calls
#define NCB  5  // Maximum number of adjustable Cb2 atoms in POwel 
//#define FTOL 1.0e-6
#define FTOL 1.0e-2 //from 10-1 to 10-6 seem to give same structure - settled for 10-2, about 2 times faster than 10-6

int itranlim;  // = 0 if powell tran step exceeds allowed limit (must be called before include traacerecipes
int dynquit;  // if = 0, then use stand. quitcond - save best end density; if = N, just run N steps and save last 

#include "tracerecipes.inc"  // Musy include now so routine isn recipes.c++ "see" phead, pfunc

# define TRPTS 30 // maximum # of trace pts

struct point {  // this structure is local to tracepep, should be different in each nextpt function
   int val[TRPTS]; // the bone pt number of this point
   float fpos[TRPTS][3];// the 3D positions of this point
//   float fvec[TRPTS][3]; // fvec[i] = fpos[i+1] - f[i]
//   int plane[TRPTS];  // = 1 it the 3 vectors starting at this point are in a plane, otherwize = 0
//   float plvec[TRPTS][3]; // the vector perpendicular to plane if plane = 1
};

extern int side[AA][NBRN][NPTS];  // defined globally (originally in pdbtolev.c++)  because needed in assignseg.c++ 

void bestcb1(struct griddata& den1,struct geometry& geo,
       float ipos[NAFIT][NAA][3],int icb,float *avecb2);
void bestcbn(struct griddata& den1,struct geometry& geo,
       float ipos[NAFIT][NAA][3],int icb,int iatom,float *avecbn);
void nextpt(struct griddata& den1,struct geometry& geo,
      struct bonedata& bone1,struct point pt,int ppt,int nm,int nii[2],int ***set,
     int *quittrace,float curdist,struct pepfit fit[NFIT],
     int fitnum[NFIT],int *testpt);

float corot(float c1[3],float c2[3],float o1[3],float o2[3])
/*  Finds angle between successive CO-CO vectors.  Used in test of
   whether sheet  correct.
  Define: c1 and c2 are position C(i)and C(i+1) and o1 and o2 as O postions
          co1 and co2 the vectors from C-O(i) and C-O (i+1)
      Then find angle betwen  co1 and co2.
*/
{
   int i;
   float co1[3],co2[3],dist1,dist2,ang;
   for(i=0;i<=2;i++){
     co1[i] = o1[i]-c1[i];
     co2[i] = o2[i]-c2[i];
   }
   dist1 = sqrt( dot(co1,co1) );
   dist2 = sqrt( dot(co2,co2) );
   ang = acos( (dot(co1,co2))/(dist1*dist2) );
   ang = ang*180/PI;
   return ang;
}


int ca_caang3(struct geometry& geo)
/* find angle between successive c(i)-ca(i+3) vectors 
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
Criteria:  max value of frbad = 0.35
Returns 1 if bad!!
*/
{
   int i,k,count,countbad;
   float vec1[3],vec2[3],mag1,mag2,ang,frbad;

//   printf("For fit %d Ca-Cang =",ifit);
//   copyfittogeo(geo,fit[ifit]);
   count =countbad= 0;
   for(i=geo.nend[0];i<=geo.nend[1]-4;i++){
     for(k=0;k<=2;k++){
#if 1 // angle between successive c(i)-ca(i+3) vectors  - good criteria
       vec1[k]= geo.pos[i+3][1][k]-geo.pos[i][1][k];
       vec2[k]= geo.pos[i+4][1][k]-geo.pos[i][1+1][k];
#endif
     }
     mag1 = sqrt( dot(vec1,vec1) );
     mag2 = sqrt( dot(vec2,vec2) );
    
     ang = acos(  dot(vec1,vec2)/(mag1*mag2) );
//printf(" ang = %5.3f",ang*180.0/PI);
     count = count+1;
     if(ang*180.0/PI<23.0)
        countbad = countbad+1;
     if(verbose>=2)
//  if(verbose>=1)
        printf(" %d: %5.3f",i,ang*180.0/PI);
  }// i
  if(verbose>=2)
//if(verbose>=1)
     printf("  frbad = %5.3f\n",(float)countbad/count);
  frbad = (float)countbad/count;
  if(frbad>0.35)
    return 1;
  else 
    return 0;
}

int cadel(struct geometry& geo)
/*Find distance between plus/minus one Ca 
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
Criteria:  max value of (max-min) = 1.0
Returns 1 if bad!!
*/
{
   int i,k;
   float vec1[3],vec2[3],mag1;
   float del[3];
   float min,max,minmaxlim;

//   printf("For fit %d Ca-Cang =",ifit);
//   copyfittogeo(geo,fit[ifit]);
   min = 1000.0;
   max = 0.0;
   minmaxlim = 1.0; // Used upto 30may00
   minmaxlim = 1.2; // New - Used after 30may00
   for(i=geo.nend[0];i<=geo.nend[1]-2;i++){
     for(k=0;k<=2;k++){
       vec1[k]= geo.pos[i+2][1][k]-geo.pos[i+1][1][k];
       vec2[k]= geo.pos[i][1][k]-geo.pos[i+1][1][k];
       del[k] = vec1[k]-vec2[k];
     }
     mag1 = sqrt( dot(del,del) );
     if(mag1<min)
       min =mag1;
     if(mag1>max)
       max = mag1;
//     printf("   %5.3f",mag1);
  }// i
//  printf(" Max - Min = %5.3f\n",max-min);
  if( (max-min)>minmaxlim){
    if(verbose>=2)
       printf("For i=%d: BAD CA(i+1)--CA(i-1) dist = %5.3f > 1.0\n",i,max-min); 
    return 1;
  }
  else{
    return 0;
 }
}

float co_axisang(struct geometry& geo,int i)
/* finds angle between C0 vector and axis for helix
  Define axis as follows,
    For O[i] use Ca[i-2] to Ca[i+2] vector if they exist
    If i-2 <0, use Ca[0] to Ca[4] vector,
    If i+2 >= n = fit.nres, use Ca[n-5] to Ca[n-1] vector
  Note: only call if nres>=5
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
*/
{
   int i0,i1,k;
   float axisv[3],covec[3],mag1,mag2,ang;

   if((i-2)<geo.nend[0]){
      i0 = geo.nend[0];
      i1 = geo.nend[0]+4;
   }
   else if( (i+2)>geo.nend[1]){
      i0=geo.nend[1]-4;
      i1=geo.nend[1];
   }
   else{
      i0 = i-2;
      i1 = i+2;
   }
   for(k=0;k<=2;k++){
     axisv[k] = geo.pos[i1][1][k] - geo.pos[i0][1][k];
     covec[k] = geo.pos[i][3][k] - geo.pos[i][2][k];
   }
   mag1 = sqrt( dot(axisv,axisv) );
   mag2 = sqrt( dot(covec,covec) );
   ang = acos(  dot(axisv,covec)/(mag1*mag2) );
   ang = ang*180/PI;
   return ang;
}   
 
#if 1 // run helixca_caang
float helixca_caang(float pos0[3],float pos1[3],float pos2[3])
/* 
pos0 = Ca(i-1); pos1= Cai; pos2 = Ca(i+2)
Finds angles between Ca(i-1)-Ca(i) and Cai-Ca(i+2) 
 Hopefully - should show when helix skips one residue
*/
{
  int k;
  float vec1[3],vec2[3],mag1,mag2,ang;
  
  for(k=0;k<=2;k++){
      vec1[k] = pos1[k]-pos0[k]; // ca[i-1]-ca[i] vector
      vec2[k] = pos2[k]-pos1[k]; // ca[i]-ca[i+2] vector
  }
  mag1 = sqrt( dot(vec1,vec1) );
  mag2 = sqrt( dot(vec2,vec2) );
  ang = acosf( dot(vec1,vec2)/(mag1*mag2) );
  return ang;
}
#endif

  
float siderot(float a1[3],float a2[3],float b1[3],float b2[3])
/*  Finds angle between successive Ca-Cb vectors.  Used in test of
   whether sheet is in correct direction.
  Define: a1 and a2 are position Ca(i)and Ca(i+1) and b1 and b2 aar Cb postions
          ab1 and ab2 the vectors from Ca-Cb (i) and Ca-Cb (i+1)
          aa = vector from Ca(i) to Ca(i+1)
          bxa = vector of (ab1) X (aa) (cross product)
      Then find angle betwen bxa and ab2 = ang.
      The angle between ab1 and ab2 = ang + 90 degrees.
*/
{
   int i;
   float ab1[3],ab2[3],aa[3],bxa[3],dist1,dist2,ang;

   for(i=0;i<=2;i++){
     ab1[i] = b1[i]-a1[i];
     ab2[i] = b2[i]-a2[i];
     aa[i] = a2[i]-a1[i];
   }
   crossprod(ab1,aa,bxa);
   dist1 = sqrt( dot(ab2,ab2) );
   dist2 = sqrt( dot(bxa,bxa) );
   ang = acos( (dot(bxa,ab2))/(dist1*dist2) );
   ang = ang*180/PI + 90;
   return ang;
}

void printgeo(struct geometry& geo, float pos[NAFIT][NAA][3])
/* Prints out positons of all atoms in pos
*/
{
   int i,j;
   
   for(i=geo.nend[0];i<=geo.nend[1];i++){
     fprintf(fpout," Residue # = %d\n",i);
     for(j=1;j<=4+geo.iside[i];j++){
        fprintf(fpout,"   Atom # = %d",j);
        fprintf(fpout,"   %f %f %f\n",pos[i][j][0],pos[i][j][1],pos[i][j][2]);
     }
   }
}
void recallspheresbat(struct geometry& geo)
// Simple version of recallspheres - no graphics apps.
{
    FILE *fp;
    int i;
    char line[305];

//fprintf(fpout,"Reading %s\n",maidfile.spherefile);
    if( (fp=fopen(maidfile.spherefile,"r")) == NULL){
         fprintf(fpout,"ERROR: %s file cannot be found\n",maidfile.spherefile);
         exit(0);
    }
    else{ //spherefile opened
       fgets(line,200,fp); /* read each line*/
       sscanf(line,"%d",&maidfile.nsphere);
       if(maidfile.nsphere == -1){ // default, do not use sphere
           printf(" DO NOT USE SPHERE LIMIT IN TRACE\n");
           geo.spherelim = -1;
       }
       else{
        for(i=1;i<=maidfile.nsphere;i++){
          fgets(line,200,fp); /* read each line*/
          sscanf(line,"%f %f %f %f",
               &sp[i].radius,&sp[i].cenpos[0],&sp[i].cenpos[1],&sp[i].cenpos[2]);
        }
       } 
       fclose(fp);
    } // spherefile opened
}

void cbdenreg(int ibeg,int iend,struct griddata& den1,
       struct geometry& geo)
/*
   Check if cb in den, cbden is not used any more 
*/
{
   int ires;
   float denat;

   if(ibeg < geo.nend[0]+1)
     ibeg = geo.nend[0]+1;
   if(iend > geo.nend[1]-1)
     iend = geo.nend[1]-1;
   for(ires = ibeg;ires<=iend;ires++){ 
    if(geo.iside[ires]>=0){ // On find side if not an a.a. residue
      denat = aveatom(den1,geo,5,ires,geo.pos); // density of Cb1
      if(denat<geo.sideden){ //If cb1 in bad density, then set iside =1 and quit
         geo.iside[ires]=1;
      }
    }
  } // ires
}

void sidenumregfit(int ibeg,int iend,struct griddata& den1,
       struct geometry& geo,struct pepfit& fit)
/*
Same as sidenumreg -except applied to fit
*/
{
   int ii,ires,j,k;
   float denat,fd[3]; 
//   float length,newlength; // = distance from Ca to end of side chain - IF this lenght is less than previous length, then do not use

   if(ibeg < 1)
     ibeg = 1;
   if(iend > fit.nres-2)
     iend = fit.nres-2;
   for(ires = ibeg;ires<=iend;ires++){ 
    if(fit.nside[ires]>=0){ // Only find side if not an a.a. residue
      for(ii = 1;ii<=5;ii++) // copy fit to geo[1]
        for(k=0;k<=2;k++)
           geo.pos[1][ii][k] = fit.pos[ires][ii][k];
      fit.nside[ires]=1; // minimum default value - used if 0 or 1 good sidechains (cbend = 0 if 0)
      denat = aveatom(den1,geo,5,1,geo.pos); // density of Cb1
      if(denat<geo.sideden){ //If cb1 in bad density, then set iside =1 and quit
         goto nextres;
      }
      if(geo.maxside>=2){
        bestcb1(den1,geo,geo.pos,1,&denat); // place second C in best postion
        if(denat<geo.sideden){
            goto nextres;
        }
        j=2; // If reach here, then there are 2 good side atoms
      }
      else
        goto nextres;         
      while(j<= geo.maxside-1){
           xtof(den1,geo.pos[1][4+j],fd); /*Check if side atom close to boundary convert from double word to float sccreen*/
           for(k=0;k<=2;k++){
              if( (fd[k]<3)||(fd[k]>den1.amax[k]-den1.amin[k]-2) ){
                 if(verbose >=2)
                    fprintf(fpout,"Point too close to boundary in sidenumregfit - quit extending sidechain\n");
                 fit.nside[ires]=j;
                 goto nextres;
              }
           }
           j= j+1;
           bestcbn(den1,geo,geo.pos,1,j,&denat);
           if(denat<geo.sideden){ // If density of sidechain atom bad, do not use this atom
              fit.nside[ires]=j-1;
              goto nextres;
           }
           for(k=1;k<= 4+j -3;k++){ // check for collision the atoms on same residue
               if(distv(geo.pos[1][4+j],geo.pos[1][k]) < 2.0){
//fprintf(fpout,"collision between atom %d and atom %d on residue %d\n",k,
                 fit.nside[ires]=j-1;
                 goto nextres;
               }
           } //k
       }//while
       fit.nside[ires]= geo.maxside; // If reach here, j must = nmax
       nextres:;
       for(ii = 1;ii<=4+fit.nside[ires];ii++) // copy geo[1] to fit
           for(k=0;k<=2;k++)
              fit.pos[ires][ii][k] = geo.pos[1][ii][k];
   } // geo.iside >= 0
  }// ires
}

void sidenumreg(int ibeg,int iend,struct griddata& den1,
       struct geometry& geo)
/*
 16jun99: keep track of distance from Ca to end of side chain -
          IF this lenght is less than previous length, then do not use
   NOTE: NOW COMMENTED OUT - NOT SURE IF HELPS
 NEW: Places each new C atom in best position and  
      extends out to maximum of geo.maxside sidechains
 As of aug19,1998 - this is  only used in extendfit routines
   Also -uses new variable(NOT USED ANYMORE) geo.cbden = 0 if Cb not in density 
       used to include Cb in density  (avedenreg routine)
       and to max lenght = Cb2 = 2
NEW:  if side is an a.a. residue (geo.iside = -rottype) then do not use
*/
{
   int ires,j,k;
   float denat,fd[3]; 
//   float length,newlength; // = distance from Ca to end of side chain - IF this lenght is less than previous length, then do not use

   if(ibeg < geo.nend[0]+1)
     ibeg = geo.nend[0]+1;
   if(iend > geo.nend[1]-1)
     iend = geo.nend[1]-1;
   for(ires = ibeg;ires<=iend;ires++){ 
    if(geo.iside[ires]>=0){ // Only find side if not an a.a. residue
      geo.iside[ires]=1; // minimum default value - used if 0 or 1 good sidechains (cbend = 0 if 0)
      denat = aveatom(den1,geo,5,ires,geo.pos); // density of Cb1
      if(denat<geo.sideden){ //If cb1 in bad density, then set iside =1 and quit
         goto nextres;
      }
      if(geo.maxside>=2){
        bestcb1(den1,geo,geo.pos,ires,&denat); // place second C in best postion
        if(denat<geo.sideden){
            goto nextres;
        }
        j=2; // If reach here, then there are 2 good side atoms
      }
      else
        goto nextres;         
//      length = distv(geo.pos[ires][1],geo.pos[ires][4+j]);
      while(j<= geo.maxside-1){
           xtof(den1,geo.pos[ires][4+j],fd); /*Check if side atom close to boundary convert from double word to float sccreen*/
           for(k=0;k<=2;k++){
              if( (fd[k]<3)||(fd[k]>den1.amax[k]-den1.amin[k]-2) ){
                 if(verbose >=2)
                    fprintf(fpout,"Point too close to boundary in sidenumreg - quit extending sidechain\n");
                 geo.iside[ires]=j;
                 goto nextres;
              }
           }
           j= j+1;
           bestcbn(den1,geo,geo.pos,ires,j,&denat);
           if(denat<geo.sideden){ // If density of sidechain atom bad, do not use this atom
              geo.iside[ires]=j-1;
              goto nextres;
           }
           for(k=1;k<= 4+j -3;k++){ // check for collision the atoms on same residue
               if(distv(geo.pos[ires][4+j],geo.pos[ires][k]) < 2.0){
//fprintf(fpout,"collision between atom %d and atom %d on residue %d\n",k,
                 geo.iside[ires]=j-1;
                 goto nextres;
               }
           } //k
#if 0
           newlength = distv(geo.pos[ires][1],geo.pos[ires][4+j]);
           if(newlength < length){
                 geo.iside[ires]=j-1;
                 goto nextres;
           }
           else
               length = newlength;
#endif
       }//while
       geo.iside[ires]= geo.maxside; // If reach here, j must = nmax
       nextres:;
   } // geo.iside >= 0
  }// ires
}


#if 1 // New Version
void sidenum2(struct griddata& den1,struct geometry& geo)
/*
 Makes all atoms have 2 chain atoms
 Identical to sidenum except only goes to maximum of 2 sidecahing atoms (= Cb,Cb2)
*/
{
   int i;
   float denat; 

   for(i=geo.nend[0]+1;i<geo.nend[1];i++){ // The residues that have side chains
    if(geo.iside[i]>=0){ // On find side if not an a.a. residue
      geo.iside[i]=1; // minimum default value - used if 0 or 1 good sidechains (cbend = 0 if 0)
      denat = aveatom(den1,geo,5,i,geo.pos); // density of Cb1
      if(denat<geo.sideden){ //If cb1 in bad density, then set iside =1 and quit
         goto nextres;
      }      
      if(geo.maxside>=2){
           bestcb1(den1,geo,geo.pos,i,&denat); // place second C in best postion
           if(denat<geo.sideden)
              geo.iside[i]=1;
           else
              geo.iside[i] = 2;
      }
      nextres:;
   } // geo.iside >= 0
  } //i
}
#endif

void sidenum(int deleteend,struct griddata& den1,struct geometry& geo)
/*
NOTE: OLD VERSION - DOES NOT FIND BEST POSITION
Firsts extends side chain in density - out to a maximum of 5
New - check if close to boundary - if too close -quit extending
  Goes through each residue - finding optimal number  of sidechain atoms.
 NOTE:  minimum number = 1  - always a Cb, required, I think, for other routines
   Cb = #5, and each additional side chain atom = 6,7,8,9  (max allowed
     is   = 9, max allowed side chain atoms = 5 = 9-4)
NOTE:  (NAA use to be max allowed = 10, now set to 20 and max allowed is set direction)
if deleteend = 1, then delete N or C term residue if if long side chain
If iside =1 - then add cb2 and test density
   else - just test cb2 density
*/
{
   int i,j,k;
   float denat,fd[3]; 
   float length,newlength; // = distance from Ca to end of side chain - IF this lenght is less than previous length, then do not use

   for(i=geo.nend[0]+1;i<geo.nend[1];i++){ // The residues that have side chains
    if(geo.iside[i]>=0){ // On find side if not an a.a. residue
      denat = aveatom(den1,geo,5,i,geo.pos); // density of Cb1
      if(denat<geo.sideden){ //If cb1 in bad density, then set iside =1 and quit
         geo.iside[i]=1;
         goto nextres;
      }      
      if(geo.iside[i]==1)
            bestcb1(den1,geo,geo.pos,i,&denat); // place second C in best postion
      else // Use previous value of Cb2 position
         denat = aveatom(den1,geo,6,i,geo.pos); // density of Cb2
      if(denat<geo.sideden){
         geo.iside[i]=1;
         goto nextres;
      }
      j=2; // If reach here, then there are 2 good side atoms
      length = distv(geo.pos[i][1],geo.pos[i][4+j]);
      while(j<=geo.maxside-1){ // allow maximum of maxside side atoms
        xtof(den1,geo.pos[i][4+j],fd); /*Check if side atom close to boundary convert from double word to float sccreen*/
        for(k=0;k<=2;k++){
           if( (fd[k]<3)||(fd[k]>den1.amax[k]-den1.amin[k]-2) ){
//if(verbose >=1)
  fprintf(fpout,"Point too close to boundary in sidenum - quit extending sidechain\n");
              geo.iside[i]=j;
              goto nextres;
           }
        }
        j= j+1;
        bestcbn(den1,geo,geo.pos,i,j,&denat);
        if(denat<geo.sideden){ // If density of sidechain atom bad, do not use this atom
           geo.iside[i]=j-1;
           goto nextres;
        }
       if(j>=4){ // check for collision with the atoms on same residue
         for(k=1;k<= 4+j -3;k++){  
           if(distv(geo.pos[i][4+j],geo.pos[i][k]) < 2.0){
//fprintf(fpout,"collision between atom %d and atom %d on residue %d\n",k,
             geo.iside[i]=j-1;
             goto nextres;
           }
         } //k
       }// j>4
        newlength = distv(geo.pos[i][1],geo.pos[i][4+j]);
        if(newlength < length){
                 geo.iside[i]=j-1;
                 goto nextres;
        }
        else
            length = newlength;
      } // while
      geo.iside[i]= geo.maxside; // If reach here, j msut = 5
      nextres:;
   } // geo.iside > 0
  } //i
if(deleteend==1){ 
  if(geo.iside[ geo.nend[0]+1 ] == 5){
      geo.nend[0] = geo.nend[0]+1;
      fprintf(fpout,"Deleting N term end because long side chain\n");
   }
   if(geo.iside[ geo.nend[1]-1 ] == 5){
      geo.nend[1] = geo.nend[1]-1;
      fprintf(fpout,"Deleting C term end because long side chain\n");
   }
}
}

void finddist(struct geometry& geo)
/*  Finds straight distance (geo.helstdist,geo.shstdist) = dist
        from ca[ibeg] to ca[iend]
  and curve dist (geo.helcurdist, geo.shcurdist = dist 
       from atom to atom  along mainchain
  begining at Ca[1] and ending at Ca[geo.nstartres+1]
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
NOTE: geo.nstartres = 3, Ca[1 to 4}
*/
{
   int i,ibeg,iend,itype;
   float dist;

//geo.nstartres = 12; // for debugging - make long ideal helix or sheet
   ibeg = 1;
   iend = geo.nstartres+1;
   for(itype = 1;itype<=2;itype++){ // helix =1, sheet = 2
       maketestpep(geo,geo.pos,geo.nstartres,geo.phi[itype],
          geo.psi[itype]); 
       geo.stdist[itype] = distv(geo.pos[ibeg][1],geo.pos[iend][1]);//Dist between end Ca's
       dist = 0;
       for(i=ibeg;i<iend;i++){ // # residues = number Ca's -1  
          dist = dist +distv(geo.pos[i][1],geo.pos[i][2]);
          dist = dist + distv(geo.pos[i][2],geo.pos[i+1][4]); 
          dist = dist + distv(geo.pos[i+1][4],geo.pos[i+1][1]);
       }
       geo.curdist[itype] = dist;
    }
#if 1 //ideal stdist (10.467) too long  and curve dist(12.945) too short for typical sheet
   geo.stdist[2] = 9.0; 
   geo.curdist[2] = 14.0; 
#endif 
//if(verbose >=1)
  fprintf(fpout,"Helix:  straight dist = %5.3f  curve dist = %5.3f  Sheet:  straight dist = %5.3f  curve dist = %5.3f\n",
         geo.stdist[1],geo.curdist[1],geo.stdist[2],geo.curdist[2]);
endfind:;
} 

void printgeopar(struct geometry& geo)
{
   fprintf(fpout,"nstartres = %d  nbadend=%d  nbadwhole = %d  extendden = %5.3f sideden = %5.3f\n",
       geo.nstartres,geo.nbadend,geo.nbadwhole,geo.extendden,geo.sideden);   
   fprintf(fpout,"nbadend = %d  angweight = %5.3f  bondwt = %5.3f  minrigid = %5.3f\n",
        geo.nbadend,geo.angweight,geo.bondwt,geo.minrigid); 
}

void saveonefit(FILE *fp,struct pepfit fit[],int i,int inum)
/* 
Writes fit[i] to file fp, giving it the number inum in the file
    usually i = inum;
*/
{
  int ii,j,jj,k,count,rottype,atomname;
  int ireside;

     fprintf(fp,"Fit %d   startendpt %d %d \n",
               inum,fit[i].val1,fit[i].val2);
     if(fit[i].irank[0]>0){ 
        for(j=1;j<=fit[i].irank[0];j++)
           fprintf(fp," %d  %f",fit[i].irank[j],fit[i].den[j]);
        fprintf(fp,"\n");      
     }
     fit[i].nside[0]=fit[i].nside[ fit[i].nres-1  ] = 0; // No side chains on first, last residue
     for(k=0;k<=2;k++){// N not defined for first res, C,O not defined for last
        j=0;ii=4;// N
        fit[i].pos[j][ii][k]=0.0;
        j= fit[i].nres-1;
        ii= 2; //C
        fit[i].pos[j][ii][k]=0.0;
        ii= 3; //C
        fit[i].pos[j][ii][k]=0.0;
     }
     fprintf(fp," %d\n",fit[i].nres); //# of residues in each fit
     for(j=0;j<fit[i].nres;j++) // Constrait type of each residue (no constraint last residue)
        fprintf(fp," %d",fit[i].itype[j]);
     fprintf(fp,"\n");
     for(j=0;j<fit[i].nres;j++) // # 0f sides on each residue
        fprintf(fp," %d",fit[i].nside[j]);
     fprintf(fp,"\n");
     ireside = 0;
     for(j=1;j<fit[i].nres-1;j++){ // check if side is amino acid
       if(fit[i].nside[j]<=0){ // then at least one side  is a residue
          ireside = 1;
          goto foundneg;
       }
     }
     foundneg:;
     if(ireside == 1){ // Then must read rotomer infor for each residue.
       for(j=1;j<fit[i].nres-1;j++) 
           fprintf(fp," %d",fit[i].irot[j]);
       fprintf(fp,"\n");
     }
     for(j=0;j<fit[i].nres;j++){ // each residue
       if( (j==0)||(j==fit[i].nres-1)||(fit[i].nside[j]>=0) ){// then side not residue
         for(ii=1;ii<=4+fit[i].nside[j];ii++) // all atom positions per reisude 
          for(k=0;k<3;k++) // x y z 
            fprintf(fp," %f",fit[i].pos[j][ii][k]);  
       } // side not residue
       else{ // side = residue
          for(ii=1;ii<=4;ii++){ // main chain atoms
             for(k=0;k<3;k++) // x y z 
               fprintf(fp," %f",fit[i].pos[j][ii][k]); 
          }
          rottype=  -fit[i].nside[j]; // residue name (number)
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                for(k=0;k<3;k++) // x y z 
                   fprintf(fp," %f",fit[i].pos[j][count+5][k]);
              } // atopmname
              else // = 5 = Cb
                for(k=0;k<3;k++) // x y z 
                  fprintf(fp," %f",fit[i].pos[j][atomname][k]);
            }// jj
          }//ii
       } // side = residue
       fprintf(fp,"\n");
     } // j  each residue 
}


void savefitcheckbone(struct griddata& den1,struct geometry& geo,struct bonedata& bone)
/* 
NOT USED anymore -
Similar to savefit, but deletes fits that are bad based
 on bones 
New Do not save if length is less then geo.savlen -1
*/
{
   int i,count;
   FILE *fp;
   char str[300];

   bonedist(den1,geo,bone); // returns fit[ifit].itemp[0] = 0 if bad, 1 if good
   strcpy(str,"copy ");
   strcat(str,maidfile.fitfile);
   strcat(str," fit.backup");
   system(str);  // Write backup file 
   fp= fopen(maidfile.fitfile,"w");
   count=0;
   for(i=1;i<=fitnum[0];i++){
      if( (fit[i].nres-1)<(geo.savlen-1) ) 
        printf("Deleting fit %d length = %d < %d\n",i,fit[i].nres-1,geo.savlen-1);
      else if(fit[i].itemp[0]!=1)
        printf("Deleting fit %d because itemp[0] !=1\n",i);
      else // do not delete
         count = count+1;
   }
   fprintf(fp,"%d\n",count); // total  # of fits
   printf(" %d fits have good bones and will be saved\n",count);
   count = 0;
   for(i=1;i<=fitnum[0];i++){
      if((fit[i].itemp[0]==1)&& ((fit[i].nres-1)>=(geo.savlen-1)) ){// fit.nres-1 = geo.nend[1]-geo.nend[0]
         count = count+1;
         saveonefit(fp,fit,fitnum[i],count);
      }
   }
   fclose(fp);  
fprintf(fpout,"Writing fit to backup %s and Saving  new fit %s \n","fit.backup",maidfile.fitfile);
   readfit(geo,maidfile.fitfile);
}

void savebackupfit(char backupfile[])
/* Copies current fit to backup with name backupfile
*/
{
   char str[300];

   fprintf(fpout,"COPY FIT %s to backup file %s \n",maidfile.fitfile,backupfile);
   strcpy(str,"copy ");
   strcat(str,maidfile.fitfile);
   strcat(str," ");
   strcat(str,backupfile);
   system(str);  // Copy backup file 
}


void savefit()
/*  Saves fits determilned by trace - and write backup to fit.backup
  Just saved into consecutive bins -
    not the set of bins that is output by trace
 fit residues run from 0,1,2 ... (fit[ fitnum[i] ].nres-1)
*/
{
   int i;
   FILE *fp;
   char str[300];

fprintf(fpout,"Writing fit to backup %s and Saving  new fit (%d fits) %s \n","fit.backup",fitnum[0],maidfile.fitfile);
   strcpy(str,"copy ");
   strcat(str,maidfile.fitfile);
   strcat(str," fit.backup");
   system(str);  // Write backup file 
   fp= fopen(maidfile.fitfile,"w");
   fprintf(fp,"%d\n",fitnum[0]); // total  # of fits
   for(i=1;i<=fitnum[0];i++)
      saveonefit(fp,fit,fitnum[i],fitnum[i]);
   fclose(fp);  
}

void freepepfit(struct pepfit& fit)
{
        freefmat3(fit.pos,fit.nalloc,NAA,3);
        freeimat3(fit.itemp2,fit.nalloc,5,2);
        freefmat3(fit.ftemp,fit.nalloc,5,2); // temp float variable for each main chain atom
        delete []fit.nside;
        delete []fit.itype;
        delete []fit.irank;
        delete []fit.den;
        delete []fit.cis;
        delete []fit.irot;
}

void allocatefit(struct pepfit& fit,int nalloc)
/* Note ftemp and itemp2 only used for bonedist - which is no longer used
*/ 
{
   int i;
   if(nalloc > fit.nalloc){ // then must allocate fit
     if(fit.nalloc>0){  // allready exists
        freepepfit(fit);
     }
     if(verbose>=2)
        fprintf(fpout,"Allocating fit\n");
     fit.nalloc = nalloc;
     fmat3(fit.pos,nalloc,NAA,3); // allocate new memory
     fit.nside = new int[nalloc];
     fit.irot = new int[nalloc]; // the best rotomer for each side
     fit.itype = new int[nalloc];
     fit.cis = new int[nalloc];
     fit.irank = new int[NAFIT];
     fit.den = new float[NAFIT];
     for(i=0;i<nalloc;i++) // as default set to trans proline
        fit.cis[i] = 0;
     fit.rankfit[0]=0; // Default - reset in readfit or readrankedfitF
     fit.main[0] = fit.main[1] = fit.main[2]= 0; // default - indicates have not yet assigned main bone
     fit.irank[0]=0;  // no previous rankings
     fmat3(fit.ftemp,nalloc,5,2); // temp float variable for each main chain atom
     imat3(fit.itemp2,nalloc,5,2); // allocate new memory
  }//if(nalloc > fit.nalloc
}   

void readonefit(FILE *fp,struct pepfit fit[],int irank0,int i)
/*
 New  - input value of fit[i].irank[0] = irank0
   and read fit[].irank[i] into temp file irank[i]
 Then allocate and copy irank[] into fit.irank
 NEW_  SET cbden = 1 by default
 Read the ith fit in fitfile, label it the ith fit, even if fitnum[i] does
     equal i;
*/
{
   int ii,j,jj,k,n0,irank[NAFIT],count,rottype,atomname;
   int ireside;
   float den[NAFIT];
   char sjunk[200];
   float ang,mag1,mag2,cacv[3],ncav[3]; // used for cis/trans proline

     fscanf(fp,"%s %d  %s %d %d",
             sjunk,&fitnum[i],sjunk,&fit[i].val1,&fit[i].val2);
if(verbose>=2)
  fprintf(fpout,"Reading fit %d: val1 = %d  val2= %d\n",
            i,fit[i].val1,fit[i].val2);
     if(irank0>0){// read previous rankings
        for(ii=1;ii<=irank0;ii++) 
            fscanf(fp,"%d%f",&irank[ii],&den[ii]);
     }
     fscanf(fp,"%d",&n0);
     fitnum[i] = i; // renumber fits so run consecuatively
     if(i> NFIT-1){
       printf("ERROR:  i > NFIT in readonefit\n");
       goto quitrout;
     }
     allocatefit(fit[i],n0+1);
     fit[i].rankfit[0]=i; //= fitnum  Only one fit per rankfit set
     fit[i].rankfit[1]=1; // Number of ranked fit in rank set
     fit[i].irank[0]=irank0;
     for(ii=1;ii<=fit[i].irank[0];ii++){ 
         fit[i].irank[ii] = irank[ii];
         fit[i].den[ii] = den[ii];
     }
     fit[i].nres = n0;
     fit[i].nside[0]=fit[i].nside[ fit[i].nres-1 ] =0; //New 1aug- set these defaults
     for(j=0;j<=fit[i].nres;j++)
         fit[i].cis[j]=0; // default value - trans
     for(j=0;j<fit[i].nres;j++){ // each residue (no constrintlast residue
        fscanf(fp,"%d",&fit[i].itype[j]);
     } // j
     for(j=0;j<fit[i].nres;j++){ // each residue (no side chain last residue
        fscanf(fp,"%d",&fit[i].nside[j]);
     }
     ireside = 0;
     for(j=1;j<fit[i].nres-1;j++){ // check if side is amino acid
       if(fit[i].nside[j]<=0){ // then at least one side  is a residue
          ireside = 1;
          goto foundneg;
       }
     }
     foundneg:;
     if(ireside == 1){ // Then must read rotomer infor for each residue.
       for(j=1;j<fit[i].nres-1;j++) 
           fscanf(fp,"%d",&fit[i].irot[j]);
     }
     else{ // assign irot = 0;
       for(j=1;j<fit[i].nres-1;j++) 
           fit[i].irot[j] = 0;
     }
     for(j=0;j<fit[i].nres;j++){ // each residue
       if( (j==0)||(j==fit[i].nres-1)||(fit[i].nside[j]>=0) ){// then side not residue
          for(ii=1;ii<=4+fit[i].nside[j];ii++) // main chain plus side chain atoms
             for(k=0;k<3;k++) // x y z 
               fscanf(fp,"%f",&fit[i].pos[j][ii][k]); 
       } 
       else{ // side = residue
           for(ii=1;ii<=4;ii++){ // main chain atoms
             for(k=0;k<3;k++) // x y z 
               fscanf(fp,"%f",&fit[i].pos[j][ii][k]); 
          }
          rottype=  -fit[i].nside[j]; // residue name (number)
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                for(k=0;k<3;k++) // x y z 
                   fscanf(fp,"%f",&fit[i].pos[j][count+5][k]);
              } // atopmname
              else // = 5 = Cb
                for(k=0;k<3;k++) // x y z 
                  fscanf(fp,"%f",&fit[i].pos[j][atomname][k]);
            }// jj
          }//ii
       } // side = residue
    } // j  each residue
    for(j=1;j<fit[i].nres-1;j++){ // check whether cis or trans proline
       if(fit[i].nside[j]== -PRO){ // check whether cis or trans
          for(k=0;k<=2;k++){
              cacv[k] = fit[i].pos[j-1][2][k] -fit[i].pos[j-1][1][k]; 
              ncav[k] = fit[i].pos[j][1][k] -fit[i].pos[j][4][k];
          }
          mag1 = sqrt( dot(cacv,cacv));
          mag2 = sqrt( dot(ncav,ncav));
          ang = acos(  dot(cacv,ncav)/(mag1*mag2) ); 
          if(ang*180.0/PI > 50.0){
             fit[i].cis[j] = 1;
             if(verbose>=1)
                printf(" For fit %d Proline %d is CIS\n",i,j); // NOTE default is trans, set above
          }
       }
    }
    quitrout:;
}  

void readrankfit(char rankedfile[],int *nrank, struct pepfit fits[],int ifirst)
// reads a set of ranked fit files - usually all from same extended fit
{
   FILE *fp;
   int i,numprevranks,irank0,nend;

            if( (fp=fopen(rankedfile,"r")) == NULL){
               fprintf(fpout,"ERROR: ranked file %s does not exist\n",rankedfile);
               exit(0);
            }
            else{ // rankedfile opend   
               fscanf(fp,"%d",nrank); // total  # of ranked fits;
//               fitnum[0] = *nrank; 
               fitnum[0] = ifirst -1 + *nrank; 
               fscanf(fp,"%d",&numprevranks);
//               for(j=1;j<= *nrank;j++){ // each fit
               for(i=ifirst;i< ifirst+*nrank;i++){ // each fit
//                  i=ifirst+j-1;
                  irank0=numprevranks; // assign number of  rankings
                  readonefit(fp,fits,irank0,i);
               }
//             for(i=1;i<= *nrank;i++) // print value of main for each fit  
               for(i=ifirst;i< ifirst+*nrank;i++) // each fit
                 fscanf(fp,"%d %d %d",&fits[i].main[0],&fits[i].main[1],&fits[i].main[2]);
               fprintf(fpout,"Starting with ranked fitfile %s; nrank = %d nres #1 = %d\n",
                    rankedfile,*nrank,fits[ifirst].nres);
//               for(i=1;i<= *nrank;i++){
               for(i=ifirst;i< ifirst+*nrank;i++){ // each fit
                  nend = fits[i].nres-1;
                  printf("    fit %d:  main[0,1,2] = %d %d %d type %d %d %d den = %5.3f\n",
                     i,fits[i].main[0],fits[i].main[1],fits[i].main[2],
                     fits[i].itype[nend-3],fits[i].itype[nend-2],
                     fits[i].itype[nend-1],fits[i].den[fit[i].irank[0]]);
              }
            }
            fclose(fp);
}


void readfit(struct geometry& geo, const char fitfile[])
// read each fit into consecutively numbered bines
// If fitnum[i] is not consecutive - MAKE it consecutive
{
   int i,irank0,totres;
   FILE *fp;
//   Widget widget; 

 totres = 0;
 if( (fp=fopen(fitfile,"r")) == NULL){
     fitnum[0] = 0; // indicates no fit residues
#if 0  // do not use error message because it requires screen functions - not use in batch mode
         errormessage(toplevel,"ERROR: There are no fit files");
#endif
     fprintf(fpout,"ERROR: There are no fit files\n" );
 }
 else{ //fitfile opened
   fscanf(fp,"%d",&fitnum[0]); // total  # of fits;
   fprintf(fpout,"Reading %d fits from fitfile %s\n",fitnum[0],fitfile);
   for(i=1;i<=fitnum[0];i++){ // each fit
     irank0=0;  // there are no rankings for files read in readfit
     readonefit(fp,fit,irank0,i);
     totres = totres +fit[i].nres-1;
   }// each fit 
   fclose(fp);  
 } // fitfile exists 
 printf(" TOTAL NUMBER OF RESIDUES =  %d\n",totres);
 geo.fuse[0] = geo.fuse[1] = geo.fuse[2] = -1;  //Default values
// geo.fixend = 0;  // NEW commented out 5may00
}

float qualfunc(struct geometry& geo,int nbad,float lastden,float avecb2)
// Places heavy weighting on whatever avecb2 corresponds to (usually = avecb)
// Function that determine overall quallity of fit
{
   float qual;
#if 0 // older version - use most of 1998
   qual = lastden + avecb2/2.0 - ( (float)nbad/(geo.nend[1]-geo.nend[0]-1) )*geo.nbadwt;
#endif
#if 1 // newer version - more of subtraction for nbad
   qual = lastden + avecb2/2.0 - ( (float)2.0*nbad/(geo.nend[1]-geo.nend[0]-1) )*lastden;
#endif
   qual = (1.0 + (geo.nend[1]-geo.nend[0])/20.0 )*qual;// increase qual by 5% for each residue
//   qual = (1.0 + (geo.nend[1]-geo.nend[0])/10.0 )*qual;// increase qual by 10% for each residue
   return qual;
}

int checksphere(float pos[3],float sprad2[NSPHERES])
/* check if point is contained 1 of the spheres 
Returns 1 if in spheres, 0 if not
*/
{
  int i,k; 
  float dist2;

  for(i=1;i<=maidfile.nsphere;i++){
    dist2=0.0;
    for(k=0;k<=2;k++)
        dist2=dist2+ sqr(pos[k]-sp[i].cenpos[k]);
    if(dist2<sprad2[i])
       return 1;
  }
  return 0;
}     

#if 0  // Old version - not correct for non-rectangular grid
int checkboundary(struct griddata& den1,float pos[NAFIT][NAA][3],
     int atomnum,int resnum,float arange)
// check if atomnum in residue resnum is with arange of boundary
{
   int i;
  
   for(i=0;i<=2;i++){
       if( (pos[resnum][atomnum][i]< den1.ximin[i]+arange) ||
           (pos[resnum][atomnum][i]> den1.ximax[i]-arange) )
           return 0;
   }
   return 1;
}
#endif

int checkboundary(struct griddata& den1,float pos[NAFIT][NAA][3],
     int atomnum,int resnum,float arange)
/*
 New version - first convert to interger - then check
 check if atomnum in residue resnum is with arange of boundary
*/
{
   int k,ig[3];

   xtoi(den1,pos[resnum][atomnum],ig);
   for(k=0;k<=2;k++)
     ig[k]=ig[k]+0.5; /*rounds to  nearest grid point*/
   for(k=0;k<=2;k++){ // check if pos in density range
      if( (ig[k]<2)|| (ig[k]>den1.amax[k]-den1.amin[k]-2) )
         return 0;
   }
   return 1;
}


int checkatomlab(struct griddata& den1,struct geometry& geo,int ***set,float pos[3])
/*
MOdified checkatom() -
   now returns number of fit it met
*/
{
   int i,k,ig[3];
   float ijk[3];

   xtof(den1,pos,ijk); /*convert from world co-ord to floating grid i,j,k co-ord*/
   for(k=0;k<=2;k++)
     ig[k]=ijk[k]+0.5; /*rounds to  nearest grid point*/
   for(k=0;k<=2;k++){ // check if pos in density range
      if( (ig[k]<1)|| (ig[k]>den1.amax[k]-den1.amin[k]-1) ){
         if(verbose>=2)
             fprintf(fpout," ERROR in checkatomlab() : res out of range ,returning 0\n");
         return 0;
      }
   }
   i=set[ig[0]][ig[1]][ig[2]];
   if(i <0 )
      return i;
   else
      return 1;  // if reach here, no point near set = -1
}        

int checkatom(struct griddata& den1,struct geometry& geo,int ***set,float pos[3])
/*
NEW: just check nearest point to Ca and N - since set atom set all 
  points within geo.setrad
OLD : Checks if pt = pos is within geo.setrad of a grid pt with set = -1
  If it is, returns 0, else returns 1 (OK)
*/
{
   int k,ig[3];
   float ijk[3];

   xtof(den1,pos,ijk); /*convert from world co-ord to floating grid i,j,k co-ord*/
   for(k=0;k<=2;k++)
     ig[k]=ijk[k]+0.5; /*rounds to  nearest grid point*/
   for(k=0;k<=2;k++){ // check if pos in density range
      if( (ig[k]<1)|| (ig[k]>den1.amax[k]-den1.amin[k]-1) ){
         if(verbose>=2)
             fprintf(fpout," ERROR in checkatom() : res out of range ,returning 0\n");
         return 0;
      }
   }
#if 1 // new version
   if(set[ig[0]][ig[1]][ig[2]] <0 )
      return 0;
   else
      return 1;  // if reach here, no point near set = -1
#endif
#if 0
   int i1,i2,i3;
   for(i1= ig[0]-geo.setrad;i1<= ig[0]+geo.setrad;i1++)
     for(i2= ig[1]-geo.setrad;i2<= ig[1]+geo.setrad;i2++)
       for(i3= ig[2]-geo.setrad;i3<= ig[2]+geo.setrad;i3++){
          if(set[i1][i2][i3] == -1)
             return 0;
       }
   return 1;  // if reach here, no point near set = -1
#endif
}        

int checksetcterm(struct griddata& den1,struct geometry& geo,int ***set,int ica)
/* 
 checks last Ca and N to see if with geo.setrad of a grid pt with set = -1
  ica  = geo.nend[1] after the extensiion - thus last residue corresponds to
    ica
  returns 0 if not OK  (near set = -1), 1 if OK
*/
{
    int i1,i2;
    
    i1 = checkatomlab(den1,geo,set,geo.pos[ica][1]);
    i2 = checkatomlab(den1,geo,set,geo.pos[ica][4]);
    if( i1<=0 )
        return i1;  
    else if(i2<=0)
        return i2;
    else
        return 1; 
}

int checksetnterm(struct griddata& den1,struct geometry& geo,int ***set,int ica)
/* checks first Ca,C and O to see if with geo.setrad of a grid pt with set = -1
  returns 0 if not OK  (near set = -1), 1 if OK
*/
{
    int i1,i2,i3;

    i1 =  checkatomlab(den1,geo,set,geo.pos[ica][1]); 
    i2 =  checkatomlab(den1,geo,set,geo.pos[ica][2]);
    i3 =  checkatomlab(den1,geo,set,geo.pos[ica][3]);
    if(i1  <= 0) // first Ca
        return i1; 
    else if (i2<=0)   // first Co
           return i2;
    else if(i3  <= 0) // first O        
           return i3; 
    else
        return 1; 
}

void setatom(struct griddata& den1,struct geometry& geo,int ***set,
    float pos[3],int val)
/*
 Sets all grid points within geo.setrad gridpoints of atom = val (normally = -1);
*/
{
   int i1,i2,i3,k,ig[3];
   float ijk[3];

   xtof(den1,pos,ijk); /*convert from world co-ord to floating grid i,j,k co-ord*/
   for(k=0;k<=2;k++)
     ig[k]=ijk[k]+0.5; /*rounds to  nearest grid point*/
   for(k=0;k<=2;k++){ // check if pos in density range
      if( ((ig[k]-geo.setrad)<0)|| ((ig[k]+geo.setrad)>den1.griddim[k]-1) ){
         if(verbose>=2)
            fprintf(fpout," ERROR:  out of range in seteatom - do not set (ig[%d]=%d),\n",k,ig[k]);
         goto quitrout;
      }
   }
   for(i1= ig[0]-geo.setrad;i1<= ig[0]+geo.setrad;i1++)
     for(i2= ig[1]-geo.setrad;i2<= ig[1]+geo.setrad;i2++)
       for(i3= ig[2]-geo.setrad;i3<= ig[2]+geo.setrad;i3++){
          set[i1][i2][i3] = val;
#if 0 // for debugging
          if((i1==50)&&(i2==58)&&(i3==19) )
            printf("\n");
#endif
       }
   quitrout:;
}        

void setendpts(struct griddata& den1,struct geometry& geo,int ***set)
/*
NOTE: Does not set O
Sets Ca-C-N-Ca-C at nterm
Sets N-Ca-C-N-Ca at cterm
Only sets the points at the end of the fit
Sets all grid points within geo.setrad of mainchain
   (including Cb atoms)   = val = -1 ;
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
*/
{
   int i,val;

   val = geo.setval;
   i=geo.nend[0]+1; 
      setatom(den1,geo,set,geo.pos[i-1][1],val);   
      setatom(den1,geo,set,geo.pos[i-1][2],val);   
//      setatom(den1,geo,set,geo.pos[i-1][3],val);
      setatom(den1,geo,set,geo.pos[i][4],val);
   i=geo.nend[0]+2; 
      setatom(den1,geo,set,geo.pos[i-1][1],val);   
      setatom(den1,geo,set,geo.pos[i-1][2],val);   
   i=geo.nend[1]; 
      setatom(den1,geo,set,geo.pos[i-1][4],val);   
      setatom(den1,geo,set,geo.pos[i-1][1],val);   
      setatom(den1,geo,set,geo.pos[i-1][2],val);   
//      setatom(den1,geo,set,geo.pos[i-1][3],val);
      setatom(den1,geo,set,geo.pos[i][4],val); 
      setatom(den1,geo,set,geo.pos[i][1],val);   
}

#if 0 // Used up to 30aug00 - Sets too many atoms at end
void setendptsfit(struct griddata& den1,struct geometry& geo,
       struct pepfit& fit,int ***set)
/*
Similar to setendpts but uses fit instead of geo
NOTE: Does not set O
Sets Ca-C-N-Ca-C at nterm
Sets N-Ca-C-N-Ca at cterm
Only sets the points at the end of the fit
Sets all grid points within geo.setrad of mainchain
   (including Cb atoms)   = val = -1 ;
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
*/
{
   int i,val;

   val = geo.setval;
   i=1; 
      setatom(den1,geo,set,fit.pos[i-1][1],val);   
      setatom(den1,geo,set,fit.pos[i-1][2],val);   
//      setatom(den1,geo,set,fit.pos[i-1][3],val);
      setatom(den1,geo,set,fit.pos[i][4],val);
   i=2; 
      setatom(den1,geo,set,fit.pos[i-1][1],val);   
      setatom(den1,geo,set,fit.pos[i-1][2],val);   
   i=fit.nres-1; 
      setatom(den1,geo,set,fit.pos[i-1][4],val);   
      setatom(den1,geo,set,fit.pos[i-1][1],val);   
      setatom(den1,geo,set,fit.pos[i-1][2],val);   
//      setatom(den1,geo,set,fit.pos[i-1][3],val);
      setatom(den1,geo,set,fit.pos[i][4],val); 
      setatom(den1,geo,set,fit.pos[i][1],val);   
}
#endif
#if 1 //New try only setting terminal 3 atoms AND O
void setendptsfit(struct griddata& den1,struct geometry& geo,
       struct pepfit& fit,int ***set)
/*
NOTE: Does not set O
Sets Ca-C- at nterm
Sets N-Ca at cterm
Only sets the points at the end of the fit
Sets all grid points within geo.setrad of mainchain
   (including Cb atoms)   = val = -1 ;
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
*/
{
   int i,val;

   val = geo.setval;
   i=1; 
      setatom(den1,geo,set,fit.pos[i-1][1],val);   
      setatom(den1,geo,set,fit.pos[i-1][2],val);   
      setatom(den1,geo,set,fit.pos[i-1][3],val);   
      setatom(den1,geo,set,fit.pos[i][4],val);
   i=fit.nres-1; 
      setatom(den1,geo,set,fit.pos[i][4],val); 
      setatom(den1,geo,set,fit.pos[i][1],val);   
      setatom(den1,geo,set,fit.pos[i-1][2],val);   
      setatom(den1,geo,set,fit.pos[i-1][3],val);   
}
#endif

void setonesidefit(int i,struct griddata& den1,struct geometry& geo,
      struct pepfit& fit,int ***set,int setside)
/*
Similar to setoneside but use fit instead of geo
If setside = -1 then set sidepoints and mainpts
If setside = n>=1 then set   mainpts and n side pts
If setside = 0, then do not set any side atoms
*/
{
   int ii,jj,val,count,rottype,atomname,maxside;

   val = geo.setval;

      if(setside== -1){  // set all side atoms
        if(fit.nside[i]>=0){
           for(ii=5;ii<=4+fit.nside[i];ii++)
             setatom(den1,geo,set,fit.pos[i][ii],val);
        }
        else{  
          rottype=  -fit.nside[i];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                setatom(den1,geo,set,fit.pos[i][count+5],val);
              } // atopmname
              else
                 setatom(den1,geo,set,fit.pos[i][atomname],val);
            }// jj
          } //ii
        }// else
      } // setside = 1 
      else if(setside >= 1){ // then set setside side atoms
        if(fit.nside[i]>=0){
           if(fit.nside[i]>setside)
               maxside = setside;
           else
               maxside = fit.nside[i];
           for(ii=5;ii<=4+maxside;ii++)
             setatom(den1,geo,set,fit.pos[i][ii],val);
        }
#if 0
        if(fit.nside[i]>=0){
           if(fit.nside[i]>setside+1)
               maxside = setside+1;
           else
               maxside = fit.nside[i];
           for(ii=5;ii<=4+maxside;ii++)
             setatom(den1,geo,set,fit.pos[i][ii],val);
        }
#endif
        else{  
          rottype=  -fit.nside[i];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                setatom(den1,geo,set,fit.pos[i][count+5],val);
              } // atopmname
              else
                 setatom(den1,geo,set,fit.pos[i][atomname],val);
              if(count==setside-1)
                 goto quitrout;
            }// jj
          } //ii
        }// else
      } // setside = 1 
      quitrout:;
}

void setoneside(int i,struct griddata& den1,struct geometry& geo,int ***set,int setside)
/*
If setside = -1 then set sidepoints and mainpts
If setside = n>=1 then set   mainpts and n side pts
If setside = 0, then do not set any side atoms
*/
{
   int ii,jj,val,count,rottype,atomname,maxside;

   val = geo.setval;

      if(setside== -1){  // set all side atoms
        if(geo.iside[i]>=0){
           for(ii=5;ii<=4+geo.iside[i];ii++)
             setatom(den1,geo,set,geo.pos[i][ii],val);
        }
        else{  
          rottype=  -geo.iside[i];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                setatom(den1,geo,set,geo.pos[i][count+5],val);
              } // atopmname
              else
                 setatom(den1,geo,set,geo.pos[i][atomname],val);
            }// jj
          } //ii
        }// else
      } // setside = 1 
      else if(setside >= 1){ // then set setside side atoms
        if(geo.iside[i]>=0){
           if(geo.iside[i]>setside)
               maxside = setside;
           else
               maxside = geo.iside[i];
           for(ii=5;ii<=4+maxside;ii++)
             setatom(den1,geo,set,geo.pos[i][ii],val);
        }
        else{  
          rottype=  -geo.iside[i];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                setatom(den1,geo,set,geo.pos[i][count+5],val);
              } // atopmname
              else
                 setatom(den1,geo,set,geo.pos[i][atomname],val);
              if(count==setside)
                 goto quitrout;
            }// jj
          } //ii
        }// else
      } // setside >0 
      quitrout:;
}

void setsidepts(struct griddata& den1,struct geometry& geo,int ***set,int setside)
/*
If setside = -1 then set sidepoints and mainpts
If setside = n>=1 then set   mainpts and n side pts
If setside = 0, then do not set any side atoms
Set points  just for side chain atoms that are assigned to geo
   set = val = -1 (default)
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
*/
{
   int i;

   for(i=geo.nend[0]+1;i<geo.nend[1];i++){ 
      setoneside(i,den1,geo,set,setside);
   }// i
}

void setsideptsfit(struct griddata& den1,struct geometry& geo,
      struct pepfit& fit,int ***set,int setside)
/*
Similar to setsidepts except use fit instead of geo
If setside = -1 then set sidepoints and mainpts
If setside = n>=1 then set   mainpts and n side pts
If setside = 0, then do not set any side atoms
Set points  just for side chain atoms that are assigned to geo
   set = val = -1 (default)
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
*/
{
   int i;

   for(i=1;i<fit.nres-1;i++){ 
      setonesidefit(i,den1,geo,fit,set,setside);
   }// i
}

void setptsfit(struct griddata& den1,struct geometry& geo,struct pepfit& fit,
       int ***set,int setside)
/*
Same as setpts except uses fit instead of geo
If setside = -1 then set sidepoints and mainpts
If setside = n>=1 then set   mainpts and n side pts
If setside = 0, then do not set any side atoms
New Set points for all side chain atoms that are assigned to geo
Sets all grid points within geo.setrad of mainchain
   (including Cb atoms)   = val = -1 ;
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
*/
{
   int i,val;
//   int ii,jj,count,rottype,atomname,maxside;

   val = geo.setval;
   for(i=1;i<fit.nres-1;i++){ 
//   for(i=geo.nend[0]+1;i<geo.nend[1];i++){ 
      setatom(den1,geo,set,fit.pos[i-1][1],val);   
      setatom(den1,geo,set,fit.pos[i-1][2],val);   
      setatom(den1,geo,set,fit.pos[i-1][3],val);
      setatom(den1,geo,set,fit.pos[i][4],val);
      setonesidefit(i,den1,geo,fit,set,setside);
   }// i
   i=fit.nres-1;
      setatom(den1,geo,set,fit.pos[i-1][1],val);   
      setatom(den1,geo,set,fit.pos[i-1][2],val);   
      setatom(den1,geo,set,fit.pos[i-1][3],val);
      setatom(den1,geo,set,fit.pos[i][4],val); 
      setatom(den1,geo,set,fit.pos[i][1],val);
}

void setpts(struct griddata& den1,struct geometry& geo,int ***set,int setside)
/*
NEW 22jun00 - do not set end Ca', allow slight overlap
If setside = -1 then set sidepoints and mainpts
If setside = n>=1 then set   mainpts and n side pts
If setside = 0, then do not set any side atoms
New Set points for all side chain atoms that are assigned to geo
Sets all grid points within geo.setrad of mainchain
   (including Cb atoms)   = val = -1 ;
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
*/
{
   int i,val;
//   int ii,jj,count,rottype,atomname,maxside;

   val = geo.setval;
   for(i=geo.nend[0]+1;i<geo.nend[1];i++){ 
      setatom(den1,geo,set,geo.pos[i-1][1],val);   
      setatom(den1,geo,set,geo.pos[i-1][2],val);   
      setatom(den1,geo,set,geo.pos[i-1][3],val);
      setatom(den1,geo,set,geo.pos[i][4],val);
      setoneside(i,den1,geo,set,setside);
   }// i
   i=geo.nend[1];
      setatom(den1,geo,set,geo.pos[i-1][1],val);   
      setatom(den1,geo,set,geo.pos[i-1][2],val);   
      setatom(den1,geo,set,geo.pos[i-1][3],val);
      setatom(den1,geo,set,geo.pos[i][4],val); 
      setatom(den1,geo,set,geo.pos[i][1],val);   
   val = 0; // set end atoms back to original   
   setatom(den1,geo,set,geo.pos[geo.nend[0]][1],val);   
   setatom(den1,geo,set,geo.pos[geo.nend[1]][1],val);   
}


void powellmin(float *finalden,phead,float (*func)(float p[],phead))
/* Procedure using powell minimization using routines from C recipes
nvar = number of adjustble variables
type of minimization determined by function passed:
  i.e.  rigidfunc,   phipsi func
     itype = 1:  rigid - translation and orinetation about xaxis, zaxis, cafit
     itype = 2:  phipsi about C terminal Ca.
  1) Use file recipes,c++   define geo, etc.externally so that can 
      pass to function call
  2) WARNING:  Recipes always define arrays etc. as going from 1 ... NDIM        
  3) p[] is the array of variables that are adjucted to give minimum value 
    p[1,2,3] = translation x,y,z measured from initial postion
    p[4] = theta;   p[5] = phi   in polar spherical coord
    p[6], p[7] = phi psi for c term rotation 
      At start p is set to initial values
      At end: p is final minimum set of values
  4) xi is matrix of vectors describing initial direction of step
       usually just set to unit vector.
    I think that magnitude of vectors in xi set the initial step size
  5) ftol sets the minimum change when routine reaches miminmu
  6)
*/
{
       int i,iter,j;
       float fret,**xi;
       xi=matrix(1,NDIM,1,NDIM);
       for(i=0;i<=nvar;i++) // set initial values of p = 0
          pp[i] = 0.0;  
	for (i=1;i<=nvar;i++)
		for (j=1;j<=nvar;j++)
			xi[i][j]=(i == j ? 1.0 : 0.0); 
        itranlim = 1; // global variable passed to powell, checks for too large translation    
	powell(pfunc,pp,xi,nvar,FTOL,&iter,&fret,func);
        if(itranlim==0){
//           fprintf(fpout,"Quitting because too large translation\n");
           goto quitpowell;
        }
#if 0
if(verbose>=1){
	fprintf(fpout,"Minimum = %6.3f #iter = %d  At:",fret,iter);
	for (i=1;i<=nvar;i++) 
             fprintf(fpout," %6.3f",pp[i]);
	fprintf(fpout,"\n");
}
#endif
	free_matrix(xi,1,NDIM,1,NDIM);
        *finalden = -fret;
        quitpowell:;
}


void findgeophipsi(struct geometry& geo)
{
   int i;

   for(i=geo.nend[0];i<=geo.nend[1]-2;i++)
     findphipsi(geo.pos,i,&geo.phipsi[i][0],&geo.phipsi[i][1]);
if(verbose>=2){
   fprintf(fpout,"PHI/PSI = (degrees)  nend[0]=%d  nend[1] =%d:   \n",
       geo.nend[0],geo.nend[1]);
   for(i=geo.nend[0];i<=geo.nend[1]-2;i++)   
      fprintf(fpout,"   i=%d:  %5.3f   %5.3f\n",
           i,geo.phipsi[i][0]*180.0/PI,geo.phipsi[i][1]*180.0/PI);
}
}
            

void trancapep(struct geometry& geo,float pos[NAFIT][NAA][3],int n0,int ica,float capos[3])
/* translates n0 residue peptide
   moves  Ca[ica] to capos
*/
{
   int i,j,jj;
   float tran[3];
   
   for(i=0;i<=2;i++)
     tran[i] = capos[i] - pos[ica][1][i];
 for(i=0;i<=2;i++){
   for(j=1;j<=n0+1;j++)
     pos[j][1][i] = pos[j][1][i]+tran[i];
   for(j=2;j<=n0+1;j++)
     pos[j][4][i] = pos[j][4][i]+tran[i];
   for(j=1;j<=n0;j++){
     pos[j][2][i] = pos[j][2][i]+tran[i];
     pos[j][3][i] = pos[j][3][i]+tran[i];
   }
   for(j=2;j<=n0;j++){
     for(jj=1;jj<=geo.iside[j];jj++)
        pos[j][4+jj][i] = pos[j][4+jj][i]+tran[i];
   }
  }
}

void rotcapep(struct geometry& geo,float pos[NAFIT][NAA][3],int n0,
    float rotv[3],float orig[3],float ang)
/* rotates n0 residue peptide
  Rotates by ang about vector rotv with origin = origin of rotv 
  Can use routine rotatept - but it call rotaxis each time
    and therefore is inefficient 
*/
{
   int i,j;
   float rom[3][3];

   rotaxis(geo.de,geo.ep,ang,rotv,rom); /* rom is rotation matrix for rotation
         of chi about unit vector u2 which is assumed to be at origin*/  
   for(j=1;j<=n0+1;j++)
     rotateset(orig,pos[j][1],rom);
   for(j=2;j<=n0+1;j++)
     rotateset(orig,pos[j][4],rom);
   for(j=1;j<=n0;j++){
     rotateset(orig,pos[j][2],rom);
     rotateset(orig,pos[j][3],rom);
   }
   for(j=2;j<=n0;j++){
     for(i=1;i<=geo.iside[j];i++)
         rotateset(orig,pos[j][4+i],rom);
   }
}


void rotcapepnew(struct geometry& geo,float pos[NAFIT][NAA][3],float fpos[NAFIT][NAA][3],int n0,
    float rotv[3],float orig[3],float ang)
/* rotates n0 residue peptide
  Rotates by ang about vector rotv with origin of rotv 
  Can use routine rotatept - but it call rotaxis each time
    and therefore is inefficient 
*/
{
   int i,j;
   float rom[3][3];

   rotaxis(geo.de,geo.ep,ang,rotv,rom); /* rom is rotation matrix for rotation
         of chi about unit vector u2 which is assumed to be at origin*/  
   for(j=1;j<=n0+1;j++)
     rotatesetnew(orig,pos[j][1],fpos[j][1],rom);
   for(j=2;j<=n0+1;j++)
     rotatesetnew(orig,pos[j][4],fpos[j][4],rom);
   for(j=1;j<=n0;j++){
     rotatesetnew(orig,pos[j][2],fpos[j][2],rom);
     rotatesetnew(orig,pos[j][3],fpos[j][3],rom);
   }
   for(j=2;j<=n0;j++){
     for(i=1;i<=geo.iside[j];i++)
        rotatesetnew(orig,pos[j][4+i],fpos[j][4+i],rom);
   }
}


void copynterm(int nside,int i0,int i1,float pos0[NAFIT][NAA][3],float pos1[NAFIT][NAA][3])
/* copy pos0 to pos1  
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
  i0 = res. number of pos pos0  i1 = residue of pos1
*/
{
 int i,j;

  for(i=0;i<=2;i++){// copy N, Cb, Cc for i0+1 residue to residue i1+1  and Ca, C and O for i0  residue to residue i1
     for(j=1;j<=nside;j++)
        pos1[i1+1][4+j][i] = pos0[i0+1][4+j][i];
     pos1[i1+1][4][i] = pos0[i0+1][4][i];
     pos1[i1][3][i] = pos0[i0][3][i];
     pos1[i1][2][i] = pos0[i0][2][i];
     pos1[i1][1][i] = pos0[i0][1][i];
  }
}

void copycterm(int nside,int i0,int i1,float pos0[NAFIT][NAA][3],float pos1[NAFIT][NAA][3])
/* copy pos0 to pos1  
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
  i0 = res. number of pos pos0  i1 = residue of pos1
*/
{
 int i,j;

  for(i=0;i<=2;i++){// copy C,O, Cb, Cc for i0 residue and Ca, N for i0+1
     pos1[i1][2][i] = pos0[i0][2][i];
     pos1[i1][3][i] = pos0[i0][3][i];
     for(j=1;j<=nside;j++)
        pos1[i1][4+j][i] = pos0[i0][4+j][i];
     pos1[i1+1][4][i] = pos0[i0+1][4][i];
     pos1[i1+1][1][i] = pos0[i0+1][1][i];
  }
}

void copyavefpostopos(struct geometry& geo,int num)
/*  Copies the aveage value of fpos for two ends to geo.pos
*/
{
   int k;
   for(k=0;k<=2;k++){ // define pos of center residue
      geo.pos[ num-1 ][1][k] = (geo.fpos[0][1][k]+
              geo.fpos[1][1][k])/2.0 ; //nterm  Ca
      geo.pos[ num-1 ][2][k] = (geo.fpos[0][2][k]+
                           geo.fpos[1][2][k])/2.0  ;// C
      geo.pos[ num-1 ][3][k] = (geo.fpos[0][3][k]+
                           geo.fpos[1][3][k])/2.0  ;// O
      geo.pos[ num ][4][k] = (geo.fpos[0][4][k]+
                           geo.fpos[1][4][k])/2.0  ;// N
      geo.pos[ num ][1][k] = (  geo.fpos[0][6][k]+
                     geo.fpos[1][6][k])/2.0  ; //cterm  Ca
   }// k
}   

void copyfpostopos(struct geometry& geo,int num,int norc)
/* Used if dynamics in middle, saves end pos in geo.fpos
  fnum is number of central residue
  norc = 0 if saving end when move the nterm half
         1 if saveing  when move cterm half
*/
{
  int k;
  for(k=0;k<=2;k++){ // define pos of center residue
      geo.pos[ num-1 ][1][k] = geo.fpos[norc][1][k]; //nterm  Ca
      geo.pos[ num-1 ][2][k] = geo.fpos[norc][2][k];// C
      geo.pos[ num-1 ][3][k] = geo.fpos[norc][3][k]; // O
      geo.pos[ num ][4][k] = geo.fpos[norc][4][k];// N
      geo.pos[ num ][1][k] = geo.fpos[norc][6][k]; //cterm  Ca
 }// k
}
   
void copypostofpos(struct geometry& geo,int num,int norc)
/* Used if dynamics in middle,  geo.fpos to geo.pos
  fnum is number of central residue
  norc = 0 if saving end when move the nterm half
         1 if saveing  when move cterm half
*/
{
  int k;
  for(k=0;k<=2;k++){ // define pos of center residue
        geo.fpos[norc][1][k] = geo.pos[num-1][1][k]; // nterm Ca pos
        geo.fpos[norc][2][k] = geo.pos[num-1][2][k];// end C pos
        geo.fpos[norc][3][k] = geo.pos[num-1][3][k]; // end O pos
        geo.fpos[norc][4][k] = geo.pos[num][4][k];// end N pos
        geo.fpos[norc][6][k] = geo.pos[num][1][k]; // cterm Ca pos
  }// k
}

void copypos(int iside[],int n0,int i0,int i1,float pos0[NAFIT][NAA][3],float pos1[NAFIT][NAA][3])
/*
NOTE: on use of geo.nside and geo.iside   CONFUSING!!
  New version - pass geo.iside[] to copypos and copy
   Since copy routine (copypos), do not keep
     track of the nunmber of side chains  (i.e. does not copy value of geo.isdide[]- 
   MUST EITHER:
     1) have all residues have same number of side chains = geo.nside
     2) Have same start points for both positions - so that geo.iside is the same for both
 copy pos0 to pos1 - n0 residues peptide, pos0 starts at i0 and pos1 at i1
*/
{
 int i,j,jj;
 for(i=0;i<=2;i++){
   for(j=1;j<=n0+1;j++)
     pos1[i1+j-1][1][i] = pos0[i0+j-1][1][i];
   for(j=2;j<=n0+1;j++)
     pos1[i1+j-1][4][i] = pos0[i0+j-1][4][i];
   for(j=1;j<=n0;j++){
     pos1[i1+j-1][2][i] = pos0[i0+j-1][2][i];
     pos1[i1+j-1][3][i] = pos0[i0+j-1][3][i];
   }
   for(j=2;j<=n0;j++){
     for(jj=1;jj<=iside[i1+j-1];jj++)
       pos1[i1+j-1][4+jj][i] = pos0[i0+j-1][4+jj][i];
   }
  }
#if 0
float x[3],dist;
for(j=2;j<=n0;j++){
if(iside[i1+j-1]==2){
for(i=0;i<=2;i++)
  x[i] = pos1[i1+j-1][6][i]-pos1[i1+j-1][5][i];
dist= sqrt(dot(x,x));
if(dist>1.6)
  fprintf(fpout,"ERROR:iside[i1+j-1]=%d j= %d  i1+j-1 = %d  dist = %6.3f\n",
         iside[i1+j-1],j, i1+j-1,dist);
}
} //j
#endif
}

void copyendfittogeo(struct geometry& geo,struct pepfit& fit)
/* Copies fit to geo - given the end values of geo
*/
{
   int i,j,jj,ii,n0,i0,count,rottype,atomname;

   i0 = geo.nend[0];
   n0=geo.nend[1]-geo.nend[0];
   if( (geo.nend[0]<0) || (geo.nend[1]>= NAFIT-1) ){
     printf("ERROR in copyendfittogeo: geo.nend[0] = %d  geo.nend[1] = %d  EXITING\n",geo.nend[0],geo.nend[1]);
     exit(0);
   }
   for(j=0;j<=n0;j++) // Default  - set cis = 0 (trans proline)
       geo.cis[i0+j] = 0;  
   for(j=0;j<=n0;j++){ // copy constaint type
     geo.rtype[i0+j]=fit.itype[j];
     geo.cis[i0+j] = fit.cis[j];
   }
   for(j=1;j<=n0-1;j++){ // save side atom data
     geo.iside[i0+j]=fit.nside[j];
     geo.irot[i0+j]=fit.irot[j];
   }
   for(i=0;i<=2;i++){ // x,y,z
      for(j=0;j<=n0;j++)
         geo.pos[i0+j][1][i]=fit.pos[j][1][i];
      for(j=1;j<=n0;j++)
         geo.pos[i0+j][4][i]=fit.pos[j][4][i];
      for(j=0;j<=n0-1;j++){
         geo.pos[i0+j][2][i]=fit.pos[j][2][i];
         geo.pos[i0+j][3][i]=fit.pos[j][3][i];
      }
      for(j=1;j<=n0-1;j++){ // copy side chain for each residue j
        if(geo.iside[i0+j]>=0){ // then side is just series or C atoms
#if 0
if(geo.iside[i0+j]>2){
  printf("geo.iside[i0+j] = %d\n",geo.iside[i0+j]);
   geo.iside[i0+j] = 2;
}
#endif
          for(jj=1;jj<=geo.iside[i0+j];jj++)
            geo.pos[i0+j][4+jj][i]=fit.pos[j][4+jj][i];
        } // >=0
        else{ // geo.iside = - rottype  (i.e. an amino acid residue
          rottype=  -geo.iside[i0+j];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                geo.pos[i0+j][count+5][i]=fit.pos[j][count+5][i];
              } // atopmname
              else
                geo.pos[i0+j][atomname][i]=fit.pos[j][atomname][i];                
            }// jj
          } //ii
          geo.resside[i0+j] = 5+count; // number of side chain atoms if amino acid
        }// else
      } // j         
   }//i
}


void copyreggeotofitnterm(struct geometry& geo,struct pepfit& fit,int iend)
/*
Similar to copyreggeotofit - but geo is extended at nterm end of fit
   iend = position in original fit corresponding to cterm end of geo
Proceudre:
   1) It is assumed that fit has already been allocated big enough
   2) New fit begins with n0 residues from geo - followed by
       original residues from fit beginning at iend.
   3) First shift the residues in fit by correct amount
   4) Then copy geo to beginning of fit 
*/
{
   int i0,ishift,i,j,jj,ii,n0,count,rottype,atomname;


   i0 = iend; //NOTE CTERM ENDOF geo is fixed so do not copy end
   n0= fit.nres-1;
   ishift = geo.nend[1]-geo.nend[0]- iend; // note when called from extendfit() this should = 1
   if(ishift <0){
      printf("ERROR: ishift <0 in copyreggeotofitnterm\n");
      exit(0);
   }
   if( n0+ishift+1>fit.nalloc){ // NOTE THIS ASSUMES ONLY 
      printf("ERROR: n0+ishift+1 = %d>fit.nalloc = %d in copyreggeotofitcterm)\n",n0+ishift+1,fit.nalloc);
      goto quitcopy;
   }
// Here copy from i0 to n0 of fit - shifting values by ishift  
   for(j=n0;j>=i0;j--){ // copy constaint type
     fit.itype[j+ishift]=fit.itype[j];
     fit.cis[j+ishift] = fit.cis[j];
   }
   for(i=0;i<=2;i++){ // x,y,z
      for(j=n0;j>=i0;j--) // copy constaint type
        fit.pos[j+ishift][1][i] =fit.pos[j][1][i];
      for(j=n0;j>=i0;j--) // copy constaint type
        fit.pos[j+ishift][4][i] = fit.pos[j][4][i];
      for(j=n0-1;j>=i0;j--){ // copy constaint type
        fit.pos[j+ishift][2][i] =fit.pos[j][2][i] ;
        fit.pos[j+ishift][3][i] = fit.pos[j][3][i];
      }
      for(j=n0-1;j>=i0;j--){ // copy constaint type
        if(fit.nside[j]>=0){ // then side is just series or C atoms
          for(jj=1;jj<=fit.nside[j];jj++)
            fit.pos[j+ishift][4+jj][i] = fit.pos[j][4+jj][i];
        } // >=0
        else{ // fit.nside[j+ishift] = - rottype  (i.e. an amino acid residue
          rottype=  -fit.nside[j];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                fit.pos[j+ishift][count+5][i]=fit.pos[j][count+5][i];
              } // atopmname
              else if(atomname==5)
                fit.pos[j+ishift][atomname][i]=fit.pos[j][atomname][i];
#if 0 // redundant and causes trouble
              else
                fit.pos[j+ishift][atomname][i]=fit.pos[j][atomname][i];
#endif
            }// jj
          } //ii
        }// else
      } // j         
   }//i
   for(j=n0-1;j>=i0;j--){ // shift side atom data
     fit.nside[j+ishift]=fit.nside[j];
     fit.irot[j+ishift]=fit.irot[j];
   }
// NOW ADD geo to front
   i0=geo.nend[0];
   n0=geo.nend[1]-geo.nend[0]-1; // -1 because cterm end of geo is fixed.
   for(j=0;j<=n0;j++){ // copy constaint type
     fit.itype[j]=geo.rtype[i0+j];
     fit.cis[j]= geo.cis[i0+j];
   }
   if(fit.val1<0) //CHANGE VALUE OF val1 indicates amino acid side chains
      fit.val1 = fit.val1+ishift;
   for(j=1;j<=n0;j++){ // save side atom data
     fit.nside[j]=geo.iside[i0+j];
     fit.irot[j]=geo.irot[i0+j];
   }
   for(i=0;i<=2;i++){ // x,y,z
      for(j=0;j<=n0;j++)
        fit.pos[j][1][i] = geo.pos[i0+j][1][i];
      for(j=1;j<=n0;j++)
        fit.pos[j][4][i] = geo.pos[i0+j][4][i];
      for(j=0;j<=n0;j++){
        fit.pos[j][2][i] = geo.pos[i0+j][2][i];
        fit.pos[j][3][i] = geo.pos[i0+j][3][i];
      }
      for(j=1;j<=n0;j++){ // copy side chain for each residue j
        if(geo.iside[i0+j]>=0){ // then side is just series or C atoms
          for(jj=1;jj<=geo.iside[i0+j];jj++)
            fit.pos[j][4+jj][i]=geo.pos[i0+j][4+jj][i];
        } // >=0
        else{ // geo.iside = - rottype  (i.e. an amino acid residue
          rottype=  -geo.iside[i0+j];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                fit.pos[j][count+5][i]=geo.pos[i0+j][count+5][i];
              } // atopmname
              else if(atomname==5)
                fit.pos[j][atomname][i]=geo.pos[i0+j][atomname][i];                
           }// jj
          } //ii
        }// else
      } // j         
   }//i
   fit.nres = fit.nres+ishift;
   
   quitcopy:;
}



void copyreggeotofit(struct geometry& geo,struct pepfit& fit,int istart)
/*
This copies geo to cterm end of fit.
Similar to copygeotofit, but start  position of fit is
     specified = istart,
   (end position does not need to be stated)
 Assumes that fit already allocated 
   Does not redefine main or val
 assumes that fit.nalloc = <=0 when initially defined
   Note: for phi/psi constraint:
     fit.itype[n0= fit.nres-1] = geo.rtype[geo.nend[1]]
  Since geo.rtype[geo.nend[1]] does not have any meaning
    Constraint for last residue = geo.rtype[geo.nend[1]-1]
      corresponds to fit.itype[fit.nres-2]
*/
{
   int i,j,jj,ii,n0,i0,count,rottype,atomname;

   n0=geo.nend[1]-geo.nend[0];
   if( n0+1+istart>fit.nalloc){
      printf("ERROR: n0+1 = %d>fit.nalloc = %d in copyreggeotofit)\n",n0+1,fit.nalloc);
      goto quitcopy;
   }
   i0 = geo.nend[0];
   for(j=0;j<=n0;j++){ // copy constaint type
     fit.itype[j+istart]=geo.rtype[i0+j];
     fit.cis[j+istart]= geo.cis[i0+j];
   }
   for(j=1;j<=n0-1;j++){ // save side atom data
     fit.nside[j+istart]=geo.iside[i0+j];
     fit.irot[j+istart]=geo.irot[i0+j];
   }
   for(i=0;i<=2;i++){ // x,y,z
      for(j=0;j<=n0;j++)
        fit.pos[j+istart][1][i] = geo.pos[i0+j][1][i];
      for(j=1;j<=n0;j++)
        fit.pos[j+istart][4][i] = geo.pos[i0+j][4][i];
      for(j=0;j<=n0-1;j++){
        fit.pos[j+istart][2][i] = geo.pos[i0+j][2][i];
        fit.pos[j+istart][3][i] = geo.pos[i0+j][3][i];
      }
      for(j=1;j<=n0-1;j++){ // copy side chain for each residue j
        if(geo.iside[i0+j]>=0){ // then side is just series or C atoms
          for(jj=1;jj<=geo.iside[i0+j];jj++)
            fit.pos[j+istart][4+jj][i]=geo.pos[i0+j][4+jj][i];
        } // >=0
        else{ // geo.iside = - rottype  (i.e. an amino acid residue
          rottype=  -geo.iside[i0+j];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                fit.pos[j+istart][count+5][i]=geo.pos[i0+j][count+5][i];
//printf("fit.pos[%d][%d][%d] = %5.3f\n",
//       j+istart,count+5,i,fit.pos[j+istart][count+5][i]);
              } // atopmname
              else
                fit.pos[j+istart][atomname][i]=geo.pos[i0+j][atomname][i];                
            }// jj
          } //ii
        }// else
      } // j         
   }//i
   quitcopy:;
}

void copyregfittogeo(struct geometry& geo,struct pepfit& fit,
      int istart,int iend)
/*Similar to copyendfittogeo, but start and end position of fit is
     specified = istart, iend
*/
{
   int i,j,jj,ii,n0,i0,count,rottype,atomname;

   geo.val1 = fit.val1;
   geo.val2 = fit.val2;
   if(istart<0){
       printf("ERROR: istart < 0\n");
      istart = 0;
   }
   if(iend>fit.nres){
      printf("ERROR: iend > fit.nres\n");
      iend = fit.nres;
   }
  geo.nend[0] = (NAFIT - (iend - istart) )/2;
   geo.nend[1] = geo.nend[0] + (iend - istart);
  if( (geo.nend[0]<0) || (geo.nend[1]>= NAFIT-1) ){
     printf("ERROR in copyregfittogeo: geo.nend[0] = %d  geo.nend[1] = %d  EXITING\n",geo.nend[0],geo.nend[1]);
     exit(0);
  }
   i0 = geo.nend[0];
   n0=geo.nend[1]-geo.nend[0];
   for(j=0;j<=n0;j++){ // copy constaint type
     geo.rtype[i0+j]=fit.itype[j+istart];
     geo.cis[i0+j] = fit.cis[j+istart];
   }
   for(j=1;j<=n0-1;j++){ // save side atom data
     geo.iside[i0+j]=fit.nside[j+istart];
     geo.irot[i0+j]=fit.irot[j+istart];// rotomer number
   }
   for(i=0;i<=2;i++){ // x,y,z
      for(j=0;j<=n0;j++)
         geo.pos[i0+j][1][i]=fit.pos[j+istart][1][i];
      for(j=1;j<=n0;j++)
         geo.pos[i0+j][4][i]=fit.pos[j+istart][4][i];
      for(j=0;j<=n0-1;j++){
         geo.pos[i0+j][2][i]=fit.pos[j+istart][2][i];
         geo.pos[i0+j][3][i]=fit.pos[j+istart][3][i];
      }
      for(j=1;j<=n0-1;j++){ // copy side chain for each residue j
        if(geo.iside[i0+j]>=0){ // then side is just series or C atoms
          for(jj=1;jj<=geo.iside[i0+j];jj++)
            geo.pos[i0+j][4+jj][i]=fit.pos[j+istart][4+jj][i];
        } // >=0
        else{ // geo.iside = - rottype  (i.e. an amino acid residue
          rottype=  -geo.iside[i0+j];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                geo.pos[i0+j][count+5][i]=fit.pos[j+istart][count+5][i];
              } // atopmname
              else
                geo.pos[i0+j][atomname][i]=fit.pos[j+istart][atomname][i];                
            }// jj
          } //ii
        }// else
      } // j         
   }//i
}


void copyendfittogeostart(struct geometry& geo,
     struct pepfit& fit,int istart)
/* Similar to copyendfittogeo,
   But istart specifies the that start number of the 
     fit that is copied
  If istart = 0, then identical to copyendfittogeo
*/
{
   int i,j,jj,ii,n0,i0,count,rottype,atomname;

   i0 = geo.nend[0];
   n0=geo.nend[1]-geo.nend[0];
   for(j=0;j<=n0;j++){ // copy constaint type
     geo.rtype[i0+j]=fit.itype[j+istart];
     geo.cis[i0+j] = fit.cis[j+istart];
   }
   for(j=1;j<=n0-1;j++){ // save side atom data
     geo.iside[i0+j]=fit.nside[j+istart];
     geo.irot[i0+j]=fit.irot[j+istart];
   }
   for(i=0;i<=2;i++){ // x,y,z
      for(j=0;j<=n0;j++)
         geo.pos[i0+j][1][i]=fit.pos[j+istart][1][i];
      for(j=1;j<=n0;j++)
         geo.pos[i0+j][4][i]=fit.pos[j+istart][4][i];
      for(j=0;j<=n0-1;j++){
         geo.pos[i0+j][2][i]=fit.pos[j+istart][2][i];
         geo.pos[i0+j][3][i]=fit.pos[j+istart][3][i];
      }
      for(j=1;j<=n0-1;j++){ // copy side chain for each residue j
        if(geo.iside[i0+j]>=0){ // then side is just series or C atoms
          for(jj=1;jj<=geo.iside[i0+j];jj++)
            geo.pos[i0+j][4+jj][i]=fit.pos[j+istart][4+jj][i];
        } // >=0
        else{ // geo.iside = - rottype  (i.e. an amino acid residue
          rottype=  -geo.iside[i0+j];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                geo.pos[i0+j][count+5][i]=fit.pos[j+istart][count+5][i];
              } // atopmname
              else
                geo.pos[i0+j][atomname][i]=fit.pos[j+istart][atomname][i];                
            }// jj
          } //ii
          geo.resside[i0+j] = 5+count; // number of side chain atoms if amino acid
        }// else
      } // j         
   }//i
}

void addfittofit(struct pepfit fit1,struct pepfit fit2,
      struct pepfit& fittemp)
/* 
  Combines two fits - used in fusefit - into one fit = fit1
   Copies fit2 to end of fit1, - with the last residue of
       fit1 deleted
  Must copy fit1 to fittemp becaue allocation erases fit1
*/
{
   int i,j,jj,rottype,count,ii,n0,atomname;
   int iend,beg1;
   
   copyfittofit(fit1,fittemp,0,fit1.nres); // this copies val1 and val2 to fittemp
   iend = fit1.nres-1;
   beg1 = 1;
   n0 = fit2.nres-2;
   for(i=0;i<=2;i++){ // x,y,z
      for(j=0;j<=n0;j++)
        fittemp.pos[j+iend][1][i] =fit2.pos[j+beg1][1][i];
      for(j=1;j<=n0;j++)
        fittemp.pos[j+iend][4][i] = fit2.pos[j+beg1][4][i];
      for(j=0;j<=n0-1;j++){
        fittemp.pos[j+iend][2][i] =fit2.pos[j+beg1][2][i] ;
        fittemp.pos[j+iend][3][i] = fit2.pos[j+beg1][3][i];
      }
      for(j=0;j<=n0;j++){ // copy side chain for each residue j
        fittemp.itype[j+iend] =fit2.itype[j+beg1];
        fittemp.nside[j+iend] =fit2.nside[j+beg1];
      }
      for(j=0;j<=n0-1;j++){ // copy side chain for each residue j
        if(fit2.nside[j+beg1]>=0){ // then side is just series or C atoms
          for(jj=1;jj<=fit2.nside[j+beg1];jj++){
            fittemp.pos[j+iend][4+jj][i] = fit2.pos[j+beg1][4+jj][i];
          }
        } // >=0
        else{ // fit2.nside[j+beg1] = - rottype  (i.e. an amino acid residue
          rottype=  -fit2.nside[j+beg1];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                fittemp.pos[j+iend][count+5][i]=fit2.pos[j+beg1][count+5][i];
              } // atopmname
              else
                fittemp.pos[j+iend][atomname][i]=fit2.pos[j+beg1][atomname][i];
            }// jj
          } //ii
        }// else
      } // j         
   }//i
}   
   

void copy2fitstogeo(struct geometry& geo,struct pepfit& fitn,
             struct pepfit& fitc)
/* Copies nterm (fitn) and cterm (fitc) to geo
  Used when what to merge fits
Assumes cterm end of fitn and nterm end of fit c over lap
  (checks to make sure)
 and copies this overlappping residue same way that  fpos (fuseposiiton)
   is defined when do dynamics in center
NOTE: UNUSUAL DEFINITION:
  fitn - means fuse the nterm end of the cterm branch
  fitc = means fuse the cterm end of the nterm brach
*/
{
   int nend0;

   nend0=geo.nend[0] = (NAFIT - fitn.nres - fitc.nres)/2;
   if(geo.nend[0]<1){
      fprintf(fpout,"ERROR: NAFIT  is too small in copyfittogeo - increase NAFIT and recompile\n");
      exit(0);
   }
   geo.nend[1] = geo.nend[0]+fitc.nres-1; // end of nterm end
   copyendfittogeo(geo,fitc);
   geo.nafit=geo.nend[1]-geo.nend[0]+1;
#if 1
   geo.fnum = geo.nend[1]; // equivalend center position 
   copypostofpos(geo,geo.nend[1],0);// "0" refers to nterm branch
   geo.nend[0]=geo.nend[1]-1;
   geo.nend[1] = geo.nend[0]+fitn.nres-1;
   copyendfittogeo(geo,fitn);
   copypostofpos(geo,geo.nend[0]+1,1);// "0" refers to nterm branch
   geo.nend[0]=nend0; // set back to orig. value
   geo.nafit=geo.nend[1]-geo.nend[0]+1;
#endif
   geo.rtype[geo.fnum-1]=0;
//   tordata.fuseconst = 0.0;
     quitrout:;
}

#if 1
void copyreg2fitstogeo(struct geometry& geo,struct pepfit& fitn,
             struct pepfit& fitc,int *istart)
/*
NEW- PREVIOUS ERROR - IMPORTANT TO COPY EITHER THE ENTIRE CHAIN
   (IF IT FITS IN geo., or a region that is more than the number 
     moved  - otherwisse - end of region is not restricted by the
     rest of the chain)  (Max of geo = NAFIT = 60)  - Max on each side
     = Nafit/2
NEW Just Copy short region of fit to geo.
For nterm end
 Copies nterm (fitn) and cterm (fitc) to geo
  Used when what to merge fits
Assumes cterm end of fitn and nterm end of fit c over lap
  (checks to make sure)
 and copies this overlappping residue same way that  fpos (fuseposiiton)
   is defined when do dynamics in center
NOTE: UNUSUAL DEFINITION:
  fitn - means fuse the nterm end of the cterm branch
  fitc = means fuse the cterm end of the nterm brach
*/
{
   int nend0;
   int ifitn,ifitc,maxnend;
   int endmoveorig;

   endmoveorig = geo.endmove;
   maxnend = NAFIT/2 -2; // Maximum allowed residues at each end
   if(maxnend < geo.endmove+2) // do not what entire geo to move if reduce length
      geo.endmove = maxnend -2;
//printf("fitn.nres = %d fitc.nres = %d\n",fitn.nres,fitc.nres); 
   if(fitn.nres > maxnend){
       ifitn = maxnend;
   }
   else
       ifitn = fitn.nres;
//printf(" Setting ifitn = %d\n",ifitn);
   if(fitc.nres > maxnend){
       ifitc = maxnend;
   }
   else
       ifitc = fitc.nres;
//printf(" Setting ifitc = %d\n",ifitc);
   *istart = fitc.nres -ifitc; // the fit start value in copyendfittogeostart
   nend0 = (NAFIT -ifitc -ifitn)/2 ; 
   geo.nend[0] = nend0;
   geo.nend[1] = geo.nend[0]+ifitc-1; // end of nterm end
   copyendfittogeostart(geo,fitc,*istart);
   geo.nafit=geo.nend[1]-geo.nend[0]+1;
#if 1
   geo.fnum = geo.nend[1]; // equivalend center position 
   copypostofpos(geo,geo.nend[1],0);// "0" refers to nterm branch
   geo.nend[0]=geo.nend[1]-1;
   geo.nend[1] = geo.nend[0]+ifitn-1;
   copyendfittogeo(geo,fitn);// this is equivalent to istart = 0
   copypostofpos(geo,geo.nend[0]+1,1);// "0" refers to nterm branch
   geo.nend[0]=nend0; // set back to orig. value
   geo.nafit=geo.nend[1]-geo.nend[0]+1;
#endif
   geo.rtype[geo.fnum-1]=0;
//   tordata.fuseconst = 0.0;
     quitrout:;
  geo.endmove= endmoveorig;
}
#endif

void copyfittogeo(struct geometry& geo,struct pepfit& fit)
{
   if(fit.nres > NAFIT-4){
       geo.badfit = 0;
       goto quitrout;
   }
   else
      geo.badfit = 1;
   geo.val1 = fit.val1;
   geo.val2 = fit.val2;
   geo.nend[0] = (NAFIT - fit.nres)/2;
   geo.main[0] = fit.main[0];
   geo.main[1] = fit.main[1];
   geo.main[2] = fit.main[2];
   if(geo.nend[0]<1){
      fprintf(fpout,"ERROR: NAFIT  is too small in copyfittogeo - increase NAFIT and recompile\n");
      exit(0);
   }
   geo.nend[1] = geo.nend[0]+fit.nres-1;
   geo.nafit=geo.nend[1]-geo.nend[0]+1;
   copyendfittogeo(geo,fit);
   quitrout:;
}

void copygeotofit(struct geometry& geo,struct pepfit& fit,int nii[])
/* assumes that fit.nalloc = <=0 when initially defined
   Note: for phi/psi constraint:
     fit.itype[n0= fit.nres-1] = geo.rtype[geo.nend[1]]
  Since geo.rtype[geo.nend[1]] does not have any meaning
    Constraint for last residue = geo.rtype[geo.nend[1]-1]
      corresponds to fit.itype[fit.nres-2]
*/
{
   int i,j,jj,ii,n0,i0,count,rottype,atomname;

   fit.val1 = nii[0];
   fit.val2 = nii[1];
   fit.main[0] = geo.main[0];
   fit.main[1] = geo.main[1];
   fit.main[2] = geo.main[2];
   n0=geo.nend[1]-geo.nend[0];
   i0 = geo.nend[0];
   allocatefit(fit,n0+2);
   fit.irank[0]=0;  // no previous rankings
   fit.nres = n0+1;//  total number of res = n0+1  (0,1,....n0)  
   for(j=0;j<=n0;j++){ // copy constaint type
     fit.itype[j]=geo.rtype[i0+j];
     fit.cis[j] = geo.cis[i0+j];
   }
   for(j=1;j<=n0-1;j++){ // save side atom data
     fit.nside[j]=geo.iside[i0+j];
     fit.irot[j]=geo.irot[i0+j];
   }
   for(i=0;i<=2;i++){ // x,y,z
      for(j=0;j<=n0;j++)
        fit.pos[j][1][i] = geo.pos[i0+j][1][i];
      for(j=1;j<=n0;j++)
        fit.pos[j][4][i] = geo.pos[i0+j][4][i];
      for(j=0;j<=n0-1;j++){
        fit.pos[j][2][i] = geo.pos[i0+j][2][i];
        fit.pos[j][3][i] = geo.pos[i0+j][3][i];
      }
      for(j=1;j<=n0-1;j++){ // copy side chain for each residue j
        if(geo.iside[i0+j]>=0){ // then side is just series or C atoms
          for(jj=1;jj<=geo.iside[i0+j];jj++)
            fit.pos[j][4+jj][i]=geo.pos[i0+j][4+jj][i];
        } // >=0
        else{ // geo.iside = - rottype  (i.e. an amino acid residue
          rottype=  -geo.iside[i0+j];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                fit.pos[j][count+5][i]=geo.pos[i0+j][count+5][i];
              } // atopmname
              else
                fit.pos[j][atomname][i]=geo.pos[i0+j][atomname][i];                
            }// jj
          } //ii
        }// else
      } // j         
   }//i
   quitcopy:;
}

void copyfittofit(struct pepfit& fit1,struct pepfit& fit2,
  int beg1,int end1)
/* This sets fit2 = fit1 
NEW - 19jul00 FOUND BIG ERROR - INCORRECT FOR CASE WHERE RES IS A.A. 
   AND beg1 does not equal 0
New - also copies den and nbad data 
Copies i= beg1 to i = (end1-1) of fit1 to i= 0, to i= end1-beg1-1  of fit2
Allows one to remove residues from fit1
NOTE: assumes that if fit2.nres != -10, then it has already been allocated
*/
{
   int i,j,jj,ii,n0,count,rottype,atomname;

   fit2.val1 = fit1.val1;
   fit2.val2 = fit1.val2;
   n0 = end1-beg1-1;
   allocatefit(fit2,n0+2);
   fit2.nres = n0+1;
   fit2.fbad = fit1.fbad;
   fit2.qual = fit1.qual;
   fit2.fside = fit1.fside;
   fit2.main[0] = fit1.main[0];
   fit2.main[1] = fit1.main[1];
   fit2.main[2] = fit1.main[2];
   if(fit1.irank[0]>0){ // Copy number of preivous rankings
     fit2.irank[0]= fit1.irank[0];
     for(i=1;i<=fit2.irank[0];i++){ //Copy ranking
        fit2.irank[i]=fit1.irank[i];
        fit2.den[i] = fit1.den[i];
     }
   }
   else{ // fit1.irank[0]=0    reset fit2 = 0
      fit2.irank[0]=0;
   }
   for(j=0;j<=n0;j++){ // copy constaint type
     fit2.itype[j]=fit1.itype[j+beg1];
     fit2.cis[j] = fit1.cis[j+beg1];
   }
   for(j=1;j<=n0-1;j++){ // save side atom data
     fit2.nside[j]=fit1.nside[j+beg1];
     fit2.irot[j]=fit1.irot[j+beg1];
   }
   for(i=0;i<=2;i++){ // x,y,z
      for(j=0;j<=n0;j++)
        fit2.pos[j][1][i] =fit1.pos[j+beg1][1][i];
      for(j=1;j<=n0;j++)
        fit2.pos[j][4][i] = fit1.pos[j+beg1][4][i];
      for(j=0;j<=n0-1;j++){
        fit2.pos[j][2][i] =fit1.pos[j+beg1][2][i] ;
        fit2.pos[j][3][i] = fit1.pos[j+beg1][3][i];
      }
      for(j=1;j<=n0-1;j++){ // copy side chain for each residue j
        if(fit2.nside[j]>=0){ // then side is just series or C atoms
          for(jj=1;jj<=fit2.nside[j];jj++)
            fit2.pos[j][4+jj][i] = fit1.pos[j+beg1][4+jj][i];
        } // >=0
        else{ // fit2.nside[j] = - rottype  (i.e. an amino acid residue
          rottype=  -fit2.nside[j];
          count = 0;
          for(ii=1;ii<=side[rottype][0][0]+1;ii++){ // copy each side chain branch
            for(jj=0;jj<side[rottype][ii][0];jj++){
              atomname=side[rottype][ii][jj+1];
              if(atomname>5){ // not part of mainchain or Cb
                count = count+1;
                fit2.pos[j][count+5][i]=fit1.pos[j+beg1][count+5][i];
              } // atopmname
              else
                fit2.pos[j][atomname][i]=fit1.pos[j+beg1][atomname][i];
            }// jj
          } //ii
        }// else
      } // j         
   }//i
   quitcopy:;
}

float avepos(struct geometry& geo,struct griddata& den1,float pos[3])
//REturns aveden,  same as aveatom but use simple real space pos
{
   int i,j,k,kc,ir[3];
   float fd[3],atomden;

   atomden = 0;
   xtof(den1,pos,fd); /* convert from double word to float sccreen*/
   for(kc=0;kc<=2;kc++)
       ir[kc]=fd[kc]; /*round down to integer*/
   for(k=0;k<=2;k++){ // check if pos in density range
      if( (ir[k]<1)|| (ir[k]>den1.amax[k]-den1.amin[k]-1) ){
//if(verbose>=2)
//  fprintf(fpout," ERROR:  out of range in pos (ir[%d]=%d),\n",k,ir[k]);
         return -1000.0;
      }
   }
   for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++) {/*interpolate*/
       atomden=atomden+ (int)den1.den[ir[0]+geo.da[i]][ir[1]+geo.da[j]][ir[2]+geo.da[k]]*
                 fabs( (fd[0]-ir[0]+geo.al[i])*(fd[1]-ir[1]+geo.al[j])*(fd[2]-ir[2]+geo.al[k]) );
   }
   return atomden;
}


float aveatom(struct griddata& den1,struct geometry& geo,int itype,
     int inum,float pos[NAFIT][NAA][3])
// returns density for atom of type itype (Ca, N, etc) and number inum
{
   int i,j,k,kc,ir[3];
   float fd[3],atomden;

   atomden = 0;
   xtof(den1,pos[inum][itype],fd); /* convert from double word to float sccreen*/
   for(kc=0;kc<=2;kc++)
       ir[kc]=fd[kc]; /*round down to integer*/
   for(k=0;k<=2;k++){ // check if pos in density range
      if( (ir[k]<1)|| (ir[k]>den1.amax[k]-den1.amin[k]-1) ){
        if(verbose>=2)
            fprintf(fpout," ERROR: res %d atom type %d out of range in aveatom (ir[%d]=%d), setting geo.quit = 1\n",inum,itype,k,ir[k]);
         geo.quit = 1;
         return -1000.0;
      }
   }
   for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++) {/*interpolate*/
       atomden=atomden+ (int)den1.den[ir[0]+geo.da[i]][ir[1]+geo.da[j]][ir[2]+geo.da[k]]*
                 fabs( (fd[0]-ir[0]+geo.al[i])*(fd[1]-ir[1]+geo.al[j])*(fd[2]-ir[2]+geo.al[k]) );
   }
   return atomden;
}

void avedengeooneside(struct griddata& den1,struct geometry& geo,
      float pos[NAFIT][NAA][3],int iside,float *aveden,int *nbad)
/* 
For now - only written for amino acid residue
Similar to avedenoneside - except use geo coord for side, rather than
   tordata units
*/
{
   int jj,countside;
   float aden;

   countside = 0;
   *nbad = 0;
   *aveden = 0;
   if(geo.resside[iside]<5)
      goto quitrout;
   else{
     for(jj=5;jj<=geo.resside[iside];jj++){
       aden = aveatom(den1,geo,jj,iside,pos);
//printf("aden = %5.3f\n",aden);
       *aveden = *aveden + aden;
       countside = countside+1;
       if(aden< geo.minrigid)
          *nbad = *nbad+1;
     }
     *aveden = *aveden/countside;
   }
   quitrout:;
}   

void avedenfit0(struct griddata& den1,struct geometry& geo,
           struct pepfit fit,float *ave,float *frout)
/*
New - if pos out of range - just skips - not used in finding den
  return nout = number out of range
NOTE: ASSUMES SIDES ARE JUST SERIES OF C'S,  NOT AMINO ACID
Similar to aveden0 but uses fit instead of geo
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
Copies all sidechain atoms in fit Cb from side (if it exists)
*/
{
   int i,j,count,nout;
   float aden;
   *ave = 0;
   count = 0;
   nout = 0;
   for(j=0;j<fit.nres-1;j++){
     aden= avepos(geo,den1,fit.pos[j][1]);
     if(aden> -900.0){ // NOT out of range
        *ave = *ave + aden;
        count = count+1;
     }
     else
       nout = nout+1;
   }
   for(j=1;j<fit.nres-1;j++){
     aden = avepos(geo,den1,fit.pos[j][4]);
     if(aden> -900.0){ // NOT out of range
        *ave = *ave + aden;
        count = count+1;
     }
     else
       nout = nout+1;
   }
   for(j=0;j<fit.nres-2;j++){
     aden = avepos(geo,den1,fit.pos[j][2]);
     if(aden> -900.0){ // NOT out of range
        *ave = *ave + aden;
        count = count+1;
     }
     else
       nout = nout+1;
     aden = avepos(geo,den1,fit.pos[j][3]);
     if(aden> -900.0){ // NOT out of range
        *ave = *ave + aden;
        count = count+1;
     }
     else
       nout = nout+1;
   }
   for(j=1;j<fit.nres-2;j++){
    for(i=1;i<=fit.nside[j];i++){
      aden = avepos(geo,den1,fit.pos[j][4+i]);
      if(aden> -900.0){ // NOT out of range
         *ave = *ave + aden;
         count = count+1;
      }
     else
       nout = nout+1;
    }
   }
   if(count==0)
     *ave = 0;
   else
      *ave = *ave/count;
   if(count+nout ==0)
      *frout = 0.0;
   else
      *frout = (float)nout/(count+nout);
}

void aveden0(struct griddata& den1,struct geometry& geo,
       float pos[NAFIT][NAA][3],float *ave)
/*
Note: this has not been modified to check geo.cbden
Save as aveden but does not waste time fine min,max and nbad
 Find averge density of for pepdide of n0 residues
Also returns min and max density - not counting side chain atoms
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
*/
{
   int j,jj,countside;
   float aden;
   *ave = 0;
   countside = 0;
   for(j=geo.nend[0];j<=geo.nend[1];j++){
     aden= aveatom(den1,geo,1,j,pos);
     *ave = *ave + aden;
   }
   for(j=geo.nend[0]+1;j<=geo.nend[1];j++){
     aden = aveatom(den1,geo,4,j,pos);
     *ave = *ave + aden;
   }
   for(j=geo.nend[0];j<=geo.nend[1]-1;j++){
     aden = aveatom(den1,geo,2,j,pos);
     *ave = *ave + aden;
#if 1 //if =0 Do not use O in density minimization routines
     aden = aveatom(den1,geo,3,j,pos);
     *ave = *ave + aden;
#endif
   }
   for(j=geo.nend[0]+1;j<=geo.nend[1]-1;j++){
    if(geo.iside[j]>=0){
      for(jj=1;jj<=geo.iside[j];jj++){
        *ave = *ave + aveatom(den1,geo,4+jj,j,pos);
        countside = countside+1;
      }
    }
   }
   *ave = *ave/( 4*(geo.nend[1]-geo.nend[0]) +1 +countside);
}

void aveden(struct griddata& den1,struct geometry& geo,
       float pos[NAFIT][NAA][3],float *ave,float *avecb2,float *aveco,
       int *nbad,int resbad[])
/*
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
New return geo.aveatom[1..6] = ave for atoms 1 to 6
New in aveage for Cb2, use correct count
New: allow nside = 0 ????
New: geo.res0 is set if den<minrigid
New:  resbad is set if den < reslev
New - find avecb2 for each residue (not jsut if good cbden) 
   return avecb in aveco and avecb2 in avecb2
Try return avecb (as avecb2) instead of avecb2.
Try return aven (as aveco)
  For avecb - count all Cb atoms- This should show up problems when a
    sheet tends lie along a side chain such as aspartic.
  There should not be many glycines in sheet or helix, so this should
     not be a problem.

  1) Change aveden so that it also return: resbad[i] which is equal to 
      the number of bad atoms in residue i. 
  3) Define a residue (and e.g.end) as follows: (residues run from geo.nend[0] to geo.nend[1]-1
      (do not need to include Cb since it is not counted in nbad)
     In general: reside[i] = Ca-C-O [i] + N [i+1], except at  c term end, where add another Ca
     Example:  total of 4 Ca's - two ends, one middle (geo.nend[0] =1, 2, geo.nend[1]-1] = 3)
      N term: residue[geo.nend[0]] =  Ca -C -O (geo.nend[0]) + N(geo.nend[0]+1)
      Midddle: residue[geo.nend[0]+1] = Ca-C-O(geo.nend[0]+1] + N(geo.nend[0]+2)
      C term: residue[geo.nend[1]-1 =  Ca- C-O (geo.nend[1]-1) +  N-Ca(geo.nend[1])
    (NOTE: Now count end Ca's,even though they are not counted in nbad)
New dec15: no longer find min max,
  Instead return aveco in the min position and remove max
New: dec11, 98  - do not count nbad for Cb - may be glycine
Note: this has not been modified to check geo.cbden
New version:
 1) "ave" density does not include Cb2 atoms (Only Cb atoms included)
 2) "avecb2" is density is average densith of Cb2 atoms - if there are any
 3) nbad does not include Cb2
 Find averge density of for pepdide of n0 residues
Also returns min and max density - not counting side chain atoms
Note: (NEW) nbad counts only internal main chain atoms
*/
{
   int j,jj,count,countcb2,countatom[10];
   float aden,reslev;

   reslev = geo.poorrigid;
   for(j=1;j<=6;j++){
      geo.aveatom[j] = 0;
      countatom[j] = 0;
   }
   *ave = 0.0;
   *avecb2 = *aveco= 0.0;
   geo.avecb = 0.0; // global variable
   *nbad = 0;
   geo.npoor = 0;
   geo.obadn = 0;
   count =countcb2= 0;
//   reslev = geo.minrigid;
   reslev = geo.poorrigid;
   for(j=geo.nend[0];j<=geo.nend[1];j++){
      resbad[j] = 0;
      geo.res0[j]=0;
   }
   for(j=geo.nend[0];j<=geo.nend[1];j++){  // Ca
     aden= aveatom(den1,geo,1,j,pos);
     *ave = *ave + aden;
     count = count+1;
     countatom[1]= countatom[1]+1;
     geo.aveatom[1] = geo.aveatom[1]+ aden;
     if( (aden< geo.poorrigid)&&(j<geo.nend[1])&&(j>geo.nend[0]) ) // do not count nbad for end Ca's
         geo.npoor = geo.npoor+1;
     if(aden<reslev){
        if(j==geo.nend[1])
           resbad[j-1] = resbad[j-1]+1;
        else
           resbad[j]=resbad[j]+1;
     }
     if(aden< geo.minrigid){ // do not count nbad for end Ca's
        if(j==geo.nend[1])
           geo.res0[j-1] = geo.res0[j-1]+1;
        else
           geo.res0[j]=geo.res0[j]+1;
        if( (j>geo.nend[0])&& (j<geo.nend[1]) ){
           *nbad = *nbad +1;
if(verbose>=2)
  printf(" Ca bad in res %d\n",j-geo.nend[0]+2);
        }
     }
   } //Ca
   for(j=geo.nend[0]+1;j<=geo.nend[1];j++){ // N
     aden = aveatom(den1,geo,4,j,pos);
     *ave = *ave + aden;
     count = count+1;
     countatom[4]= countatom[4]+1;
     geo.aveatom[4] = geo.aveatom[4]+ aden;
     if( (aden< geo.poorrigid)&&(j<geo.nend[1])&&(j>geo.nend[0]) ) // do not count nbad for end Ca's
         geo.npoor = geo.npoor+1;
     if(aden<reslev)
        resbad[j-1]=resbad[j-1]+1;
     if(aden< geo.minrigid){ // NOTE: N[i] is part of i-1 residue
        geo.res0[j-1] = geo.res0[j-1]+1;
        *nbad = *nbad+1;
if(verbose>=2)
   printf(" N bad in res %d  aden = %5.3f  minrigid = %5.3f  denscale = %5.3f\n",j-geo.nend[0]+2,aden,geo.minrigid,maidfile.denscale);
     }
   }
   for(j=geo.nend[0];j<=geo.nend[1]-1;j++){ 
     aden = aveatom(den1,geo,2,j,pos);// C
     *ave = *ave + aden;
     countatom[2]= countatom[2]+1;
     geo.aveatom[2] = geo.aveatom[2]+ aden;
     if( (aden< geo.poorrigid)&&(j<geo.nend[1])&&(j>geo.nend[0]) ) // do not count nbad for end Ca's
         geo.npoor = geo.npoor+1;
     if(aden<reslev)
        resbad[j]=resbad[j]+1;
     if(aden< geo.minrigid){
        geo.res0[j]=geo.res0[j]+1;
        *nbad = *nbad+1;
if(verbose>=2)
   printf(" C bad in res %d\n",j-geo.nend[0]+2);
     }
     aden = aveatom(den1,geo,3,j,pos);// O
     *ave = *ave + aden;
     count = count+2;
     *aveco = *aveco+ aden;
     countatom[3]= countatom[3]+1;
     geo.aveatom[3] = geo.aveatom[3]+ aden;
     if( (aden< geo.poorrigid)&&(j<geo.nend[1])&&(j>geo.nend[0]) ) // do not count nbad for end Ca's
         geo.npoor = geo.npoor+1;
#if 0
     if(aden<reslev)
        resbad[j]=resbad[j]+1;
#endif
     if(aden< geo.minrigid){
        geo.res0[j]=geo.res0[j]+1;
        *nbad = *nbad+1;
        geo.obadn = geo.obadn+1;
//printf(" O bad in res %d\n",j-geo.nend[0]+2);
     }
   }// j
   for(j=geo.nend[0]+1;j<=geo.nend[1]-1;j++){
     if(geo.iside[j]>=0){
       jj = 1; // The Cb atoms
       aden = aveatom(den1,geo,4+jj,j,pos);
       *ave = *ave + aden;
       countatom[4+jj]= countatom[4+jj]+1;
       geo.aveatom[4+jj] = geo.aveatom[4+jj]+ aden;
       count = count+1;
#if 1 // define  global variable avecb as Cb den
       geo.avecb = geo.avecb+ aden;
#endif
#if 0
       if(aden< geo.minrigid){
        *nbad = *nbad+1;
       }
#endif
     }
   }// j
#if 1 // define avecb2 as Cb2 den
    jj = 2; // Cb2
    for(j=geo.nend[0]+1;j<=geo.nend[1]-1;j++){
//printf(" geo.iside[%d] = %d\n",j, geo.iside[j]);
     if(geo.iside[j]>=0){
      if(geo.iside[j]>1){
         aden = aveatom(den1,geo,4+jj,j,pos);
         countatom[4+jj]= countatom[4+jj]+1;
         geo.aveatom[4+jj] = geo.aveatom[4+jj]+ aden;
         *avecb2 = *avecb2 + aden;
         countcb2=countcb2+1;
      }
      else { // findbest cb2
         bestcb1(den1,geo,geo.pos,j,&aden);
         *avecb2 = *avecb2 + aden;
         countatom[4+jj]= countatom[4+jj]+1;
         geo.aveatom[4+jj] = geo.aveatom[4+jj]+ aden;
         countcb2=countcb2+1;
//printf(" Cb2 den after bestcb1 = %f\n",aden); 
      }
     }        
    } // j
    geo.avecb = geo.avecb/(geo.nend[1]-geo.nend[0] -1);
    *avecb2 = *avecb2/countcb2; // NOTE: this assumes that for those atoms with no Cb2, Cb2 den = 0
#endif
    *ave = *ave/count;
    *aveco = *aveco/countatom[3];
    for(jj=1;jj<=6;jj++)
       geo.aveatom[jj] = geo.aveatom[jj]/countatom[jj];
}


void avemidden(struct griddata& den1,struct geometry& geo,
       float pos[NAFIT][NAA][3],float *ave,float *avemid)
/*
Finds aveden for mid point between mainchain atoms.
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
*/
{
   int k,j,count;
   float aden,midpos[3];

   *ave = *avemid = 0.0;
   count = 0;
   for(j=geo.nend[0];j<geo.nend[1];j++){  // Ca
     for(k=0;k<=2;k++) // Ca-C midpoint
        midpos[k] = (pos[j][1][k]+pos[j][2][k])/2.0;
     aden= avepos(geo,den1,midpos);
     *avemid = *avemid + aden;
     aden= avepos(geo,den1,pos[j][1]);
     *ave = *ave + aden;
     count = count+1;
   } //Ca
   for(j=geo.nend[0]+1;j<=geo.nend[1];j++){ // N
     for(k=0;k<=2;k++) // N-Ca midpoint
        midpos[k] = (pos[j][4][k]+pos[j][1][k])/2.0;
     aden= avepos(geo,den1,midpos);
     *avemid = *avemid + aden;
     aden= avepos(geo,den1,pos[j][4]);
     *ave = *ave + aden;
     count = count+1;
   }
   for(j=geo.nend[0];j<=geo.nend[1]-1;j++){ 
     for(k=0;k<=2;k++) // C-N midpoint
        midpos[k] = (pos[j][2][k]+pos[j+1][4][k])/2.0;
     aden= avepos(geo,den1,midpos);
     *avemid = *avemid + aden;
     aden= avepos(geo,den1,pos[j][2]);
     *ave = *ave + aden;
     count = count+1;
   }// j
   for(j=geo.nend[0]+1;j<=geo.nend[1]-1;j++){
     for(k=0;k<=2;k++) // C-O midpoint
        midpos[k] = (pos[j][2][k]+pos[j][3][k])/2.0;
     aden= avepos(geo,den1,midpos);
     *avemid = *avemid + aden;
     aden= avepos(geo,den1,pos[j][3]);
     *ave = *ave + aden;
     count = count+1;
   }// j
   *ave = *ave/count;
   *avemid = *avemid/count;
}

void avedenregcb(struct griddata& den1,struct geometry& geo,
       float pos[NAFIT][NAA][3],float *ave,float *avecb2,
       int *nbad,int rbeg,int rend)
/*
Same as avedenreg but includes Cb if geo.iside[j]!= glycine
*/
{
   int j,count,countcb2;
   float aden;
   *ave = 0.0;
   *avecb2 = 0.0;
   *nbad = 0;
   geo.npoor = 0;
   count = 0;
   countcb2 = 0;
   if(rbeg < geo.nend[0])
     rbeg = geo.nend[0];
   if(rend > geo.nend[1])
     rend = geo.nend[1];
   for(j=rbeg;j<=rend;j++){  // Ca
     count = count +1;
     aden= aveatom(den1,geo,1,j,pos);
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
            *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j,1);
        }
   }
   for(j=rbeg+1;j<=rend;j++){ // N
     count = count +1;
     aden = aveatom(den1,geo,4,j,pos);
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j,4);
     }
   }
   for(j=rbeg;j<=rend-1;j++){ 
     count = count +1;
     aden = aveatom(den1,geo,2,j,pos);// C
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j,2);
     }
     count = count +1;
     aden = aveatom(den1,geo,3,j,pos);// O
     *ave = *ave + aden;
     *avecb2 = *avecb2 + aden;  // avecb2 = aveden for O
     countcb2 = countcb2+1;
#if 1 //New - 2jun99 - include O   -- New 9apr99 - do not include O in nbad
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j,3);
     }
#endif
   }// j
#if 0 //NEW 25SEP00 - DO NOT USE CB HERE - is used in detaildenoneside() Use cb if not glycine
   if(rbeg == geo.nend[0])
     cbbeg = rbeg+1;
   else
     cbbeg = rbeg;
   if(rend == geo.nend[1])
     cbend = rend-1;
   else
     cbend = rend;
   for(j=cbbeg;j<=cbend;j++){
    if( (geo.iside[j]<0)&&(geo.iside[j]!= -GLY) ){
        count = count +1;
        aden = aveatom(den1,geo,5,j,pos);
        *ave = *ave + aden;
         if(aden< geo.minrigid){
             *nbad = *nbad+1;
 //fprintf(fpout," nbad for res = %d  atom = %d\n",j,5);
        }
    } // not glycine
   }// j
#endif
   *ave = *ave/count;
   *avecb2 = *avecb2/countcb2;
}


void avedenregcbside(struct griddata& den1,struct geometry& geo,
       float pos[NAFIT][NAA][3],float *ave,float *avecb2,
       float *nbad,int rbeg,int rend)
/*
ASSUME residue is amino acid
Same as avedenregcb but includes some side chain atoms
Also - fbad is ave nbad per residue.
*/
{
   int j,jj,count,countcb2,cbbeg,cbend,maxside,ndiv;
   float aden;

   *ave = 0.0;
   *avecb2 = 0.0;
   *nbad = 0;
   geo.npoor = 0;
   count = 0;
   countcb2 = 0;
   if(rbeg < geo.nend[0])
     rbeg = geo.nend[0];
   if(rend > geo.nend[1])
     rend = geo.nend[1];
   for(j=rbeg;j<=rend;j++){  // Ca
     count = count +1;
     aden= aveatom(den1,geo,1,j,pos);
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
            *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j,1);
        }
   }
   for(j=rbeg+1;j<=rend;j++){ // N
     count = count +1;
     aden = aveatom(den1,geo,4,j,pos);
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j,4);
     }
   }
   for(j=rbeg;j<=rend-1;j++){ 
     count = count +1;
     aden = aveatom(den1,geo,2,j,pos);// C
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j,2);
     }
     count = count +1;
     aden = aveatom(den1,geo,3,j,pos);// O
     *ave = *ave + aden;
     *avecb2 = *avecb2 + aden;  // avecb2 = aveden for O
     countcb2 = countcb2+1;
#if 1 //New - 2jun99 - include O   -- New 9apr99 - do not include O in nbad
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j,3);
     }
#endif
   }// j
   if(rbeg == geo.nend[0])
     cbbeg = rbeg+1;
   else
     cbbeg = rbeg;
   if(rend == geo.nend[1])
     cbend = rend-1;
   else
     cbend = rend;
   for(j=cbbeg;j<=cbend;j++){
      if(geo.iside[j] == -8)
         goto nextj;
      else if(geo.resside[j]<5)
         goto nextj;
      else{
         maxside = geo.resside[j]-5;
         if(maxside>geo.maxside-1)
             maxside = geo.maxside-1;
         for(jj=5;jj<=5+maxside;jj++){ // 5 corresponds to Cb
            count = count +1;
            aden = aveatom(den1,geo,jj,j,pos);
            *ave = *ave + aden;
            if(aden< geo.minrigid)
              *nbad = *nbad+1;
         }
      }
      nextj:;
   }// j
   *ave = *ave/count;
   *avecb2 = *avecb2/countcb2;
   ndiv = rend -rbeg -1;
   if(ndiv<1)
      ndiv = 1;
   *nbad = *nbad/ndiv;
}


void avedenreg(struct griddata& den1,struct geometry& geo,
       float pos[NAFIT][NAA][3],float *ave,float *avecb2,
       int *nbad,int rbeg,int rend)
/*
New 29apr99 - count npoor
New 9apr99 - do not include O in nbad
New  return avecb2 = aveco
NEW 19mar99  -DO NOT USE SIDE CHAINS AT ALL
For now - (19aug98) this is only used in extendfit routines.
Similar to aveden except calculates only for region rbeg to rend
Does not include Cb in nbad if geo.usecb =1
Returns ave = aveden per atoms
  and nbad = total # of bad atoms
*/
{
   int j,count,countcb2;
//   int jj,cbbeg,cbend;
   float aden;
   *ave = 0.0;
   *avecb2 = 0.0;
   *nbad = 0;
   geo.npoor = 0;
   count = 0;
   countcb2 = 0;
   if(rbeg < geo.nend[0])
     rbeg = geo.nend[0];
   if(rend > geo.nend[1])
     rend = geo.nend[1];
   for(j=rbeg;j<=rend;j++){  // Ca
     count = count +1;
     aden= aveatom(den1,geo,1,j,pos);
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
            *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j-geo.nend[0]+1,1);
        }
   }
   for(j=rbeg+1;j<=rend;j++){ // N
     count = count +1;
     aden = aveatom(den1,geo,4,j,pos);
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j-geo.nend[0]+1,4);
     }
   }
   for(j=rbeg;j<=rend-1;j++){ 
     count = count +1;
     aden = aveatom(den1,geo,2,j,pos);// C
     *ave = *ave + aden;
     if(aden< geo.poorrigid)
        geo.npoor = geo.npoor+1;
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j-geo.nend[0]+1,2);
     }
     count = count +1;
     aden = aveatom(den1,geo,3,j,pos);// O
     *ave = *ave + aden;
     *avecb2 = *avecb2 + aden;  // avecb2 = aveden for O
     countcb2 = countcb2+1;
#if 1 //New - 2jun99 - include O   -- New 9apr99 - do not include O in nbad
     if(aden< geo.minrigid){
        *nbad = *nbad+1;
//fprintf(fpout," nbad for res = %d  atom = %d\n",j-geo.nend[0]+1,3);
     }
#endif
   }// j
   *ave = *ave/count;
   *avecb2 = *avecb2/countcb2;
}


#if 1 // New version - uses geo.torend
void aventermden(int usecb,struct griddata& den1,struct geometry& geo,int ica,
       float pos[NAFIT][NAA][3],float *ave,int *nbad)
/*
New - feb26,99  do not include O in nbad
NEW in 23sep98 -(NOT USED ANYMORE) only include Cb den if geo.cbden = 1
if geo.usecb == 1, then use cb denisty and nbad(Never use Cb2) of = 2 just den
 Find averge density of for pepdide of n0 residues
Similar to aveden - but used for nterm residue witn ica =1
  Need only aveage positions of atoms that are altered by phi/psi
   rotation of cterm  
= Cb, Cc, N for residue 2 and
  Ca, C amd O for residue 1  (= first residue)
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
*/
{
   int j,jj;
   float aveat;
   int ibeg,iend,count;

   *ave = 0;
   *nbad = 0;
   count = 0;
   j = ica;//
   ibeg=ica;
   if(ibeg-1+geo.torend >=geo.nend[1]-1)
       iend = geo.nend[1]-1;
   else
       iend = ibeg-1+geo.torend;
  for(ica = ibeg;ica<=iend;ica++){
     aveat =  aveatom(den1,geo,1,j,pos); //Ca
     if( aveat < geo.minrigid)
        *nbad = *nbad+1;
     *ave = *ave + aveat;
     count = count+1;
     aveat =  aveatom(den1,geo,2,j,pos); //C
     if( aveat < geo.minrigid)
        *nbad = *nbad+1;
     *ave = *ave + aveat;
     count = count+1;
     aveat =  aveatom(den1,geo,3,j,pos); //O
#if 0 // New - feb26,99  do not include O in nbad
     if( aveat < geo.minrigid)
        *nbad = *nbad+1;
#endif
     *ave = *ave + aveat;
   j=ica+1;
     aveat = aveatom(den1,geo,4,j,pos); //N
     if( aveat < geo.minrigid)
        *nbad = *nbad+1;
     *ave = *ave + aveat;
     count = count+1;
     if(geo.iside[j]>=0){
      if( usecb>=1 ){
       jj =1; // Only Cb, (not Cb2)
       aveat =  aveatom(den1,geo,4+jj,j,pos);
       if(usecb ==1)
          if( aveat < geo.minrigid)
             *nbad = *nbad+1;
       *ave = *ave + aveat;
       count = count+1;
      }
     }
  }// ica
  *ave = *ave/count;
}
#endif


#if 1 // new version - uses geo.torend
void avectermden(int usecb,struct griddata& den1,struct geometry& geo,int ica,
       float pos[NAFIT][NAA][3],float *ave,int *nbad)
/*
New  Mar23 99, measure density of last geo.torend residues
  (Default: geo.torend = 1  - same as old case)
New - feb26,99  do not include O in nbad
if geo.usecb=1, then include Cb densithy
 Find averge density of for pepdide of n0 residues
Similar to aveden - but used for cterm residue witn ica =1
  Need only aveage positions of atoms that are altered by phi/psi
   rotation of cterm  
= Cb, Cc, C and 0 for residue 1 and
  Ca, N for residue 2  (= last residue)
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
*/
{
   int j,jj;
   float aveat;
   int ibeg,iend,count;

   *nbad = 0;
   *ave = 0;
   count = 0;
   iend = ica;
   if(iend+1-geo.torend <=geo.nend[0]+1)
       ibeg = geo.nend[0]+1;
   else
       ibeg = iend+1-geo.torend;
 for(ica = ibeg;ica<=iend;ica++){
   j = ica;// = 1
     aveat = aveatom(den1,geo,2,j,pos);  //C
     if( aveat < geo.minrigid)
        *nbad = *nbad+1;
     *ave = *ave + aveat;
     count = count+1;
     aveat = aveatom(den1,geo,3,j,pos); //O
#if 0 // New - feb26,99  do not include O in nbad
     if( aveat < geo.minrigid)
        *nbad = *nbad+1;
#endif
     *ave = *ave + aveat;
     count = count+1;
     if(geo.iside[j]>=0){
      if( usecb>=1 ){
        jj = 1; // Just the use first Cb
        aveat = aveatom(den1,geo,4+jj,j,pos);
        if(usecb ==1)
          if( aveat < geo.minrigid)
             *nbad = *nbad+1;
        *ave = *ave + aveat;
         count = count+1;
      }
     }
   j=ica+1;
     aveat = aveatom(den1,geo,4,j,pos);//N
     if( aveat < geo.minrigid)
        *nbad = *nbad+1;
     *ave = *ave + aveat;
     count = count+1;
     aveat = aveatom(den1,geo,1,j,pos);//Ca
     if( aveat < geo.minrigid)
        *nbad = *nbad+1;
     *ave = *ave + aveat;
     count = count+1;
  } // ica
  *ave = *ave/count;
}
#endif


void tranpep(int nside,float ipos[NAFIT][NAA][3],float fpos[NAFIT][NAA][3],int n0,
    float p[])
/* translates n0 (=geo.nafit-1) residue peptide (postions initially given by geo.pos)
     by vector p[]  (where p[1,2,3] are x,y,z of transoation vector
  returns new pos = pos
*/
{
   int i,j,jj;

 for(i=0;i<=2;i++){
   for(j=1;j<=n0+1;j++)
     fpos[j][1][i] = ipos[j][1][i]+p[i+1];
   for(j=2;j<=n0+1;j++)
     fpos[j][4][i] = ipos[j][4][i]+p[i+1];
   for(j=1;j<=n0;j++){
     fpos[j][2][i] = ipos[j][2][i]+p[i+1];
     fpos[j][3][i] = ipos[j][3][i]+p[i+1];
   }
   for(j=2;j<=n0;j++){
     for(jj=1;jj<=nside;jj++)
       fpos[j][4+jj][i] = ipos[j][4+jj][i]+p[i+1];
   }
  }
}

#if 1 // old version - do not translate along axis
void globmin(struct griddata& den1,struct geometry& geo,
    float pos[NAFIT][NAA][3],int n0,int ica,
    float nca[3],float perpv[3],int tstep,float thtot,float phitot,
    float trandel,float rotdel,float p[])
/*
New on Dec. 16,98  - change geo.pos to pos  (they are identical, but geo is changed in other routines
New version -also rotates by 2PI about Ca1 to Caend axis
  nca now = original ca1 to caend axis
 Find global minimum of an n0 residue peptide:
returns best translaton (p[1,2,3], best theta = p[4] and best phi = p[5]
 1) Set up x,y,z coord system (and corresponding theta, phi spherical co-ord
    with Ca[ica] at origin, nca along z and perpv on x.
 2) Vary 6 variables to find maximum density:
     a) Rotate
     a) Rotate postion of z axis about x axis total angle of thtot.
     b) Rotate about z axis total ang of phitot.
         For rotations used fixed origin = orig, and perpv[3], and nca[3]
     c) translate over region of +-trantot  - in steps of trandel -
         this corresponds to 3 variables (x,y,z) itself
     The step size of rotation angle is such that maximum movement of furthers
       atom  (ie. ca1) is trandel Angstroms
*/
{
    int i[3],k,mth,mphi,ith,iph,iaxis; 
    float th,phi,aphi,dist,delph,thdel,ave,tran[3],ptemp[8]; 
    float maxden; // save best orientation
    float tpos1[NAFIT][NAA][3],tpos2[NAFIT][NAA][3],tpos3[NAFIT][NAA][3]; // temp pos position
    float tpos4[NAFIT][NAA][3];
//    float avecb2,aveco;
//    int nbad,resbad[NAFIT];

//    dist =distv(geo.pos[1][1],geo.pos[n0+1][1]); // distance from Ca[geo.cafix] to Ca[1]
    dist =distv(pos[1][1],pos[n0+1][1]); // distance from Ca[geo.cafix] to Ca[1]
dist = dist/2.0;
    thdel = rotdel/dist; // step size of theta rotation
    mth =1+ thtot/thdel; // max # of theta steps  - round up
    thdel = thtot/mth; // reset th del so that equal steps from 0 to thttot
    maxden = -10000.0;
for(iaxis=0;iaxis<8;iaxis++){// rotate about origingalca1 caend axis
    aphi = iaxis*2.0*PI/8.0;
//    rotcapepnew(geo,pos,tpos4,n0,nca,geo.pos[ica][1],aphi); // rotate about nca = ca1 to caend by aphi with with ca[1] origin of rot vec             
    rotcapepnew(geo,pos,tpos4,n0,nca,pos[ica][1],aphi); // rotate about nca = ca1 to caend by aphi with with ca[1] origin of rot vec             
    for(ith=0;ith<=mth;ith++){  //Start at first step so delph always finite -  rotate by thdel step
       th = ith*thdel; // the theta angle
//       rotcapepnew(geo,tpos4,tpos1,n0,perpv,geo.pos[ica][1],th); // rotate about perpv by th with with ca[ica] origin of rot vec             
       rotcapepnew(geo,tpos4,tpos1,n0,perpv,pos[ica][1],th); // rotate about perpv by th with with ca[ica] origin of rot vec             
       if(ith==0){
          mphi = 0; //NEW 27aug01 - (used to be =0,divide by 0) do not take phi step if ith =0
          delph= 0.0;
       }
       else{
         delph = rotdel/(dist*sin(th));//the delta phi angle step
         mphi = phitot/delph +1; // round up
         delph = phitot/mphi; // make phitot = mphi*delph 
       }
       for(iph = 0;iph<=mphi;iph++){ // the phi step 
          phi = iph*delph;
          if(iph!=0)
//            rotcapepnew(geo,tpos1,tpos2,n0,nca,geo.pos[ica][1],phi); // rotate about original ca1 to caend by phi with with ca[ica] origin of rot vec
            rotcapepnew(geo,tpos1,tpos2,n0,nca,pos[ica][1],phi); // rotate about original ca1 to caend by phi with with ca[ica] origin of rot vec
          else
            copypos(geo.iside,n0,1,1,tpos1,tpos2);
          for(i[0] = -tstep;i[0]<=tstep;i[0]++){// i[x,y,z] is translation about origin
             tran[0] = i[0]*trandel;
             for(i[1] = -tstep;i[1]<=tstep;i[1]++){
                tran[1] = i[1]*trandel;
                for(i[2] = -tstep;i[2]<=tstep;i[2]++){
                   tran[2] = i[2]*trandel;
                   for(k=0;k<=2;k++)
                       ptemp[k+1] = tran[k];
                   tranpep(geo.iside[n0],tpos2,tpos3,n0,ptemp); // translates by p[1,2,3] the initial geo.pos to tpos
#if 1
                   aveden0(den1,geo,tpos3,&ave); // Find average density (ave) for this orientation               
#endif
#if 0
                   aveden(den1,geo,tpos3,&ave,&avecb2,&aveco,&nbad,resbad); // Find average density (ave) for initial orientation 
                   ave = ave+ avecb2/4;  // place heavy weight on cb
#endif
                     if(geo.quit==1){
                         printf("ERROR - Out side of boundary in globmin() - quitting\n");
                         goto quitrout;
                     }
//printf("ave = %5.3f  avecb2 = %5.3f\n",ave,avecb2);
//fprintf(fpout,"aveden = %f  aphi=%5.3f th=%5.3f phi=%5.3f i=%d j=%d k=%d\n",
//   ave,aphi,th,phi,i[0],i[1],i[2]);
                   if(ave > maxden){ // then save this orientation
                     maxden = ave;
                     for(k=1;k<=3;k++)
                       p[k] = ptemp[k];
                     p[4] = th;
                     p[5] = phi;
                     p[6]= aphi; // the angle about Ca to Caend axis
                  }
                }// i[2] 
            } // i[1]
         } // i[0]
       } // phi
    } // theta
} // aphi
if(verbose>=2)
  fprintf(fpout,"After real globmin density = %f   tran = %5.3f %5.3f %5.3f  th = %5.3f (%5.3f deg)  phi = %5.3f (%5.3f deg) aphi = = %5.3f (%5.3f deg)\n",
     maxden,p[1],p[2],p[3],p[4],p[4]*180/PI,p[5],p[5]*180/PI,p[6],p[6]*180/PI);
quitrout:;
}
#endif


#if 1 // new version - do not translate along axis (if sheet)(nca= unit vector from Ca to Caend
void globmintran(struct griddata& den1,struct geometry& geo,
    float pos[NAFIT][NAA][3],int n0,int ica,
    float nca[3],float perpv[3],int tstep,float thtot,float phitot,
    float trandel,float rotdel,float p[])
/*
New on Dec. 16,98  - change geo.pos to pos  (they are identical, but geo is changed in other routines
New version -also rotates by 2PI about Ca1 to Caend axis
  nca now = original ca1 to caend axis
 Find global minimum of an n0 residue peptide:
returns best translaton (p[1,2,3], best theta = p[4] and best phi = p[5]
 1) Set up x,y,z coord system (and corresponding theta, phi spherical co-ord
    with Ca[ica] at origin, nca along z and perpv on x.
 2) Vary 6 variables to find maximum density:
     a) Rotate
     a) Rotate postion of z axis about x axis total angle of thtot.
     b) Rotate about z axis total ang of phitot.
         For rotations used fixed origin = orig, and perpv[3], and nca[3]
     c) translate over region of +-trantot  - in steps of trandel -
         this corresponds to 3 variables (x,y,z) itself
     The step size of rotation angle is such that maximum movement of furthers
       atom  (ie. ca1) is trandel Angstroms
*/
{
    int i[4],k,mth,mphi,ith,iph,iaxis; 
    float th,phi,aphi,dist,delph,thdel,ave,tran[3],ptemp[8]; 
    float maxden; // save best orientation
    float tpos1[NAFIT][NAA][3],tpos2[NAFIT][NAA][3],tpos3[NAFIT][NAA][3]; // temp pos position
    float tpos4[NAFIT][NAA][3];
//    int resbad[NAFIT];

//    dist =distv(geo.pos[1][1],geo.pos[n0+1][1]); // distance from Ca[geo.cafix] to Ca[1]
    dist =distv(pos[1][1],pos[n0+1][1]); // distance from Ca[geo.cafix] to Ca[1]
dist = dist/2.0;
    thdel = rotdel/dist; // step size of theta rotation
    mth =1+ thtot/thdel; // max # of theta steps  - round up
    thdel = thtot/mth; // reset th del so that equal steps from 0 to thttot
    maxden = -10000.0;
for(iaxis=0;iaxis<8;iaxis++){// rotate about origingalca1 caend axis
    aphi = iaxis*2.0*PI/8.0;
//    rotcapepnew(geo,pos,tpos4,n0,nca,geo.pos[ica][1],aphi); // rotate about nca = ca1 to caend by aphi with with ca[1] origin of rot vec             
    rotcapepnew(geo,pos,tpos4,n0,nca,pos[ica][1],aphi); // rotate about nca = ca1 to caend by aphi with with ca[1] origin of rot vec             
    for(ith=0;ith<=mth;ith++){  //Start at first step so delph always finite -  rotate by thdel step
       th = ith*thdel; // the theta angle
//       rotcapepnew(geo,tpos4,tpos1,n0,perpv,geo.pos[ica][1],th); // rotate about perpv by th with with ca[ica] origin of rot vec             
       rotcapepnew(geo,tpos4,tpos1,n0,perpv,pos[ica][1],th); // rotate about perpv by th with with ca[ica] origin of rot vec             
       if(ith==0){
          mphi = 0; //NEW 27aug01 - (used to be =0,divide by 0) do not take phi step if ith =0
          delph= 0.0;
       }
       else{
         delph = rotdel/(dist*sin(th));//the delta phi angle step
         mphi = phitot/delph +1; // round up
         delph = phitot/mphi; // make phitot = mphi*delph 
       }
       for(iph = 0;iph<=mphi;iph++){ // the phi step 
          phi = iph*delph;
          if(iph!=0)
//            rotcapepnew(geo,tpos1,tpos2,n0,nca,geo.pos[ica][1],phi); // rotate about original ca1 to caend by phi with with ca[ica] origin of rot vec
            rotcapepnew(geo,tpos1,tpos2,n0,nca,pos[ica][1],phi); // rotate about original ca1 to caend by phi with with ca[ica] origin of rot vec
          else
            copypos(geo.iside,n0,1,1,tpos1,tpos2);
          for(i[0] = -tstep;i[0]<=tstep;i[0]++){// i[x,y,z] is translation about origin
             tran[0] = i[0]*trandel;
             for(i[1] = -tstep;i[1]<=tstep;i[1]++){
                tran[1] = i[1]*trandel;
                for(i[2] = -tstep;i[2]<=tstep;i[2]++){
                   tran[2] = i[2]*trandel;
                   for(i[3]= -geo.axstep;i[3]<=geo.axstep;i[3]++){ // translate large step along axis                       
                     for(k=0;k<=2;k++)
                       ptemp[k+1] = tran[k]+nca[k]*i[3]*geo.axdel;
                     tranpep(geo.iside[n0],tpos2,tpos3,n0,ptemp); // translates by p[1,2,3] the initial geo.pos to tpos
#if 1
                     aveden0(den1,geo,tpos3,&ave); // Find average density (ave) for this orientation               
#endif
#if 0
                     aveden(den1,geo,tpos3,&ave,&avecb2,&aveco,&nbad,resbad); // Find average density (ave) for initial orientation 
                     ave = ave+ avecb2/4;  // place heavy weight on cb
#endif
                     if(geo.quit==1){
                         printf("ERROR - Out side of boundary in globmintran() - quitting\n");
                         goto quitrout;
                     }
//printf("ave = %5.3f  avecb2 = %5.3f\n",ave,avecb2);
//fprintf(fpout,"aveden = %f  aphi=%5.3f th=%5.3f phi=%5.3f i=%d j=%d k=%d\n",
//   ave,aphi,th,phi,i[0],i[1],i[2]);
                     if(ave > maxden){ // then save this orientation
                       maxden = ave;
                       for(k=1;k<=3;k++)
                         p[k] = ptemp[k];
                       p[4] = th;
                       p[5] = phi;
                       p[6]= aphi; // the angle about Ca to Caend axis
                    }// if ave
                  } //i[3]
                }// i[2] 
            } // i[1]
         } // i[0]
       } // phi
    } // theta
} // aphi
if(verbose>=2)
  fprintf(fpout,"After real globmin density = %f   tran = %5.3f %5.3f %5.3f  th = %5.3f (%5.3f deg)  phi = %5.3f (%5.3f deg) aphi = = %5.3f (%5.3f deg)\n",
     maxden,p[1],p[2],p[3],p[4],p[4]*180/PI,p[5],p[5]*180/PI,p[6],p[6]*180/PI);
quitrout:;
}
#endif


void rotcbnew(struct geometry& geo,float ipos[NAFIT][NAA][3],float pos1[1][NAA][3],
      int icb,float cbv[3],float ang,int iatom)
/* 
 Rotates sideatom =   iatom = # of sidechain atom  (1,2,.. )  actual atom number = 4+itatom
rotates by angle (ang) about vector cbv -  for residue = icb
    Rotates the vector from atom (iatom -1) to iatom, witgh iatom -1 at origin
      and return new positon  pos1[0][4+iatom]
*/
{
   float rom[3][3];

   rotaxis(geo.de,geo.ep,ang,cbv,rom); /* rom is rotation matrix for rotation
         of ang about unit vector rotv which is assumed to be at origin*/ 
//fprintf(fpout,"icb = %d  ipos[5] = %f   ipos[6] = %f\n",icb,ipos[icb][5][0],ipos[icb][6][0]);
   rotatesetnew(ipos[icb][4+iatom-1],ipos[icb][4+iatom],pos1[0][4+iatom],rom);
}

void rotcb(struct geometry& geo,float ipos[NAFIT][NAA][3],
      int icb,float cbv[3],float ang,int iatom)
// Same as rotcbnew except return new postiotinof old ipos.
{
   float rom[3][3];

   rotaxis(geo.de,geo.ep,ang,cbv,rom); /* rom is rotation matrix for rotation
         of ang about unit vector rotv which is assumed to be at origin*/ 
   rotateset(ipos[icb][4+iatom-1],ipos[icb][4+iatom],rom);
}
  

void movepep(struct geometry& geo,float ipos[NAFIT][NAA][3],float fpos[NAFIT][NAA][3],
        int n0,float xaxis[3],float zaxis[3],float orig[],float p[])
/* 
1)
Translate ipos by p[1,2,3] and rotate by p[4] p[5]  
*/
{
    rotcapepnew(geo,ipos,fpos,n0,zaxis,orig,p[6]); // rotate about nca = ca1 to caend by aphi with with ca[1] origin of rot vec             
    rotcapep(geo,fpos,n0,xaxis,orig,p[4]); //Returns new fpos  rotate n0 residue peptide  (coord. given by tpos)
           // with origin at Cafix by theta = p[4]              
    rotcapep(geo,fpos,n0,zaxis,orig,p[5]); // rotate about nca by phi with with ca[ica] fixed
    tranpep(geo.iside[n0],fpos,fpos,n0,p); // translates by p[1,2,3] the initial geo.pos to tpos
}

void phipsicterm(int istart,struct geometry& geo,float pos[NAFIT][NAA][3],
     float origphi[3],float origpsi[3],float phiv[3],float psiv[3],float phi,float psi)
/*
New Version -- only rotate Cb
 rotates  cterm residue by phi and psi about vector phiv and psiv through orig
pos is just a 2 residue array containing c term atoms 
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
p[1] = phi
p[2] = psi
*/
{
   int i,nca;
   float rom[3][3],dist;

   nca = istart;
   rotaxis(geo.de,geo.ep,phi,phiv,rom); // rom is rotation matrix for rotation        
   rotateset(origphi,pos[nca][2],rom);// rotate C
   rotateset(origphi,pos[nca][3],rom);// rotate 0
   rotateset(origphi,pos[nca][5],rom);//rotate Cb
   if(geo.iside[nca] ==2)
     rotateset(origphi,pos[nca][6],rom);// rotte Cc
   nca = nca+1;
   rotateset(origphi,pos[nca][4],rom);// rotate N
   rotateset(origphi,pos[nca][1],rom);// rotate Ca
   // rotate by psi
   nca= nca-1;
   for(i=0;i<=2;i++) // psiv = new Ca -C vector  (origpsi = Ca)
      psiv[i] = pos[nca][2][i]-origpsi[i];
   dist = sqrt( dot(psiv,psiv) );
//   dist = geo.dsqrt[1];
   for(i=0;i<=2;i++)
      psiv[i] = psiv[i]/dist;
   rotaxis(geo.de,geo.ep,psi,psiv,rom); // rom is rotation matrix for rotation        
   rotateset(origpsi,pos[nca][3],rom);// rotate 0
   nca = nca+1;
   rotateset(origpsi,pos[nca][4],rom);// rotate N
   rotateset(origpsi,pos[nca][1],rom);// rotate Ca
}

void phipsictermnew(int istart,struct geometry& geo,float pos[NAFIT][NAA][3],float fpos[NAFIT][NAA][3],
     float origphi[3],float origpsi[3],float phiv[3],float psiv[3],float phi,float psi)
/*
Note: phipsictermnew and phipsintermnew give same result as  
   phipsicterm and  phipsinterm -  although new funtions slilghtly faster
   not worth the extra complecations
 rotates  cterm residue by phi and psi about vector phiv and psiv through orig
pos is just a 2 residue array containing c term atoms 
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
p[1] = phi
p[2] = psi
*/
{
   int i,nca;
   float rom[3][3],dist;

   nca = istart;
   rotaxis(geo.de,geo.ep,phi,phiv,rom); // rom is rotation matrix for rotation        
   rotatesetnew(origphi,pos[nca][2],fpos[nca][2],rom);// rotate C
   rotatesetnew(origphi,pos[nca][3],fpos[nca][3],rom);// rotate 0
   rotatesetnew(origphi,pos[nca][5],fpos[nca][5],rom);//rotate Cb
   if(geo.iside[nca] ==2)
     rotatesetnew(origphi,pos[nca][6],fpos[nca][6],rom);// rotte Cc
   nca = nca+1;
   rotatesetnew(origphi,pos[nca][4],fpos[nca][4],rom);// rotate N
   rotatesetnew(origphi,pos[nca][1],fpos[nca][1],rom);// rotate Ca
   // rotate by psi
   nca= nca-1;
   for(i=0;i<=2;i++) // psiv = new Ca -C vector  (origpsi = Ca)
      psiv[i] = fpos[nca][2][i]-origpsi[i];
   dist = sqrt( dot(psiv,psiv) );
//   dist = geo.dsqrt[1];
   for(i=0;i<=2;i++)
      psiv[i] = psiv[i]/dist;
   rotaxis(geo.de,geo.ep,psi,psiv,rom); // rom is rotation matrix for rotation        
   rotateset(origpsi,fpos[nca][3],rom);// rotate 0
   nca = nca+1;
   rotateset(origpsi,fpos[nca][4],rom);// rotate N
   rotateset(origpsi,fpos[nca][1],rom);// rotate Ca
#if 0
float cn[3];
for(i=0;i<=2;i++)
  cn[i] = fpos[2][4][i]-fpos[1][2][i]; // vector from c to n
dist = sqrt( dot(cn,cn) );
fprintf(fpout, "In phipsicnew dist = %f\n",dist);
#endif
}

void phipsinterm(struct geometry& geo,float pos[NAFIT][NAA][3],
     float origphi[3],float origpsi[3],float phiv[3],float psiv[3],float phi,float psi)
/*
Note - does not rotate Cb2
 rotates  nterm residue by phi and psi about vector phiv and psiv through orig
pos is just a 2 residue array containing c term atoms 
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
Note: actually want to rotate by -phi and - psi since going
   in reverse direction
The psi axis or rotation does to not vary from call to call
  but need to calculate a phi axis each call
origpsi = origphi = Ca pos
*/
{
   int i,nca;
   float rom[3][3],dist;

   // rotate by psi
   nca = 1;
   rotaxis(geo.de,geo.ep,-psi,psiv,rom); // rom is rotation matrix for rotation        
   rotateset(origpsi,pos[nca][2],rom);// rotate C
   rotateset(origpsi,pos[nca][3],rom);// rotate 0
   rotateset(origpsi,pos[nca][1],rom);//rotate Ca
   nca = nca+1;
   rotateset(origpsi,pos[nca][4],rom);// rotate N
   rotateset(origpsi,pos[nca][5],rom);// rotate Cb
//   rotateset(origpsi,pos[nca][6],rom);// rotate Cc
   // rotate by phi
   for(i=0;i<=2;i++) // phiv = new N to Ca vector (may not be ideal lenght if adjust Ca bond length (nca = 2; origphi = Ca)
      phiv[i] = origpsi[i]-pos[nca][4][i];
   dist = sqrt( dot(psiv,psiv) );
//   dist = geo.dsqrt[4];
   for(i=0;i<=2;i++)
      phiv[i] = psiv[i]/dist;
   nca = 1;
   rotaxis(geo.de,geo.ep,-phi,phiv,rom); //phi rotation: rom is rotation matrix for rotation        
   rotateset(origphi,pos[nca][2],rom);// rotate C
   rotateset(origphi,pos[nca][3],rom);// rotate 0
   rotateset(origphi,pos[nca][1],rom);//rotate Ca
}


void phipsintermnew(struct geometry& geo,float pos[NAFIT][NAA][3],float fpos[NAFIT][NAA][3],
     float origphi[3],float origpsi[3],float phiv[3],float psiv[3],
     float phi,float psi)
/* rotates  nterm residue by phi and psi about vector phiv and psiv through orig
pos is just a 2 residue array containing c term atoms 
1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in pos
p[1] = phi
p[2] = psi
Note: actually want to rotate by -phi and - psi since going
   in reverse direction
The psi axis or rotation does to not vary from call to call
  but need to calculate a phi axis each call
origpsi = origphi = Ca pos
*/
{
   int i,nca;
   float rom[3][3],dist;

  // rotate by psi
    nca = 1;
   rotaxis(geo.de,geo.ep,-psi,psiv,rom); // rom is rotation matrix for rotation        
   rotatesetnew(origpsi,pos[nca][2],fpos[nca][2],rom);// rotate C
   rotatesetnew(origpsi,pos[nca][3],fpos[nca][3],rom);// rotate 0
   rotatesetnew(origpsi,pos[nca][1],fpos[nca][1],rom);//rotate Ca
   nca = nca+1;
   rotatesetnew(origpsi,pos[nca][4],fpos[nca][4],rom);// rotate N
   rotatesetnew(origpsi,pos[nca][5],fpos[nca][5],rom);// rotate Cb
//   rotatesetnew(origpsi,pos[nca][6],fpos[nca][6],rom);// rotate Cc
  // rotate by phi
   for(i=0;i<=2;i++) // phiv = new N to Ca vector  (nca = 2; origphi = Ca)
      phiv[i] = origpsi[i]-fpos[nca][4][i];
   dist = sqrt( dot(phiv,phiv) );
//   dist = geo.dsqrt[4];
   for(i=0;i<=2;i++)
      phiv[i] = phiv[i]/dist;
   nca = 1;
   rotaxis(geo.de,geo.ep,-phi,phiv,rom); //phi rotation: rom is rotation matrix for rotation        
   rotateset(origphi,fpos[nca][2],rom);// rotate C
   rotateset(origphi,fpos[nca][3],rom);// rotate 0
   rotateset(origphi,fpos[nca][1],rom);//rotate Ca
}


void checkfuse(struct griddata& den1,struct geometry& geo,int canfuse[2][3],int *ifuse) 
/* check if met another fit and can still fuse
*/
{
   int nii[2],cfit,nfit,newfit,delfit,iend[2];
   struct pepfit tfit;

   tfit.nalloc= -10; // initial default - indicates have not yet allocated   
   tfit.qual = -1100.0;
   allocatefit(tfit,NAFIT); // temporary fit used for fusion, etc.
    nii[0]=nii[1] = 0;  // dummy values, the correct values are added later
   cfit = nfit = -1; // indicates did not fuse
   iend[0]=geo.nend[0]; // save original because changed if fuse
   iend[1]=geo.nend[1];
   if( (canfuse[0][0]>0)&&(geo.nend[1]== canfuse[0][1]-1)
            &&(canfuse[0][2]==2) ){// then have deleted 1 res and need to delete another
         geo.nend[1] = geo.nend[1]-1;
         geo.nafit = geo.nafit-1;
   }
   if( (canfuse[1][0]>0)&&(geo.nend[0]== canfuse[1][1]+1)
            &&(canfuse[1][2]==2) ){// then have deleted 1 res and need to delete another
         geo.nend[0] = geo.nend[0]+1;
         geo.nafit = geo.nafit-1;
   }
   if( (canfuse[0][0]>0)&&(geo.nend[1] == canfuse[0][1]) ){ // then can fuse at cterm end
        cfit = canfuse[0][0];
        if(verbose>=1)
           printf("FUSING Cterm end of geo with fit %d and returning new fit %d\n",cfit,cfit);
        copygeotofit(geo,tfit,nii);
        fuseextfit3(den1,geo,tfit,fit[cfit],fit[cfit]); // fuses 2 fits and returns new fit = fit[cfit]
        *ifuse = cfit; // indicates fused - new fit = ifuse
   }
   if( (canfuse[1][0]>0)&&(iend[0] == canfuse[1][1]) ){ // then can fuse at nterm end
         nfit = canfuse[1][0];
         if(cfit>0){// then already fused and replaced geo fit fit[cfit]
             if(cfit>nfit){ // delete the higher numbered fit
                newfit = nfit;
                delfit = cfit;
             }
             else{
                newfit = cfit;
                delfit = nfit;
             }
             if(verbose>=1)
                 printf("FUSING Nterm end of fused fit %d with fit %d and returning new fit %d\n",
                       cfit,nfit,newfit);
             fuseextfit3(den1,geo,fit[nfit],fit[cfit],fit[newfit]); // fuses 2 fits and returns new fit = tfit
             removefit(fit,delfit); // this removes higher numbered fit from file and saves new new fitifle
             fitnum[ fitnum[0]+1 ] = -10; // Used as indicator that fit is empty
             *ifuse = newfit; // indicates fused
         }
         else{ // then just fuse geo with nfit
            if(verbose>=1)
               printf("FUSING Nterm end of geo with fit %d and returning new fit %d\n",nfit,nfit);
            copygeotofit(geo,tfit,nii);
            fuseextfit3(den1,geo,fit[nfit],tfit,fit[nfit]); // fuses 2 fits and returns new fit = nfit
            *ifuse = nfit; // indicates fused
         }    
   }
   freepepfit(tfit);
}   

int checkangrange(struct geometry& geo,float phi,float psi,int rtype,
    float *phimin,float *phimax,float *psimin,float *psimax)
/*
NEW: 8dec98  Allow extra 3 degrees angle range
 phi,psi = absolute  ph/psi angles
 return 0 if not in range, 1 if in range
 geo.itype = 1 (helix)  or 2 (sheet)
 check if phi psi in range for itype
If use an error weighting scheme that includes angles, should not need this
  add small delang so that is delphi close to limit (as set in tordyn) will not give error
*/
{
   float delr;
#if 0 // for debugging
rtype = 1;
phi= -125.194*PI/180.0;  psi= 1.411*PI/180.0;
#endif 
   if(rtype ==1){ // for helix, have strong angforconstraint, use smaller range
//      delr = 5.0*PI/180.0;
      delr = 7.0*PI/180.0; // On 24apr99 Tried Increase range
      *phimin = geo.sheet[rtype][0]-delr;
      *phimax = geo.sheet[rtype][1]+delr;
#if 0 // Commented out 30may00
      psim = geo.sheet[rtype][5]*phi + geo.sheet[rtype][6]; // correalted ideal psi
      *psimin = psim -geo.sheet[rtype][7];// correlated psimin
      *psimax = psim +geo.sheet[rtype][7];
      if(*psimin < geo.sheet[rtype][2]) // absolute allowed min.
             *psimin = geo.sheet[rtype][2];
      if(*psimax > geo.sheet[rtype][3]) // absolute allowed max.
             *psimax = geo.sheet[rtype][3];
#endif
#if 1//NEW  30may00 just use absolute min/max at all times
      *psimin = geo.sheet[rtype][2];
      *psimax = geo.sheet[rtype][3];
#endif
      if( (phi< *phimin) ||(phi> *phimax) )
          return 0;
      else{ // phi OK 
         if( (psi < *psimin-delr)||(psi > *psimax+delr)  )
             return 0;
         else
           return 1;
      }
   } // rtype = 1
   else{ // not helix
      delr = 12.0*PI/180.0;  // Used upto 11feb99
//        delr = 16.0*PI/180.0;  
      if(rtype==2){
        if (psi < -130.0*PI/180.0)// for sheet allow angle to psi >180.0 - which is shfifted to -180
           psi = psi+2.0*PI;
        if (phi > 130.0*PI/180.0)// for sheet allow angle to phi < -180.0 - which is shfifted to -180
            phi = phi-2.0*PI;
      }
      *phimin = -delr+geo.sheet[rtype][0];
      *phimax =  delr+geo.sheet[rtype][1];
      *psimin =  -delr+geo.sheet[rtype][2];
      *psimax = delr+geo.sheet[rtype][3];
      if( (phi < *phimin)||(phi > *phimax)||
           (psi< *psimin)||(psi> *psimax) )
          return 0;
      else
         return 1;
   } // not helix
}

void ranktop(int n1,int n2,float maxden[MAXSTRONG],float maxphipsi[MAXSTRONG][2])
/*
   goes through list of n from n1 to n2 densities, 
       puts max value in position 1
*/
{
    int i,imax;
    float fmax,ftemp,ftemp1;

    fmax = -1000.0;
    for(i=n1;i<=n2;i++){ // find fmax
      if(maxden[i]> fmax){
          imax = i;
          fmax = maxden[i];
      }
    }
    if(imax!=n1){ // then exchange so that n1 is stronges
       ftemp = maxden[n1];
       maxden[n1] = maxden[imax];
       maxden[imax]=ftemp;
       ftemp = maxphipsi[n1][0];
       ftemp1 = maxphipsi[n1][1];
       maxphipsi[n1][0]=maxphipsi[imax][0];
       maxphipsi[imax][0] = ftemp;
       maxphipsi[n1][1]=maxphipsi[imax][1];
       maxphipsi[imax][1] = ftemp1;
   }
}
void findstrongphicterm(struct geometry& geo,struct griddata& den1,
    float maxphi[],float maxden[])
/*
  Returns maxphi[0,1] = best phi in phi<0 and phi>0 range
*/
{
   float phi,phi0,psi0;
   float cden[MAXROT],delrot;
   float fpos[NAFIT][NAA][3];
   int i,nrot,n0;

   nrot =36; //MUST BE LESS < 100;  rotate in steps of 10 degrees
   delrot = 2.0*PI/nrot; 
   phi0=psi0 = 0.0; // set phi psi = 0
   n0=geo.nend[1]; // end before extension
   for(i =0;i<nrot;i++){// rotate in steps of 10 degrees - find max C den and corresponding Cb den
     phi= phi0+delrot*i; 
     makealanine2(geo,geo.pos,0,geo.nend[1],phi,psi0);
     cden[i]=aveatom(den1,geo,2,n0,fpos); // store density of c  (add 2 so can use cbden-2)
   }//i
   maxden[0] = maxden[1] = -1010.0;
   for(i =0;i<nrot;i++){// - find max C den and corresponding Cb den
     phi= phi0+delrot*i; 
     if(phi>PI)
       phi =  phi - 2.0*PI;
     if( (phi<0) && (cden[i]>maxden[0]) ){
        maxden[0]= cden[i];
        maxphi[0]= phi;
     }
     else if( (phi>0) && (cden[i]>maxden[1]) ){
        maxden[1]= cden[i];
        maxphi[1]= phi;
     }
   }
   if(verbose>=2)
     printf(" Best neg phi = %5.3f (den = %5.3f) Best pos phi = %5.3f  (den= %5.3f)\n",
          maxphi[0],maxden[0],maxphi[1],maxden[1]);
}

 
void findstrongphipsinterm(struct geometry& geo,struct griddata& den1,
    float maxphipsi[MAXSTRONG][2],float maxden[MAXSTRONG],int *nstrong)
/*
Brute force -
  For each phi, try all psi - store ave of O,N,Ca density
  Finds the the best phi angle for addition of residue at cterm
   end by finding best fit for either C or Cb (or both)
*/
{
   float phi,psi,phi0,psi0,rotv[3],mag;
   float cden[MAXROT][MAXROT],delrot;
   float fpos[NAFIT][NAA][3];
   int i,i2,k,nrot,n0;

   nrot =36; //MUST BE LESS < 100;  rotate in steps of 10 degrees
   delrot = 2.0*PI/nrot; 
   phi0=psi0 = 0.0; // set phi psi = 0
   *nstrong = 0;
   n0=geo.nend[0]; // end before extension
   for(i =0;i<nrot;i++){// rotate in steps of 10 degrees - find max C den and corresponding Cb den
     psi= psi0+delrot*i; 
     makerevalanine2(geo,geo.pos,0,n0,phi0,psi);
     for(k=0;k<=2;k++) // Ca to N vector
        rotv[k] = geo.pos[n0][1][k]-geo.pos[n0][4][k];
     mag = sqrt( dot(rotv,rotv) );  
     for(k=0;k<=2;k++) 
          rotv[k]=rotv[k]/mag;
     for(i2=0;i2<nrot;i2++){
        phi= phi0+delrot*i2;
        nrotcoca(geo,geo.pos,fpos,n0,rotv,geo.pos[n0][1],phi); //rotate c and cb by phi about nca vec
        avecocaden(den1,geo,n0-1,fpos,&cden[i+2][i2+2]);// store ave density of o,n,Ca  (add 2 so can use cbden-2)
     }
   }//i
   for(i =2;i<nrot+2;i++){  // make periodic
     for(k=0;k<2;k++){
         cden[k][i]= cden[nrot+k][i];
         cden[nrot+2+k][i]=cden[2+k][i];
         cden[i][k]= cden[i][nrot+k];
         cden[i][nrot+2+k]=cden[i][2+k];
      }
   }//i
   for(i=0;i<=1;i++){ // periodic for corners
     for(k=0;k<2;k++){
         cden[k][i]= cden[nrot+k][i];
         cden[nrot+2+k][i]=cden[2+k][i];
         cden[i][k]= cden[i][nrot+k];
         cden[i][nrot+2+k]=cden[i][2+k];
      }
   }
  for(i =2;i<nrot+2;i++){// find maxima of C density
      for(i2 =2;i2<nrot+2;i2++){      
         if(cden[i][i2]>0.0)
          if( cden[i][i2]>cden[i-1][i2])
            if( cden[i][i2]>cden[i-2][i2])
              if( cden[i][i2]> cden[i+1][i2])
                if( cden[i][i2]>cden[i+2][i2] )
                  if( cden[i][i2]>cden[i][i2-1])
                    if( cden[i][i2]>cden[i][i2-2])
                      if( cden[i][i2]> cden[i][i2+1])
                        if( cden[i][i2]>cden[i][i2+2] )
                          if(cden[i][i2]>cden[i-1][i2-1] ) // check 1 point on diagonal
                            if(cden[i][i2]>cden[i+1][i2+1] ){// found max    // check 1 point on diagonal
                              *nstrong = *nstrong+1;
                              if(*nstrong == MAXSTRONG){
                                 fprintf(fpout,"ERROR:  nstrong = MAXSTRONG  in extendfit - trncating\n");
                                 *nstrong = MAXSTRONG -1;
                                 goto quitrout;
                              } 
                              maxden[*nstrong] = cden[i][i2];
                              maxphipsi[*nstrong][0] = -(phi0+ (i2-2)*delrot); //minus the angle becuase in negative directin the number of delrot angle steps corresponding to i
                              maxphipsi[*nstrong][1] =psi0+ (i-2)*delrot; // the number of delrot angle steps corresponding to i
                           }// found max
     } // i2
  }//i
  quitrout:;
  for(i=1;i<= *nstrong;i++){
    if(maxphipsi[i][0]>PI)
        maxphipsi[i][0] =  maxphipsi[i][0] - 2.0*PI;
    if(maxphipsi[i][1]>PI)
        maxphipsi[i][1] =  maxphipsi[i][1] - 2.0*PI;
  }     
  ranktop(1,*nstrong,maxden,maxphipsi); // places stongest in positon 1
  ranktop(2,*nstrong,maxden,maxphipsi); // places next stongest in positon 2
  ranktop(3,*nstrong,maxden,maxphipsi); // places next stongest in positon 3
  ranktop(4,*nstrong,maxden,maxphipsi); // places next stongest in positon 4
  if(verbose>=2){
     printf(" FOUND %d strong phi-psi:\n",*nstrong);
     for(i=1;i<= *nstrong;i++)
        printf("   i  = %d maxden= %5.3f phi = %5.3f psi =%5.3f \n",
          i,maxden[i],maxphipsi[i][0]*180.0/PI,maxphipsi[i][1]*180.0/PI);
  }
}


 
void findstrongphipsicterm(struct geometry& geo,struct griddata& den1,
    float maxphipsi[MAXSTRONG][2],float maxden[MAXSTRONG],int *nstrong)
/*
Brute force -
  For each phi, try all psi - store ave of O,N,Ca density
  Finds the the best phi angle for addition of residue at cterm
   end by finding best fit for either C or Cb (or both)
*/
{
   float phi,psi,phi0,psi0,rotv[3],mag;
   float cden[MAXROT][MAXROT],delrot;
   float fpos[NAFIT][NAA][3];
   int i,i2,k,nrot,n0;

   nrot =36; //MUST BE LESS < 100;  rotate in steps of 10 degrees
   delrot = 2.0*PI/nrot; 
   phi0=psi0 = 0.0; // set phi psi = 0
   *nstrong = 0;
   n0=geo.nend[1]; // end before extension
   for(i =0;i<nrot;i++){// rotate in steps of 10 degrees - find max C den and corresponding Cb den
     phi= phi0+delrot*i; 
     makealanine2(geo,geo.pos,0,geo.nend[1],phi,psi0);
     for(k=0;k<=2;k++) // Ca to C vector
        rotv[k] = geo.pos[n0][2][k]-geo.pos[n0][1][k];
     mag = sqrt( dot(rotv,rotv) );  
     for(k=0;k<=2;k++) 
          rotv[k]=rotv[k]/mag;
     for(i2=0;i2<nrot;i2++){
        psi= psi0+delrot*i2;
        rotonca(geo,geo.pos,fpos,n0,rotv,geo.pos[n0][2],psi); //rotate o,n,and ca about rotv
        aveoncaden(den1,geo,n0,fpos,&cden[i+2][i2+2]);// store ave density of o,n,Ca  (add 2 so can use cbden-2)
     }
   }//i
   for(i =2;i<nrot+2;i++){  // make periodic
     for(k=0;k<2;k++){
         cden[k][i]= cden[nrot+k][i];
         cden[nrot+2+k][i]=cden[2+k][i];
         cden[i][k]= cden[i][nrot+k];
         cden[i][nrot+2+k]=cden[i][2+k];
      }
   }//i
   for(i=0;i<=1;i++){ // periodic for corners
     for(k=0;k<2;k++){
         cden[k][i]= cden[nrot+k][i];
         cden[nrot+2+k][i]=cden[2+k][i];
         cden[i][k]= cden[i][nrot+k];
         cden[i][nrot+2+k]=cden[i][2+k];
      }
   }
  for(i =2;i<nrot+2;i++){// find maxima of C density
      for(i2 =2;i2<nrot+2;i2++){      
         if(cden[i][i2]>0.0)
          if( cden[i][i2]>cden[i-1][i2])
            if( cden[i][i2]>cden[i-2][i2])
              if( cden[i][i2]> cden[i+1][i2])
                if( cden[i][i2]>cden[i+2][i2] )
                  if( cden[i][i2]>cden[i][i2-1])
                    if( cden[i][i2]>cden[i][i2-2])
                      if( cden[i][i2]> cden[i][i2+1])
                        if( cden[i][i2]>cden[i][i2+2] )
                          if(cden[i][i2]>cden[i-1][i2-1] ) // check 1 point on diagonal
                            if(cden[i][i2]>cden[i+1][i2+1] ){// found max    // check 1 point on diagonal
                              *nstrong = *nstrong+1;
                              if(*nstrong == MAXSTRONG){
                                 fprintf(fpout,"ERROR:  nstrong = MAXSTRONG  in extendfit - trncating\n");
                                 *nstrong = MAXSTRONG -1;
                                 goto quitrout;
                              } 
                              maxden[*nstrong] = cden[i][i2];
                              maxphipsi[*nstrong][0] =phi0+ (i-2)*delrot; // the number of delrot angle steps corresponding to i
                              maxphipsi[*nstrong][1] =psi0+ (i2-2)*delrot; // the number of delrot angle steps corresponding to i
                           }// found max
     } // i2
  }//i
  quitrout:;
  for(i=1;i<= *nstrong;i++){
    if(maxphipsi[i][0]>PI)
        maxphipsi[i][0] =  maxphipsi[i][0] - 2.0*PI;
    if(maxphipsi[i][1]>PI)
        maxphipsi[i][1] =  maxphipsi[i][1] - 2.0*PI;
  }     
  ranktop(1,*nstrong,maxden,maxphipsi); // places stongest in positon 1
  ranktop(2,*nstrong,maxden,maxphipsi); // places next stongest in positon 2
  ranktop(3,*nstrong,maxden,maxphipsi); // places next stongest in positon 3
  ranktop(4,*nstrong,maxden,maxphipsi); // places next stongest in positon 4
  if(verbose>=2){
     printf(" FOUND %d strong phi-psi:\n",*nstrong);
     for(i=1;i<= *nstrong;i++)
        printf("   i  = %d maxden= %5.3f phi = %5.3f psi =%5.3f \n",
          i,maxden[i],maxphipsi[i][0]*180.0/PI,maxphipsi[i][1]*180.0/PI);
  }
}

void addcterm(struct geometry& geo,struct griddata& den1,int constrainttype)
/* code from extendcterm that add cterm residue and carries out powell refinement
*/
{
   int i,n0,irange,type;
   float avecb2,phi,psi;
   float maxphipsi[MAXSTRONG][2], maxden[MAXSTRONG];
   float psideg;
   int nstrong;

   n0 = geo.nend[1]; //Increase n0 by 1 Note geo.nafit=geo.nend[1] is equivalent to n0+1
   geo.cis[n0] = 0; // default - trans proline
   if(n0>NAFIT-2){
     fprintf(fpout," ERROR: n0>NAFIT-2 - quitting extendcterm\n");
     goto endcterm;
   }
   type=geo.rtype[n0]= constrainttype;
   if(verbose>=2)
      fprintf(fpout,"in addcterm type = %d\n",type);

   findstrongphipsicterm(geo,den1,maxphipsi,maxden,&nstrong);
   if(type==0){ // use best phi - psi
//      findstrongphipsicterm(geo,den1,maxphipsi,maxden,&nstrong);
      phi = maxphipsi[1][0];
      psi = maxphipsi[1][1];
printf(" Using phi/psi (degrees) = %5.3f  %5.3f\n",phi*180.0/PI,psi*180.0/PI);
   } 
#if 0 //  // use default psi
   else{ // some constaint
      psi = geo.psi[type];  // always use default psi
      findstrongphicterm(geo,den1,maxphi,maxden);
      if( (type==1)||(type==2)||(type==5)||(type==6) ){
        if(maxden[0] < 0.5*geo.extendden){ //bad density for phi<0 then use default
           if(verbose>=2)
              printf("best phi not used because maxden < 0.5*geo.extendden\n");
           phi = geo.phi[type]; // default values, used if bestphi in wrong region
        }
        else{ //maxden OK
           phi = maxphi[0]; // default values, used if bestphi in wrong region
        }
      } //type =1
      else  if( (type==3)||(type==4) ){
        if(maxden[1] < 0.5*geo.extendden){ //bad density for phi<0 then use default
           if(verbose>=2)
              printf("best phi not used because maxden < 0.5*geo.extendden\n");
           phi = geo.phi[type]; // default values, used if bestphi in wrong region
        }
        else{ //maxden OK
           phi = maxphi[1]; // default values, used if bestphi in wrong region
     }
   } 
#endif //use default psi
   else{ // some constaint
    for(i=1;i<=4;i++){ // look at top for results from findstrongphipsi - use strongest
     phi = maxphipsi[i][0];
     psi = maxphipsi[i][1];
     if(i<= nstrong){
       if(maxden[i]>  0.5*geo.extendden){
          if(phi<0){
            psideg =psi*180.0/PI;
            if( (type==1)&&(psideg< 45.0)&&(psideg> -100.0) )
               goto foundphipsi;
            else if( (type==2)&&(psideg> 45.0) )
               goto foundphipsi;
            else if( (type==5)&&(psideg< 111.0)&&(psideg> 9.0) )
               goto foundphipsi;
            else if( (type==6)&&(psideg< 61.0)&&(psideg> -41.0) )
               goto foundphipsi;
          }// phi <0
          else { // phi >0
            if( (type==3)&&(psideg< 101.0)&&(psideg> -11.0) )
               goto foundphipsi;
            else if( (type==4)&&(psideg< -91.0) )
               goto foundphipsi;
          } // phi>0
        } // maxden >>
      } // i < = nstrong
     } // i
     phi = geo.phi[type]; // IF REACH HERE - USE DEFAULT
     psi = geo.psi[type];  
     foundphipsi:; // jump to here if found max phi/psi
   } // some constraint
#if 0 // for debugging
printf(" Input phi, psi in degrees\n");
scanf(" %f  %f",&phi,&psi);
phi = phi*PI/180.0;
psi = psi*PI/180.0;
   makealanine2(geo,geo.pos,0,n0,phi,psi); // nside = 1
//   makecisalanine2(geo,geo.pos,0,n0,phi,psi); // nside = 1
goto skipstuff;
#endif
   if(verbose>=2)
      printf("TYPE = %d USING PHI = %5.3f  PSI = %5.3f\n",type,phi*180.0/PI,psi*180.0/PI);
   makealanine2(geo,geo.pos,0,n0,phi,psi); // nside = 1
   skipstuff:;
   if(0== checkboundary(den1,geo.pos,1,n0+1,geo.arange) ){ // then outside boundary - finished
       fprintf(fpout,"WARNING  outside boundary in addcterm - ADDING DEFAULT ALANINE\n");
       geo.iside[n0]=1;
       geo.nafit=geo.nafit+1; // use last added residue
       geo.nend[1] = geo.nend[1]+1;
   }
   else{ // boindary OK  continue 
     irange = 1;  // INdicates angle in OK range - relevant only if powell minimumzations used 
     if( (geo.nside ==2) ){
            bestcb1(den1,geo,geo.pos,n0,&avecb2); // place second C in best postion
            geo.iside[n0] =2;
     }
     else
           geo.iside[n0]=1;
     if(irange ==0){
        fprintf(fpout,"Quitting because outside boundary after cpowell\n");
     }
     else{ // irnage OK
#if 0 // Use this normally
        avectermden(geo.usecb,den1,geo,geo.nend[1],geo.pos,&lastden,&nbad); // ave cterm density 
#endif
        geo.nafit=geo.nafit+1; // use last added residue
        geo.nend[1] = geo.nend[1]+1;
#if 0 // Use this for debugging
float avecb2,phipsi[2]; 
       sidenumreg(geo.nend[1]-geo.endmove-1,geo.nend[1],den1,geo); // finds sidenum 
       avedenreg(den1,geo,geo.pos,&lastden,&avecb2,&nbad,
                  geo.nend[1]-1,geo.nend[1]); // Find average density for last two additions
      findphipsi(geo.pos,geo.nend[1]-2,&phipsi[0],&phipsi[1]);
      if(verbose >=2)
         fprintf(fpout,"ADDED CTERM RESIDUE: geo.rtype = %d lastden = %f  nbad = %d phi = %5.3f psi = %5.3f\n",
            type,lastden,nbad,phipsi[0]*180.0/PI,phipsi[1]*180.0/PI);
#endif
     }// irnage OK
   }// boudnary OK
   endcterm:;
}


void naddnterm(struct geometry& geo,struct griddata& den1,int constrainttype)
/* 
New version - uses findstronphipsi
code from extendcterm that add cterm residue and carries out powell refinement
*/
{
   int i,n0,irange,type;
   float avecb2,phi,psi;
   float maxphipsi[MAXSTRONG][2], maxden[MAXSTRONG];
   float psideg;
   int nstrong;

   n0 = geo.nend[0]; //Increase n0 by 1 Note geo.nafit=geo.nend[1] is equivalent to n0+1
   geo.cis[n0] = 0; // default - trans proline
   if(n0>NAFIT-2){
     fprintf(fpout," ERROR: n0>NAFIT-2 - quitting extendcterm\n");
     goto endcterm;
   }
   type=geo.rtype[n0]= constrainttype;
   if(verbose>=2)
      fprintf(fpout,"in addnterm type = %d\n",type);

   findstrongphipsinterm(geo,den1,maxphipsi,maxden,&nstrong);
   if(type==0){ // use best phi - psi
      phi = maxphipsi[1][0];
      psi = maxphipsi[1][1];
printf(" Using phi/psi (degrees) = %5.3f  %5.3f\n",phi*180.0/PI,psi*180.0/PI);
   } 
   else{ // some constaint
    for(i=1;i<=4;i++){ // look at top for results from findstrongphipsi - use strongest
     phi = maxphipsi[i][0];
     psi = maxphipsi[i][1];
     if(i<= nstrong){
       if(maxden[i]>  0.5*geo.extendden){
          if(phi<0){
            psideg =psi*180.0/PI;
            if( (type==1)&&(psideg< 45.0)&&(psideg> -100.0) )
               goto foundphipsi;
            else if( (type==2)&&(psideg> 45.0) )
               goto foundphipsi;
            else if( (type==5)&&(psideg< 111.0)&&(psideg> 9.0) )
               goto foundphipsi;
            else if( (type==6)&&(psideg< 61.0)&&(psideg> -41.0) )
               goto foundphipsi;
          }// phi <0
          else { // phi >0
            if( (type==3)&&(psideg< 101.0)&&(psideg> -11.0) )
               goto foundphipsi;
            else if( (type==4)&&(psideg< -91.0) )
               goto foundphipsi;
          } // phi>0
        } // maxden >>
      } // i < = nstrong
     } // i
     phi = geo.phi[type]; // IF REACH HERE - USE DEFAULT
     psi = geo.psi[type];  
     foundphipsi:; // jump to here if found max phi/psi
   } // some constraint
   if(verbose>=2)
      printf("TYPE = %d USING PHI = %5.3f  PSI = %5.3f\n",type,phi*180.0/PI,psi*180.0/PI);
   makerevalanine2(geo,geo.pos,0,n0,phi,psi);
  skipstuff:;
   if(0== checkboundary(den1,geo.pos,1,n0,geo.arange) ){ // then outside boundary - finished
       fprintf(fpout,"WARNING  outside boundary in addcterm - ADDING DEFAULT ALANINE\n");
       geo.iside[n0]=1;
       geo.nafit=geo.nafit+1; // use last added residue
       geo.nend[0] = geo.nend[0]-1;
   }
   else{ // boindary OK  continue 
     irange = 1;  // INdicates angle in OK range - relevant only if powell minimumzations used 
     if( (geo.nside ==2) ){
            bestcb1(den1,geo,geo.pos,n0,&avecb2); // place second C in best postion
            geo.iside[n0] =2;
     }
     else
           geo.iside[n0]=1;
     if(irange ==0){
        fprintf(fpout,"Quitting because outside boundary after cpowell\n");
     }
     else{ // irnage OK
        geo.nafit=geo.nafit-1; // use last added residue
        geo.nend[0] = geo.nend[0]-1;
     }// irnage OK
   }// boudnary OK
   endcterm:;
}


#if 1 // old version - does not use findstrongphipsi
void addnterm(struct geometry& geo,struct griddata& den1,int constrainttype)
/* code from extendcterm that add cterm residue and carries out powell refinement
*/
{
   int n0,irange,nbad,type;
//int usepsicb=0;
   float lastden,avecb2,maxpsi,maxphi;

   n0 = geo.nend[0]; //Increase n0 by 1 Note geo.nafit=geo.nend[1] is equivalent to n0+1
   type=geo.rtype[n0]= constrainttype;
   if(n0<2){
     fprintf(fpout," ERROR: n0 <2  quitting extendnterm \n");
     goto endnterm;
   }
   maxphi = geo.phi[type]; // default values
   maxpsi = geo.psi[type];
#if 1 // If psimax in correct region, then use as intial fit
float phi0,psi0,rotv[3],mag,maxnden,nden,delrot,psi;
float fpos[NAFIT][NAA][3],psin,psideg;
int i,k,imaxn,nrot;
   nrot =36; //MUST BE LESS < 100;  rotate in steps of 10 degrees
   delrot = 2.0*PI/nrot; 
   phi0=psi0 = 0.0; // set phi psi = 0
   n0=geo.nend[0]; // end before extension
   for(k=0;k<=2;k++) // N to Ca vector
        rotv[k] = geo.pos[n0][1][k]-geo.pos[n0][2][k];
   mag = sqrt( dot(rotv,rotv) );  
   for(k=0;k<=2;k++) // C to Ca vector
      rotv[k]=rotv[k]/mag;
#if 0 // debugging
printf(" Input phi, psi in degrees\n");
scanf(" %f  %f",&maxphi,&maxpsi);
maxphi = maxphi*PI/180.0;
maxpsi = maxpsi*PI/180.0;
   makecisrevalanine2(geo,geo.pos,0,n0,maxphi,maxpsi);
   goto skipstuff;
#endif
   makerevalanine2(geo,geo.pos,0,n0,phi0,psi0);
   maxnden = -1000.0;
   for(i =0;i<nrot;i++){// rotate in steps of 10 degrees - find max C den and corresponding Cb den
     psi= psi0+delrot*i; 
     rotncb(geo,geo.pos,fpos,n0,rotv,geo.pos[n0][1],psi); //rotate c and cb by phi about nca vec
     nden=aveatom(den1,geo,4,n0,fpos); // store density of n  
     if(nden>maxnden){
        maxnden = nden;
        imaxn = i;
     }
   }
    psin = imaxn*delrot;  
   if(psin>PI)
       psin = psin-2.0*PI;
   psin = - psin; // minus sign because going in oposite direction
   if(maxnden > 0.5*geo.extendden){ // then try this angle
      psideg = psin*180.0/PI;
      if( (type==1)&&(psideg< 45.0)&&(psideg> -100.0) )
              maxpsi = psin;
      else if( (type==2)&&(psideg> 45.0) )
             maxpsi = psin;
      else if( (type==3)&&(psideg< 101.0)&&(psideg> -11.0) )
             maxpsi = psin;
      else if( (type==4)&&(psideg< -91.0) )
             maxpsi = psin;
      else if( (type==5)&&(psideg< 111.0)&&(psideg> 9.0) )
             maxpsi = psin;
      else if( (type==6)&&(psideg< 61.0)&&(psideg> -41.0) )
             maxpsi = psin;
   }
//printf("maxpsi = %5.3f maxnden = %5.3f\n",maxpsi*180.0/PI,maxnden);
#endif
   makerevalanine2(geo,geo.pos,0,n0,maxphi,maxpsi);
skipstuff:; // skip here if use makecis....
   if(0== checkboundary(den1,geo.pos,1,n0-1,geo.arange) ){ // then outside boundary - finished
       fprintf(fpout,"WARNING  outside boundary in addnterm - ADDING DEFAULT ALANINE\n");
       geo.iside[n0]=1;
       geo.nafit=geo.nafit+1; // use last added residue
       geo.nend[0] = geo.nend[0]-1;
   }
   else{ // boindary OK  continue 
     irange = 1;  // INdicates angle in OK range - relevant only if powell minimumzations used     
    if(geo.nside ==2){
            bestcb1(den1,geo,geo.pos,n0,&avecb2); // place second C in best postion
            geo.iside[n0]=2;
     }
     else
            geo.iside[n0]=1;
     if(irange ==0){
        fprintf(fpout,"Quitting because outside boundary after cpowell\n");
     }
     else{ // irnage OK
//        aventermden(geo.usecb,den1,geo,geo.nend[0]-1,geo.pos,&lastden,&nbad); // 0 = do not use Cb  This lastden is pure density, no angle weighting ave nterm density 
        geo.nafit=geo.nafit+1; // use last added residue
        geo.iside[ geo.nend[0] ] = geo.nside;  // set nside for added residue = default
        geo.nend[0] = geo.nend[0]-1;
   sidenumreg(geo.nend[0],geo.nend[0]+geo.endmove,den1,geo); // finds sidenum 
   avedenreg(den1,geo,geo.pos,&lastden,&avecb2,&nbad,
                  geo.nend[0],geo.nend[0]+1); // Find average density for last two additions
if(verbose>=2)
  fprintf(fpout,"ADDED NTERM RESIDUE: type = %d lastden = %f  nbad = %d ends = %d %d\n",
       type,lastden,nbad,geo.nend[0],geo.nend[1]);
#if 0
float phi,psi;
findphipsi(geo.pos,geo.nend[0],&phi,&psi);
fprintf(fpout,"  phi = %f    psi = %f\n",phi,psi);
#endif
     }
   }// boudnary OK
   endnterm:;
}
#endif

int checkresidue(int nc,struct geometry& geo,struct griddata& den1,
            int ***set,float lastden,int nbad,float phi,float psi,int rtype)
/*
 NOTE: prior to 30may00 - had checked both ends of helix dist
   New - 30may00 - use nc to determine which end to check
 Checks residue and returns 0 if not OK, 1 if OK
  and prints out reason for quiting
 if nc = -1, do not check set, else, if nc = 0 for nterm, nc = 1 for c term
*/
{
   float phimin,phimax,psimin,psimax,dist;
#if 0 //NEW 18oct00 - do not checkset now because are trying to fuse
   if(nc==0){
       ii=checksetnterm(den1,geo,set,geo.nend[0]);
       if(ii<=0){
//if(verbose >=1)
          fprintf(fpout," IN checkres bad NTERM END CLOSE TO SET %d\n",-ii);
          return 0;
       } 
   }
   else if(nc==1){ 
       ii=checksetcterm(den1,geo,set,geo.nend[1]);
       if(ii<=0){
if(verbose>=1)
          fprintf(fpout," IN checkres bad CTERM END CLOSE TO SET %d\n",-ii);
          return 0; 
       }
   }
#endif
   if(rtype>=0){// then check angrange
    if(checkangrange(geo,phi,psi,rtype,&phimin,&phimax,&psimin,&psimax)==0){
//if(verbose >=1)
      fprintf(fpout,"IN checkres bad PHI= %6.3f/PSI=%6.3f NOT IN RANGE (type = %d: %5.3f %5.3f %5.3f %5.3f)\n",
             phi*180.0/PI,psi*180.0/PI,rtype,phimin*180.0/PI,phimax*180.0/PI,psimin*180.0/PI,psimax*180.0/PI);
      return 0;
    }
   } // rtype >=0
#if 0  // pre 10feb99 - Not needed becuase phi must be less to 2 PI 
   else{ // check anglimit
     if(  (fabs(phi)>2.0*PI) || (fabs(psi)>2.0*PI) ){
if(verbose>=1)
         fprintf(fpout," QUITING BECAUSE PHI= %6.3f/PSI=%6.3f GREATER THAN LIMIT (2PI = 360)\n",
             phi*180.0/PI,psi*180.0/PI);
         return 0;
     }
  }
#endif
  if (nbad >geo.nbadend) {
if(verbose>=1)
      fprintf(fpout," IN checkres bad  nbad = %d\n",nbad);
      return 0; 
   }
   if (lastden<geo.extendden){
if(verbose>=1)
      fprintf(fpout," IN checkres bad  lastden = %6.3f\n",lastden);
      return 0;
   }
   if( (rtype==1)&&( (geo.nend[1]-geo.nend[0])>4) ){//If helix - check Ca[i]-Ca[i+4] dist
      if(nc==0){ // check res 1
         dist=distv(geo.pos[geo.nend[0]][1],geo.pos[geo.nend[0]+4][1]);
         if(dist < geo.ca1_4min){
            fprintf(fpout,"IN checkres bad  because Ca[1]-Ca[5] dist = %5.3f\n",dist); 
            return 0;
         }
      }
      else if(nc==1){ 
         dist=distv(geo.pos[geo.nend[1]-4][1],geo.pos[geo.nend[1]][1]);
         if(dist < geo.ca1_4min){
            fprintf(fpout,"IN checkres bad  because Ca[end-4]-Ca[end] dist = %5.3f\n",dist); 
            return 0;
         }
      }
   } // helix constraint 
   return 1;
}

void initialcphipsi(struct geometry& geo,struct griddata& den1,
        int type,float *maxphi)
/*
NOTE:  cbden not used
 Cterm end: Initial guess for phi angles based on density
  Rotate C and Cb about N-Ca bond
    Use whatever phi gives best density for C or Cb
*/
{
float phi0,psi0,rotv[3],mag,maxcden,cden,delrot,phi;
float fpos[NAFIT][NAA][3],phideg,phic;
int i,k,imaxc,nrot,n0;
   nrot =36; //MUST BE LESS < 100;  rotate in steps of 10 degrees
   delrot = 2.0*PI/nrot; 
   phi0=psi0 = 0.0; // set phi psi = 0
   n0=geo.nend[1]; // end before extension
   for(k=0;k<=2;k++) // N to Ca vector
        rotv[k] = geo.pos[n0][1][k]-geo.pos[n0][4][k];
   mag = sqrt( dot(rotv,rotv) );  
   for(k=0;k<=2;k++) // N to Ca vector
      rotv[k]=rotv[k]/mag;
   makealanine2(geo,geo.pos,0,geo.nend[1],phi0,psi0);
   maxcden = -1000.0;
   for(i =0;i<nrot;i++){// rotate in steps of 10 degrees - find max C den and corresponding Cb den
     phi= phi0+delrot*i; 
     rotccb(geo,geo.pos,fpos,n0,rotv,geo.pos[n0][1],phi); //rotate c and cb by phi about nca vec
     cden=aveatom(den1,geo,2,n0,fpos); // store density of c  
     if(cden>maxcden){
        maxcden = cden;
        imaxc = i;
     }
   }
   phic = imaxc*delrot;  
   if(phic>PI)
       phic = phic-2.0*PI;
   phideg = -1000.0;
   if(maxcden > 0.5*geo.extendden){ // then try this angle
      phideg = phic*180.0/PI;
      if( (phideg< 1.0)&&(phideg> -161.0) ){
              *maxphi = phic;
      }
   }
if(verbose==2)
  printf("maxphi = %5.3f  phic = %5.3f maxcden=%5.3f phideg=%5.3f\n",
       *maxphi*180.0/PI,phic*180.0/PI,maxcden,phideg);
}


void initialnphipsi(struct geometry& geo,struct griddata& den1,
        int type,float *maxpsi)
/*
NOTE:  cbden not used
N term end:  Initial guess for psi angles based on density
  Rotate Cb and N about C to Ca bond - Find best psi.
  NOTE: Output psi = -bestpsi - since psi is for res. 1 to 2 
     and bestpsi for 2 to 1
1=ca,2=c,3=o;4=n,5=cb; 6=cb2
*/
{
float phi0,psi0,rotv[3],mag,maxnden,nden,delrot,psi;
float fpos[NAFIT][NAA][3],psideg,psin;
int i,k,imaxn,nrot,n0;
   nrot =36; //MUST BE LESS < 100;  rotate in steps of 10 degrees
   delrot = 2.0*PI/nrot; 
   phi0=psi0 = 0.0; // set phi psi = 0
   n0=geo.nend[0]; // end before extension
   for(k=0;k<=2;k++) // N to Ca vector
        rotv[k] = geo.pos[n0][1][k]-geo.pos[n0][2][k];
   mag = sqrt( dot(rotv,rotv) );  
   for(k=0;k<=2;k++) // C to Ca vector
      rotv[k]=rotv[k]/mag;
   makerevalanine2(geo,geo.pos,0,n0,phi0,psi0);
   maxnden= -1000.0;
   for(i =0;i<nrot;i++){// rotate in steps of 10 degrees - find max C den and corresponding Cb den
     psi= psi0+delrot*i; 
     rotncb(geo,geo.pos,fpos,n0,rotv,geo.pos[n0][1],psi); //rotate c and cb by phi about nca vec
     nden=aveatom(den1,geo,4,n0,fpos); // store density of n  
     if(nden>maxnden){
        maxnden = nden;
        imaxn = i;
     }
   }
   psin = imaxn*delrot;  
   if(psin>PI)
       psin = psin-2.0*PI;
   psin = - psin;
   psideg = -1000.0;
   if(maxnden > 0.5*geo.extendden){ // then try this angle
      psideg = psin*180.0/PI; 
      if( (type==1)&&(psideg< 45.0)&&(psideg> -100.0) ){
              *maxpsi = psin;
      }
      else if( (type==2)&&(psideg> 45.0) ){
             *maxpsi = psin;
      }
   }
if(verbose==2)
   printf("maxpsi = %5.3f maxnden = %5.3f psideg = %5.3f\n",
         *maxpsi*180.0/PI,maxnden,psideg);
}

#if 1 // New version - NOTE HAVE CHANGED (21jun99) so that sidenum2 called
void refinecend(struct geometry& geo,struct griddata& den1,int n0,
   float phi,float psi,int *quitref,int *nbad,float *lastden)
/*   Runs tor. dyn refinement on C term end
*/
{
  float avecb2,origrfor;
  int quitcond;

  if(dynquit==0)
     quitcond = 2;
  else 
     quitcond = dynquit;
   origrfor = tordata.rfor;
   *quitref = 0;  // if = 1 then on boundary 
   makealanine2(geo,geo.pos,0,n0,phi,psi);
   if(0== checkboundary(den1,geo.pos,1,n0+1,geo.arange) ){ // then outside boundary - finished
       fprintf(fpout,"Quitting because outside boundary\n");
       *quitref=1;
       goto quitrefinec;
   }
   if(geo.nside ==2)
            bestcb1(den1,geo,geo.pos,n0,&avecb2); // place second C in best postion
// Run tordyn after each addition  see trace.c23jul98 for another option
    geo.nafit=geo.nafit+1; // use last added residue
    geo.nend[1] = geo.nend[1]+1;
    geo.rtype[ geo.nend[1]-1 ] = geo.itype;
    geo.iside[geo.nend[1]-1] = 2; //This sets sides number of side atoms = 2 (bestcb1 above has made Cb2)
    sidenum2(den1,geo); // Not used because set all residues to 2 side chains atoms
//      sidenumreg(geo.begend[0],geo.begend[1],den1,geo); // Not used anymore
    if(tordata.adata[1]>2) //This restarts interactive tor dyn each time called   
            tordata.adata[1] = 2;

#if 1  // try using simulated annealing 
float tormult0;
int i,nstep;
//       geo.endmove = 8;
       tormult0 = 1.5; 
       nstep = 6; // Must be > 1
       for(i=1;i<=nstep;i++){
         tordata.rfor = origrfor*tormult0*(nstep- i)/(nstep-1); // runs from 0 to torlult
         tordynbat(6,den1,geo,tordata,lastden,nbad);// Run tordyn- BE CAREFUL quitcond must be >20 if use detalilden below 
         if(geo.quit==1){
             if(verbose>=1)
                printf("geo.quit =1  - setting lastden to bad value, and resetting geo.quit\n");
             *lastden = -10000.0; // indicates  bad fit, do not rank
             geo.quit = 0; // reset to OK value for next call
             geo.nafit = geo.nafit-1;
             geo.nend[1] = geo.nend[1]-1;
             *quitref=1;
             goto quitrefinec;
         }
       }
#endif
#if 0  //Standard procedure  - worked well until 18oct00
    tordynbat(quitcond,den1,geo,tordata,lastden,nbad);// "2" means use c term density as criteria for q;uiting
    if(tordata.irepeat==1){ //run 30 more times with small random force
           tordata.rfor = tordata.rfor2;
           tordata.adata[1] = 2; 
//          tordynbat(2,den1,geo,tordata,lastden,nbad);// "2" means use c term density as criteria for q;uiting
            tordynbat(20,den1,geo,tordata,lastden,nbad);// "20" means run 20 rounds of refinement
            tordata.rfor = origrfor;
    }
#endif
    avectermden(geo.usecb,den1,geo,geo.nend[1]-1,geo.pos,lastden,nbad); // ave cterm density 
    quitrefinec:;
    tordata.rfor = origrfor;
}

void refinenend(struct geometry& geo,struct griddata& den1,int n0,
   float phi,float psi,int *quitref,int *nbad,float *lastden)
/*   Runs tor. dyn refinement on C term end
*/
{
  float avecb2,origrfor;
  int quitcond;

  if(dynquit==0)
     quitcond = 1;
  else 
     quitcond = dynquit;
   origrfor = tordata.rfor;
   *quitref = 0;  // if = 1 then on boundary 
   makerevalanine2(geo,geo.pos,0,n0,phi,psi);
   if(0== checkboundary(den1,geo.pos,1,n0-1,geo.arange) ){ // then outside boundary - finished
       fprintf(fpout,"Quitting because outside boundary\n");
       *quitref=1;
       goto quitrefinec;
   }
   if(geo.nside ==2)
            bestcb1(den1,geo,geo.pos,n0,&avecb2); // place second C in best postion
// Run tordyn after each addition  see trace.c23jul98 for another option
    geo.nafit=geo.nafit+1; // use last added residue
    geo.nend[0] = geo.nend[0]-1;
    geo.rtype[ geo.nend[0] ] = geo.itype;
    geo.iside[ geo.nend[0]+1 ] = 2; // This sets sides number of side atoms = 2 (bestcb1 above has made Cb2)
    sidenum2(den1,geo);  // Not used anymore
//      sidenumreg(geo.begend[0],geo.begend[1],den1,geo); // Not used anymore
    if(tordata.adata[1]>2) //This restarts interactive tor dyn each time called   
            tordata.adata[1] = 2; 

#if 1  // try using simulated annealing 
float tormult0;
int i,nstep;
//       geo.endmove = 8;
       tormult0 = 1.5; 
       nstep = 6; // Must be > 1
       for(i=1;i<=nstep;i++){
         tordata.rfor = origrfor*tormult0*(nstep- i)/(nstep-1); // runs from 0 to torlult
         tordynbat(6,den1,geo,tordata,lastden,nbad);// Run tordyn- BE CAREFUL quitcond must be >20 if use detalilden below 
         if(geo.quit==1){
             if(verbose>=1)
                printf("geo.quit =1  - setting lastden to bad value, and resetting geo.quit\n");
             *lastden = -10000.0; // indicates  bad fit, do not rank
             geo.quit = 0; // reset to OK value for next call
             geo.nafit = geo.nafit-1;
             geo.nend[0] = geo.nend[0]+1;
             *quitref=1;
             goto quitrefinec;
         }
       }
#endif
#if 0
    tordynbat(quitcond,den1,geo,tordata,lastden,nbad);// "1" means use n term density as criteria for q;uiting
    if(tordata.irepeat==1){ //run 30 more times with small random force
           tordata.rfor = tordata.rfor2;
           tordata.adata[1] = 2; 
//          tordynbat(1,den1,geo,tordata,lastden,nbad);// "2" means use c term density as criteria for q;uiting
            tordynbat(20,den1,geo,tordata,lastden,nbad);// "20" means run 20 rounds of refinement
            tordata.rfor = origrfor;
    }
#endif
    aventermden(geo.usecb,den1,geo,geo.nend[0],geo.pos,lastden,nbad); // This lastden is pure density, no angle weighting ave nterm density 
    quitrefinec:;
    tordata.rfor = origrfor;
}
#endif
void extendcterm(phead,int nphipsi,
        float *prevden,float frden,int icheck,int ipowell,int ***set,
        int canfuse[2])
/*
New - 18oct00 - if meets another fit, check fusedist, and adds one more
  imet = 0 if have not met another fit
       =1  if just met another fit at last addition
       =2 if added another fit after met fit
  if fusefit>0 then the geo returned was already fused with the fit = newfit
     When enter routine - if have just met another fit, the imet = fit #
  Normally on entering extendcterm  - fusefit = 0
    This value is then used in the subsequent call to extendnterm
New - try both defaul and best angle, choose the best
New: 4mar99  - if end residue is bad, add another residue, run dynamics
      and then recheck this residue, if still bad, then quit
   Only quit if second to last residue is bad  (or end set is bad) (if last res. bad,
       add another, and see if still bad)
   Also, now checkset here rather then in checkres, if end is bad then quit
Add torsion dybnamics, just like in extendnterm
Revision - in powell, only use Cb (not Cb2)
  then after find best fit - add best CB2
NOTE:  avectermden does not include Cb2
  Add residue to C terminal end.
  nphipsi = 2  is number of variables adjuxt in powelmin 
  n0 = geo.nafit-1 is total # if residues in this peptide (geo) - last atom is Ca on residue
     n0+1
  1) Add residue with input phi/psi or type itype.
  2) If end atom of this residuew outside boundary, then set n0 = n0-1 and quit
     else - refine the phi/psi angles.  
     If refined value is outside the limits of allowed phi/psi for this
       itype (helix or sheet,
       then set n0 = n0-1 and quit
  3) Check ave density for last residue, if it is less than frden of aveden
      for previous residues (prevden), then set n0 = n0-1 and quit
     NOTE: For now prevden = density of two residues origionally fit with rigid
       refinement  - May be better to keep running average of prevden
  4) Continue adding until get condition for quiting
NOTE: icall is  now used to indicate whether or not to check set for contact
   with previously fit residue
  icheckset = 1, check set, icall = 0 do not check
  checkset = 0, check nterm end, =1 check cterm end; = -1 do not check
*/
{
   int i,n0,count,nbad,sside[NAFIT],rtype,checkset,prevbad;
   float lastden,phi,psi,beforeden;
   float maxphi;
   int onebad,nii[2],metfit,imet,ci,iend,nres;  //if = 1 indicates end was bad last time
   struct pepfit tfit;
   float maxdist,mindist,distn,distc;
int quittrace;

  onebad = 0;
  geo.trmetfit[1]=0;// = 1 if trace meets another fit - used as criteria for cutting end
   tfit.nalloc= -10; // initial default - indicates have not yet allocated   
   tfit.qual = -1100.0;
   allocatefit(tfit,NAFIT); // temporary fit used for fusion, etc.
   nii[0]=nii[1] = 0;
  if(icheck == 1)// check set for contack
    checkset= 1;  // indicates check c term end
  else
    checkset = -1; // do not check
// Add residue at C term end - refine phi/psi angle using Powell
  count =0;
// geo.fixend=0; // Default value - use entire geo, do not fix ends
   geo.fixend=2; // Fix N term end
   imet=0; 
while(1){ //  Use goto quitextendcterm to leave loop
   if(imet!=2){
     ci =checksetcterm(den1,geo,set,geo.nend[1]);
     if(ci<0){ // cterm met fit -ci - should meet nterm end
         if(verbose>=1)
            printf("Initial fit met fit %d at cterm end\n",-ci);
        geo.trmetfit[1]=1;// = 1 if trace meets another fit - used as criteria for cutting end
#if 0 // For debugging - look at this fit and quit
  if( -ci == 100){
        fitnum[0]= fitnum[0]+1; // add another fit
        fitnum[ fitnum[0] ] = 114;
        fit[ fitnum[0] ].nalloc = -10; // initial default - indicates have not yet allocated 
        copygeotofit(geo,fit[ fitnum[0] ],nii);
        savefit();
        exit(0);
  }
#endif
         iend = geo.nend[1];
         nres = fit[-ci].nres-1;
         distn = distv(geo.pos[iend][1],fit[-ci].pos[0][1]); // dist to nterm of fit i;
         distc = distv(geo.pos[iend][1],fit[-ci].pos[nres][1]); // dist to cterm of fit i;
         if(distc<distn){  // New - 12feb01 - just remove end if cterm meets cterm 
#if 0 // 15feb01 - no longer delete fit if meets wrong end - can remove good sheet direction
            if(distc< 2.0){
//            if(distc< 0.0){ // debug - do not use this condition
               if(verbose>=1)
                   printf(" BAD FIT because cterm end < 5 A from cterm end of fit %d\n",-ci);
               canfuse[0] = -100;
            }
            else{ // Just bad end, remove and quit
#endif
           if(verbose>=1)
                   printf(" BAD END because cterm met cterm end of fit %d (distc=%5.3f)\n",-ci,distc);
           geo.nafit = geo.nafit-1; // discard last 1 residue and quit
           geo.nend[1] = geo.nend[1]-1;
           geo.fixend = 0; // Run on all atoms
#if 0 //Try refining after cutting end -  Does not help
           if(tordata.adata[1]>2) //This restarts interactive tor dyn each time called   
               tordata.adata[1] = 2; 
printf("Refining after cut end\n");
           tordynbat(30,den1,geo,tordata,&lastden,&nbad);//  run quitcond rounds of refinement at use last value
#endif
//            }
            goto quitextendcterm;
         }
         else{ //cterm end met nterm  - check fusedist
            geo.trmetfit[1]=1;// = 1 if trace meets another fit - used as criteria for cutting end
            imet=1; // first contact
            metfit = -ci; // passed to extendfit
         }
      }//ci<0
   } // imet !=2
   if(imet>0){
        copygeotofit(geo,tfit,nii);
        fusedist(tfit,fit[metfit],&maxdist,&mindist); //cterm extension of tfit met fit ci 
printf("maxdist = %5.3f\n",maxdist);
        if(maxdist <  geo.maxfusedist){// good fused
              geo.trmetfit[1]=0;// if can fuse, assume end branch is OK
              printf(" Cterm end can be fused with fit %d\n",metfit);
//             fuseextfit3(den1,geo,tfit,fit[metfit],tfit); // fuses 2 fits and returns new fit = tfit
             canfuse[0] = metfit;
             canfuse[1]= geo.nend[1];
             canfuse[2]= imet; // if imet = 2 indicates added 1 residue after original contact
//             copyfittogeo(geo,tfit); // No longer used becaue do not fuse here
             goto quitextendcterm;
        }
        else{ // badfusedist
           if(imet==2){ // second addition 
              geo.nafit = geo.nafit-2; // discard last 2 residue and quit
              geo.nend[1] = geo.nend[1]-2;
              if(verbose>=1)
                 printf("Met cterm and could not fuse, disarding last 2 residues\n");
              goto quitextendcterm;
           } 
           else{ // imet =1
             imet =2;
           }
        }// badfusedist           
   } // imet>0
   count =count+1;
   n0 = geo.nend[1]; //Increase n0 by 1 Note geo.nafit=geo.nend[1] is equivalent to n0+1
   if(n0>NAFIT-2){
     fprintf(fpout," ERROR: n0>NAFIT-2 - quitting extendcterm\n");
     goto quitextendcterm;
   }
   copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],geo.pos,fpos);// save initial  geo.pos
   for(i=geo.nend[0]+1;i<geo.nend[1];i++) // save side data 
        sside[i] = geo.iside[i];
   maxphi = geo.phi[geo.itype];//Default best angle if do not use density for initial phi
   initialcphipsi(geo,den1,geo.itype,&maxphi);
#if 1 //Try both maxphi and standphi
float temppos[NAFIT][NAA][3],firstden,qual1,qual2;
int firstbad,quitref;
   if( fabs(geo.phi[geo.itype]-maxphi)> 20.0*PI/180.0){ // try both
      refinecend(geo,den1,n0,maxphi,geo.psi[geo.itype],&quitref,&nbad,&lastden);
      if(quitref==1){ // on boundary - remove last residue and quit
         goto quitextendcterm;
      }
      copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],geo.pos,temppos);// save refined pos
      firstden = lastden;
      firstbad = nbad;
      qual1= lastden - nbad*maidfile.denscale;
      geo.nend[1]= geo.nend[1]-1; // reset to value before refine
      geo.nafit = geo.nafit-1;
      copypos(geo.iside,geo.nend[1]-geo.nend[0]-1,geo.nend[0],
                   geo.nend[0],fpos,geo.pos);//Reduce geo.nend[1] by 1 since refinecend increase by 1 initial  geo.pos
      refinecend(geo,den1,n0,geo.phi[geo.itype],geo.psi[geo.itype],&quitref,&nbad,&lastden); // standard phi
if(verbose==2)
   printf(" firstden = %5.3f  firstbad = %d, secondden = %5.3f secondbad = %d\n",
        firstden,firstbad,lastden,nbad);
      if(quitref==1){ // on boundary - discard last residue and quit
         goto quitextendcterm;
      }
      qual2= lastden- nbad*maidfile.denscale;
      if(qual1>qual2){
         lastden=firstden;
         nbad=firstbad;
         copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],temppos,geo.pos);// Use first pos
      } // qual1>qual2
    }  // phi - maxphi >20
    else{ // just use geo.phi[geo.itype]
      refinecend(geo,den1,n0,geo.phi[geo.itype],geo.psi[geo.itype],&quitref,&nbad,&lastden); // standard phi
      if(quitref==1){ // on boundary
         goto quitextendcterm;
      }
    }
#endif      
    if(onebad==1){// indicates prevous residue was bad before last additon -check again
         avectermden(geo.usecb,den1,geo,geo.nend[1]-2,geo.pos,&beforeden,&prevbad); // ave cterm density 
         if(lastden>1.2*geo.extendden) // then increase beforeden by 1.3
            beforeden = 1.3*beforeden;
         rtype = geo.rtype[ geo.nend[1]-2 ];
         findphipsi(geo.pos,geo.nend[1]-3,&phi,&psi);
         if( 0==checkresidue(checkset,geo,den1,set,beforeden,prevbad,phi,psi,rtype) ){//set rtype = -1 so do not check angles
              geo.nafit = geo.nafit-2; // discard last 2 residue and quit
              geo.nend[1] = geo.nend[1]-2;
              for(i=geo.nend[0]+1;i<geo.nend[1];i++) // save side data 
                 geo.iside[i]=sside[i];
              copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],fpos,geo.pos);//prevous refined pos 
if(verbose>=2)
   fprintf(fpout, "Next to last residue is still bad,\n");
              goto quitextendcterm;
         }
         else{ // second to last residue is now OK
           onebad = 0;
if(verbose>=2)
   fprintf(fpout, "Next to last residue is now OK,\n");
         }
      }// onebad
if(verbose>=2)
  fprintf(fpout,"After tor. dyn:  lastden = %f  nbad = %d\n",lastden,nbad);
      rtype = geo.rtype[ geo.nend[1]-1 ];
      findphipsi(geo.pos,geo.nend[1]-2,&phi,&psi);
      if( 0==checkresidue(checkset,geo,den1,set,lastden,nbad,phi,psi,rtype) ){//set rtype = -1 so do not check angles
          onebad = 1; // indicates last residue is bad
if(verbose>=2)
   fprintf(fpout, "End residue is bad, setting onebad = 1\n");
      }
   if(geo.nend[1]>NAFIT-3 ){
fprintf(fpout,"QUITING CTERM EXTENSION BECAUSE FIT IS TOO LONG: geo.nend[1]=%d\n",geo.nend[1]);
       goto quitextendcterm;
   } 
}; // while
quitextendcterm:;
  fprintf(fpout," FINISHED EXTENDING C TERM: ends: %d %d\n",geo.nend[0],geo.nend[1]);
if(verbose >=1)
  findgeophipsi(geo);
   freepepfit(tfit);
}

void extendnterm(phead,int nphipsi,
        float *prevden,float frden,int icheck,int ipowell,int ***set,
        int canfuse[2])
/*
New: 4mar99  - if end residue is bad, add another residue, run dynamics
      and then recheck this residue, if still bad, then quit
   Only quit if second to last residue is bad  (or end set is bad) (if last res. bad,
       add another, and see if still bad)
   Also, now checkset here rather then in checkres, if end is bad then quit
New Verson - For Powell only use Cb, then add best Cb2
  aventermden does not include Cb2
Very similar to extendcterm
  Add residue to N terminal end.
  nphipsi = 2  is number of variables adjuxt in powelmin 
  n0 = geo.nafit-1 is total # if residues in this peptide (geo) - last atom is Ca on residue
     n0+1
  1) Add residue with input phi/psi or type itype.
  2) If end atom of this residuew outside boundary, then set n0 = n0-1 and quit
     else - refine the phi/psi angles.  
     If refined value is outside the limits of allowed phi/psi for this
       itype (helix or sheet,
       then set n0 = n0-1 and quit
  3) Check ave density for last residue, if it is less than frden of aveden
      for previous residues (prevden), then set n0 = n0-1 and quit
     NOTE: For now prevden = density of two residues origionally fit with rigid
       refinement  - May be better to keep running average of prevden
  4) Continue adding until get condition for quiting
  5) If get condition for quiting,
      Run a round of torsion dynamics and try again to extend
     Condition for running torsion dynamcics:
        trytor = 0  ( indicates has not been run yet during this extension)
        trytor = 1 and at least 2 new residues have been added since last dynamic run
            ((count - lastcount)>2)
  NEW VERSION:  For each addition, run tordyn if density bad
      using fixend = 1 (C term fixed) and default geo.endmove (=3)
     on the the most recent peptide (with bad end)
   If density still bad, then delete the bad end and quit
 Note: try either 1) angel constraints in tordyn
       or 2) not angle constaints but delete end if bad angle 
Note: ipowell is not used anymore-
  GENERAL PRINCIPLE:  DO REFINEMENT ALL THE TIME - DO NOT WORRY ABOUT CPU TIME      
if ipowell = 1, then do powell minimization at each step
NOTE: icall= icheck is  now used to indicate whether or not to check set for contact
   with previously fit residue
  icheck = 1, check set, icheck = 0 do not check
  checkset = 0, check nterm end, =1 check cterm end; = -1 do not check
1=ca,2=c,3=o;4=n,5=cb; 6=cb2
*/
{
   int i,n0,count,nbad,sside[NAFIT],rtype,checkset,prevbad;
   float lastden,phi,psi,beforeden,maxpsi;
   int onebad,nii[2],metfit,ni,imet,nres,iend;  //if = 1 indicates end was bad last time
   struct pepfit tfit;
   float maxdist,mindist,distc,distn;

  onebad = 0;
   geo.trmetfit[0]=0;// = 1 if trace meets another fit - used as criteria for cutting end
   tfit.nalloc= -10; // initial default - indicates have not yet allocated   
   tfit.qual = -1100.0;
   allocatefit(tfit,NAFIT); // temporary fit used for fusion, etc.
   nii[0]=nii[1] = 0;
  if(icheck == 1)// check set for contack
    checkset= 0;  // indicates check n term end
  else
    checkset = -1; // do not check
// Add residue at N term end - refine phi/psi angle using Powell
count =0;
geo.fixend=1; // =0:use entire geo, =1: fix C term end
// geo.fixend=0; // =0:use entire geo, =1: fix C term end
imet = 0;
while(1){ //  Use goto quitextendcterm to leave loop
   if(imet!=2){
      ni=checksetnterm(den1,geo,set,geo.nend[0]);
      if(ni<0){ // nterm met fit -ni - should meet cterm end
         if(verbose>=1)
            printf("Initial fit met fit %d at nterm end\n",-ni); 
         geo.trmetfit[0]=1;// = 1 if trace meets another fit - used as criteria for cutting end
         iend = geo.nend[0];
         nres = fit[-ni].nres-1;
         distn = distv(geo.pos[iend][1],fit[-ni].pos[0][1]); // dist to nterm of fit i;
         distc = distv(geo.pos[iend][1],fit[-ni].pos[nres][1]); // dist to cterm of fit i;
         if(distn<distc){ // 12feb01 - just remove end if nterm met nterm
#if 0
            if(distn< 5.0){
               if(verbose>=1)
                   printf(" BAD FIT because nterm end < 5 A from nterm end of fit %d\n",-ni);
               canfuse[0] = -100;
            }
            else{ // Just bad end, remove and quit
#endif
               if(verbose>=1)
                   printf(" BAD END because nterm met nterm end of fit %d (distn=%5.3f)\n",-ni,distn);
               geo.nafit = geo.nafit-1; // discard last 1 residue and quit
               geo.nend[0] = geo.nend[0]+1;
//            }
            goto quitextendnterm;
         }
         else{ //cterm end met nterm  - check fusedist
            geo.trmetfit[0]=1;// = 1 if trace meets another fit - used as criteria for cutting end
            imet = 1; // first contact
            metfit = -ni; // passed to extendfit
         }
       }
   } // imet!=2
   if(imet>0){
        copygeotofit(geo,tfit,nii);
        fusedist(fit[metfit],tfit,&maxdist,&mindist); //nterm extension of tfit met fit ni 
printf("maxdist = %5.3f\n",maxdist);
        if(maxdist <  geo.maxfusedist){// good fused
              printf(" Nterm end can be fused with fit %d\n",metfit);
//             fuseextfit3(den1,geo,fit[metfit],tfit,tfit); // fuses 2 fits and returns new fit = tfit
             geo.trmetfit[0]=0;// If can fuse, assume good end branch
             canfuse[0] = metfit;
             canfuse[1] = geo.nend[0];
             canfuse[2]= imet; // if imet = 2 indicates added 1 residue after original contact
//             copyfittogeo(geo,tfit);
             goto quitextendnterm;
        }
        else{ // badfusedist
           if(imet==2){ // second addition 
              geo.nafit = geo.nafit-2; // discard last 2 residue and quit
              geo.nend[0] = geo.nend[0]+2;
              if(verbose>=1)
                 printf("Met nterm and could not fuse, disarding last 2 residues\n");
              goto quitextendnterm;
           } 
           else{ // imet =1
             imet =2;
           }
        }// badfusedist           
   } // imet>0
   count =count+1;
   n0 = geo.nend[0]; //Increase n0 by 1 Note geo.nafit=geo.nend[1] is equivalent to n0+1
   if(n0<2){
     fprintf(fpout," ERROR: n0 <2  quitting extendnterm \n");
     goto quitextendnterm;
   }
   copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],geo.pos,fpos);// save initial  geo.pos
   for(i=geo.nend[0]+1;i<geo.nend[1];i++) // save side data 
        sside[i] = geo.iside[i];
   maxpsi = geo.psi[geo.itype];
   initialnphipsi(geo,den1,geo.itype,&maxpsi);

#if 1 //Try both maxpsi and standpsi
float temppos[NAFIT][NAA][3],firstden,qual1,qual2;
int firstbad,quitref;
   if( fabs(geo.psi[geo.itype]-maxpsi)> 20.0*PI/180.0){ // try both
      refinenend(geo,den1,n0,geo.phi[geo.itype],maxpsi,&quitref,&nbad,&lastden);
      if(quitref==1){ // on boundary - remove last end and quit
         goto quitextendnterm;
      }
      copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],geo.pos,temppos);// save refined pos
      firstden = lastden;
      firstbad = nbad;
      qual1= lastden - nbad*maidfile.denscale;
      geo.nend[0]= geo.nend[0]+1; // reset to value before refine
      geo.nafit = geo.nafit-1;
      copypos(geo.iside,geo.nend[1]-geo.nend[0]-1,geo.nend[0],
                   geo.nend[0],fpos,geo.pos);//Reduce geo.nend[1] by 1 since refinecend increase by 1 initial  geo.pos
      refinenend(geo,den1,n0,geo.phi[geo.itype],geo.psi[geo.itype],&quitref,&nbad,&lastden); // standard phi
if(verbose==2)
   printf(" firstden = %5.3f  firstbad = %d, secondden = %5.3f secondbad = %d\n",
        firstden,firstbad,lastden,nbad);
      if(quitref==1){ // on boundary - remove last end and quit
         goto quitextendnterm;
      }
      qual2= lastden- nbad*maidfile.denscale;
      if(qual1>qual2){
         lastden=firstden;
         nbad=firstbad;
         copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],temppos,geo.pos);// Use first pos
      } // qual1>qual2
    }  // phi - maxphi >20
    else{ // just use geo.phi[geo.itype]
      refinenend(geo,den1,n0,geo.phi[geo.itype],geo.psi[geo.itype],&quitref,&nbad,&lastden); // standard phi
      if(quitref==1){ // on boundary - remove last end and quit
         goto quitextendnterm;
      }
    }
#endif      
#if 0  // old version - just use maxpsi
float avecb2;  
float origrfor = tordata.rfor;
   makerevalanine2(geo,geo.pos,0,n0,geo.phi[geo.itype],maxpsi);
//fprintf(fpout,"Init C to Ca dist = %f\n",distv(geo.pos[n0-1][1],geo.pos[n0-1][2]) );
   if(0== checkboundary(den1,geo.pos,1,n0-1,geo.arange) ){ // then outside boundary - finished (last residue discarded because geo.nend[0] unchanged
       fprintf(fpout,"Quitting because outside boundary\n");
       goto quitextendnterm;
   }
     if(geo.nside ==2)
           bestcb1(den1,geo,geo.pos,n0,&avecb2);
     geo.nafit=geo.nafit+1; // use last added residue
     geo.nend[0] = geo.nend[0]-1;
     geo.rtype[ geo.nend[0] ] = geo.itype;
//   count = count -1;  // Do not use this last residue
     geo.iside[ geo.nend[0]+1 ] = 2; // Just arbitrary so that sidenum2 will find sidenjm
     if(tordata.adata[1]>2) //This restarts interactive tor dyn each time called   
            tordata.adata[1] = 2;   
     tordynbat(1,den1,geo,tordata,&lastden,&nbad);// "1" means use n term density as criteria for q;uiting
if(tordata.irepeat==1){ //run 20 more times with small random force
   tordata.rfor = tordata.rfor2;
   tordata.adata[1] = 2; 
//   tordynbat(1,den1,geo,tordata,&lastden,&nbad);// "2" means use c term density as criteria for q;uiting
   tordynbat(20,den1,geo,tordata,&lastden,&nbad);// "20" means run 20 rounds of refimement
   tordata.rfor = origrfor;
}
     aventermden(geo.usecb,den1,geo,geo.nend[0],geo.pos,&lastden,&nbad); // This lastden is pure density, no angle weighting ave nterm density 
#endif

     if(onebad==1){// indicates prevous residue was bad before last additon -check again
         aventermden(geo.usecb,den1,geo,geo.nend[0]+1,geo.pos,&beforeden,&prevbad); // This lastden is pure density, no angle weighting ave nterm density 
         if(lastden>1.2*geo.extendden) // then increase prevden by 1.3
            beforeden = 1.3*beforeden;
         rtype = geo.rtype[ geo.nend[0]+2 ];
         findphipsi(geo.pos,geo.nend[0]+1,&phi,&psi);
         if(0==checkresidue(checkset,geo,den1,set,beforeden,prevbad,phi,psi,rtype) ){//set rtype = -1 so do not check angles
               geo.nafit = geo.nafit-2; // discard last 2 residues and quit
               geo.nend[0] = geo.nend[0] +2;
               for(i=geo.nend[0]+1;i<geo.nend[1];i++) // save side data 
                 geo.iside[i]=sside[i];
               copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],fpos,geo.pos);//use original  geo.pos
if(verbose>=2)
   fprintf(fpout, "Next to last residue is still bad,\n");
               goto quitextendnterm;
//            }
         }
         else{ // second to last residue is now OK
           onebad = 0;
if(verbose>=2)
   fprintf(fpout, "Next to last residue is now OK,\n");
         }
      }// onebad
#if 0 // NOT used now - now check if can fuse
      ii=checksetnterm(den1,geo,set,geo.nend[0]);
      if(ii<=0){
if(verbose>=1)
            fprintf(fpout," QUITING BECAUSE NTERM END CLOSE TO SET %d\n",-ii);
            geo.nafit = geo.nafit-1; // discard last residue and quit
            geo.nend[0] = geo.nend[0] +1;
            for(i=geo.nend[0]+1;i<geo.nend[1];i++) // save side data 
                 geo.iside[i]=sside[i];
            copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],fpos,geo.pos);//use original  geo.pos
            goto quitextendnterm;
       }
#endif
if(verbose>=2)
  fprintf(fpout,"After tor. dyn:  lastden = %f nbad = %d\n",lastden,nbad);
       rtype = geo.rtype[ geo.nend[0]+1 ];
       findphipsi(geo.pos,geo.nend[0],&phi,&psi);
       if(0==checkresidue(checkset,geo,den1,set,lastden,nbad,phi,psi,rtype) ){//set rtype = -1 so do not check angles
          onebad = 1; // indicates last residue is bad
if(verbose>=2)
   fprintf(fpout, "End residue is bad, setting onebad = 1\n");
       }
   if(geo.nend[0]<2 ){
fprintf(fpout,"QUITING NTERM EXTENSION BECAUSE FIT IS TOO LONG: geo.nend[0]=%d\n",geo.nend[0]);
       goto quitextendnterm;
   } 
}; // while
quitextendnterm:;
#if 0  // debug - show last "bad" fit residue
   geo.nafit=geo.nafit+1; // OK to add residue
   geo.nend[0] = geo.nend[0]-1;
#endif
  fprintf(fpout," FINISHED EXTENDING N TERM  Ends: %d %d\n",geo.nend[0],geo.nend[1]);
if(verbose >=1) 
  findgeophipsi(geo);
  freepepfit(tfit);
}

float rigidfunc(float p[],phead)
 /* returns the average density as function of x,y,z,theta and phi
New version - also refine phi/psi
1) geo.pos (defined external) is the initial postion
2) translated and rotated postions are given by tpos.
     origphi is the position that is used for rigid translation
geo.nafit = n0+1;
3) NOW - also adjust phi - psi  Valid only for n0 = 2
// Translate ipos by p[1,2,3] and ridid rotate by p[4] p[5], adjust phi (p[6]) psi p[7]  
*/
{
    int n0;
    float ave,dist;

    n0 = geo.nafit-1;

   dist = sqrt(p[1]*p[1] + p[2]*p[2] + p[3]*p[3]); // lenght of tran step
   if(dist>3.0){
if(verbose>=2)
  fprintf(fpout,"DISTANCE LIMIT: dist > 3.0 in rigidfunc\n");
      itranlim = 0; // global variable
      return  -1000.0;
   }
   else 
      itranlim = 1;
   if(dist>geo.arange){ // then check boundary
      if( (0== checkboundary(den1,ipos,1,geo.nend[0],geo.arange)) ||
          (0== checkboundary(den1,geo.pos,1,geo.nend[1],geo.arange)) ){ // then outside boundary - finished
if(verbose>=1)
         fprintf(fpout,"Rigid fit outside boundary\n");
         itranlim =0;
         return  -1000.0;
     }
   }
   movepep(geo,ipos,fpos,n0,xaxis,zaxis,origphi,p);
#if 0
int i,j;
float x[3];
for(j=2;j<=n0;j++){
for(i=0;i<=2;i++)
  x[i] = fpos[j][1][i]-fpos[j][5][i];
dist= sqrt(dot(x,x));
if(dist>1.6)
  fprintf(fpout,"In rigid ERROR: j= %d   dist = %6.3f\n",
         j,dist);
} //j
#endif

//fprintf(fpout,"p= %5.3f %5.3f %5.3f %5.3f %5.3f %5.3f %5.3f\n",p[1],p[2],p[3],p[4],p[5],p[6],p[7] );
    aveden0(den1,geo,fpos,&ave); // Find average density (ave) for this orientation
    ave = -ave;  //change sign becuse want maximum value, but Powell finds minimum 
   return ave;
}

void bestcbn(struct griddata& den1,struct geometry& geo,
       float ipos[NAFIT][NAA][3],int icb,int iatom,float *avecbn)
/*
Similar to best cb1, except adds side chain atoms from cb3 (iatom = 3) on
Finds position of the # = ncb2 in peptide with maximal density
*/
{
   int i,k;
   float cbv[3],dist,ang,aden,maxden,delang; 
   float pos1[1][NAA][3],bestang;

     delang = 2.0*PI/geo.ncbang;
     addcbn(geo,ipos,icb,iatom);
     for(k=0;k<=2;k++)
        cbv[k]=ipos[icb][4+iatom-1][k]-ipos[icb][4+iatom-2][k];
     dist = sqrt( dot(cbv,cbv) );
     for(k=0;k<=2;k++)
        cbv[k] = cbv[k]/dist;
     maxden = -1000.0;
     for(i=0;i<geo.ncbang;i++){
       ang = i*delang;
       rotcbnew(geo,ipos,pos1,icb,cbv,ang,iatom);
       aden= aveatom(den1,geo,iatom+4,0,pos1);
//fprintf(fpout,"icb = %d ang = %f   aden = %f pos1[0]= %f cbv = %f\n",icb,ang,aden,pos1[0][6][0],cbv[icb][0]);
       if(aden>maxden){
         maxden = aden;
         bestang = ang;
       }
     }// i
     rotcb(geo,ipos,icb,cbv,bestang,iatom);// rotate to bestang
     *avecbn = maxden;
//fprintf(fpout," best CB2 angles (degrees) =  %f\n",bestang*180/PI);
}


void bestcb1(struct griddata& den1,struct geometry& geo,
       float ipos[NAFIT][NAA][3],int icb,float *avecb2)
/*Finds position of the # = ncb2 in peptide with maximal density
  Note returns  avecb2 = avecb2 (input) + maxden
*/
{
   int i,k;
   float cbv[3],dist,ang,aden,maxden,delang; 
   float pos1[1][NAA][3],bestang;

     delang = 2.0*PI/geo.ncbang;
     addcb2(geo,ipos,icb); /*add second carbon on sidechain*/
     for(k=0;k<=2;k++)
        cbv[k]=ipos[icb][5][k]-ipos[icb][1][k];
     dist = sqrt( dot(cbv,cbv) );
     for(k=0;k<=2;k++)
        cbv[k] = cbv[k]/dist;
     maxden = -1000.0;
     for(i=0;i<geo.ncbang;i++){
       ang = i*delang;
       rotcbnew(geo,ipos,pos1,icb,cbv,ang,2);
       aden= aveatom(den1,geo,6,0,pos1);
       if(aden< -900.0){ // if out of range for 1 angle - return bad value
           *avecb2 = -100.0;
           goto quitrout;
       }
//fprintf(fpout,"icb = %d ang = %f   aden = %f pos1[0]= %f cbv = %f\n",icb,ang,aden,pos1[0][6][0],cbv[icb][0]);
       if(aden>maxden){
         maxden = aden;
         bestang = ang;
       }
     }// i
     rotcb(geo,ipos,icb,cbv,bestang,2);// rotate to bestang
//     *avecb2 = *avecb2+maxden; //Old (pre 10feb99) - Must be error
     *avecb2 = maxden;
//  fprintf(fpout," best CB2 angles (degrees) =  %f\n",bestang*180/PI);
    quitrout:;
}

void bestcb(struct griddata& den1,struct geometry& geo,
       float ipos[NAFIT][NAA][3],int n0,float *avecb2)
/*
Forces all residues to have geo.nside side chain atoms
Finds position of all Cb2's in peptide with maximal density
*/
{
   int icb;
  
//   geo.nside = 2; Now set in bestden
   if(geo.nside==2){
     *avecb2 = 0.0;
     for(icb=2;icb<=n0;icb++){
        bestcb1(den1,geo,ipos,icb,avecb2);
        geo.iside[icb]=geo.nside;
     } // icb
     *avecb2 = *avecb2/(n0-1);
     if(verbose>=2)
        fprintf(fpout,"adding cb2: avecb2 = %f\n",*avecb2);
   }// geo.nside = 2
}

#if 1
void bestden(phead,float ang,float perpv[3],float u[3],int n0,int ica,
    float v[3],float *finalden,int *iboundary,float *aveco,
    int *nbad,float *avecb2,int useglob,float *qual,int resbad[])
/*
New (1oct98) comment out use of powellmin - just use tordyn
 Orients peptide in forward or reverse direction and
     finds maximum density
  u is the vector from Ca2 to pt1 (u1) or to pt 7 (u7)
  if u1, then orient in forward direction, if u7 then in reverse driection
  ica is the Ca that is origin of rotation in global and Powell
Note for this routine:  geo.nend[0] = 1, n0 = geo.nend[1]-geo.nend[0]
*/
{
   int i;
   float dist,nca[3],maxden;
   int usepowellmin = 0; // if = 1 then use powellmin, else just do tor. dyn.
   int usetordyn = 1; //debug if =1 then run tordyn
#if 1 // only needed if do powellmin
   float dist1,nc[3],lperpv[3];
#endif   

   geo.quit = 0;  // used as marker for point out of range in   aveatom  and findforden
   *iboundary =1; // indicates fit within boundary
   for(i=0;i<=2;i++) // vector from ca[1] to ca[end]
      nca[i] = fpos[n0+1][1][i]-fpos[1][1][i];
   dist = sqrt( dot(nca,nca) );
   for(i=0;i<=2;i++)
      nca[i] = nca[i]/dist;
   for(i=0;i<=2;i++){ // define xaxis, yaxis - used in Powell minimization
      xaxis[i] = perpv[i];
      zaxis[i] = nca[i];
   }
// Do rigid refinement - first global, then local using Powell
   if( (0== checkboundary(den1,fpos,1,geo.nend[0],geo.arange) )||
             (0== checkboundary(den1,fpos,1,geo.nend[1],geo.arange)) ){
if(verbose>=1)
        fprintf(fpout,"Quitting before globmin because Out of Boundary before globmin\n");
        itranlim =0;
        *finalden = -1000.0;
        goto quitbest;
   }
if(useglob==1){ //  use globmin
#if 1
     globmintran(den1,geo,fpos,n0,cafix,nca,perpv,geo.tstep,geo.thtot,geo.phitot,geo.trandel,
        geo.rotdel,pp); //fpos is original unchanged peptide find global minimum  - returns best translation, rotation data - geo.pos not changed
#endif
#if 0
     globmin(den1,geo,fpos,n0,cafix,nca,perpv,geo.tstep,geo.thtot,geo.phitot,geo.trandel,
        geo.rotdel,pp); //fpos is original unchanged peptide find global minimum  - returns best translation, rotation data - geo.pos not changed
#endif
   if(geo.quit==1){
       *finalden = -1000.0;
      fprintf(fpout," geo.quit = 1 after globmintran in bestden - do not use\n");
       goto quitbest;
   }
// Use best pp values to move fpos to  ipos = use as initial value to Powell Minimization
   for(i=0;i<=2;i++) // Origin of rotation vectors in Global min. - 
     origphi[i]=fpos[cafix][1][i];
   movepep(geo,fpos,ipos,n0,xaxis,zaxis,origphi,pp);
} // use globmin
else{ // if do not use globmin - just move fpos to ipos
   copypos(geo.iside,n0,1,1,fpos,ipos);
}
//goto quitbest;
if(useglob==1){
   aveden0(den1,geo,ipos,&maxden); // Find average density (ave) for initial orientation 
if(verbose>=2)
   fprintf(fpout," After globalmin   maxden = %f\n",maxden);
   if(maxden<0.1 ){ // If lousy density after global - do not bother to do Powell
      *finalden = maxden;
      goto quitbest;
   }
} // if useglob = 1
if(usepowellmin==1){  // use powellmin  and tordyn
   // Define new orig and axis for rotation
   for(i=0;i<=2;i++){ // vector from ca[1] to ca[end]
      nca[i] = ipos[n0+1][1][i]-ipos[1][1][i];
      nc[i] = perpv[i];  // Set nc = old perpv - use to find new perp vector
   }
   dist1 = sqrt( dot(nca,nca) );
   crossprod(nca,nc,lperpv);
   dist = sqrt( dot(lperpv,lperpv) );
   for(i=0;i<=2;i++){
      nca[i] = nca[i]/dist1;
      lperpv[i] = lperpv[i]/dist;
   }
   for(i=0;i<=2;i++){ // define xaxis, yaxis - used in Powell minimization
      xaxis[i] = lperpv[i];
      zaxis[i] = nca[i];
   }
   for(i=0;i<=2;i++)
     origphi[i]=ipos[1][1][i];
   powellmin(finalden,pfunc,rigidfunc); //(returns best pos = fpos; finalden is pointer Rigid refinemnent returns best tran, rot of ipos
   if(geo.quit==1){
       *finalden = -1000.0;
      fprintf(fpout," geo.quit = 1 after powellmin in bestden - do not use\n");
       goto quitbest;
   }
if(verbose>=2){
  for(i=1;i<=nvar;i++)
    fprintf(fpout," pp[%d]=%5.3f",i,pp[i]); 
  fprintf(fpout,"\n");
}  
   if(itranlim==0){
if(verbose>=1)
        fprintf(fpout,"Quitting because too large translation (set finalden = -1000\n");
        *finalden = -1000.0;
        goto quitbest;
   }
   geo.nside=2;
   bestcb(den1,geo,fpos,n0,avecb2);
   copypos(geo.iside,n0,1,1,fpos,geo.pos);
} // usepowellmin
else{// use if do not use powellmin
   geo.nside=2;
   bestcb(den1,geo,ipos,n0,avecb2);
   copypos(geo.iside,n0,1,1,ipos,geo.pos);
}
   geo.fixend=0; // Default value - use entire geo, do not fix ends
   for(i=geo.nend[0];i<=geo.nend[1];i++){ // set iside = nside  and rtypefor all residue
         geo.iside[i] = geo.nside;
         geo.rtype[i] = geo.itype;
   }
if(usetordyn==1){//debug  do not Run tortional dynamics
   float origrfor;
   origrfor = tordata.rfor;
   tordata.rfor = tordata.rfor3;
   if(tordata.adata[1]>2) //This restarts interactive tor dyn each time called   
      tordata.adata[1] = 2; 
   tordynbat(0,den1,geo,tordata,finalden,nbad);// "0" means use all atoms  density as criteria for q;uiting
   if(geo.quit==1){
       tordata.rfor = origrfor; // reset back to orig. value
       *finalden = -1000.0;
        fprintf(fpout," geo.quit = 1 after tordyn in bestden - do not use\n");
       goto quitbest;
   }
 //Always run some more times with small random force
   tordata.rfor = 0.0;
   if(tordata.adata[1]>2) //This restarts interactive tor dyn each time called   
      tordata.adata[1] = 2; 
   tordynbat(0,den1,geo,tordata,finalden,nbad);// "0" means use all atoms  density as criteria for q;uiting
   tordata.rfor = origrfor; // reset back to orig. value
   if(geo.quit==1){
       *finalden = -1000.0;
        fprintf(fpout," geo.quit = 1 after tordyn in bestden - do not use\n");
       goto quitbest;
   }
   copypos(geo.iside,n0,1,1,geo.pos,fpos);
} // use torsiondyn
else{ // debug  tordyn not used
   copypos(geo.iside,n0,1,1,geo.pos,fpos);
}
#if 1
    aveden0(den1,geo,fpos,finalden); // Find average density (ave) for this orientation               
if(verbose>=2)
  fprintf(fpout,"For aveden 0  finalden = %f\n",*finalden);
   aveden(den1,geo,fpos,finalden,avecb2,aveco,nbad,resbad); // Find average density (ave) for initial orientation 
   *qual = qualfunc(geo,*nbad,*finalden,geo.avecb);//
if(verbose>=1)
   fprintf(fpout," After refinement in bestden: qual = %5.3f finalden = %5.3f  avecb=%5.3f avecb2 = %5.3f aveco = %5.3f  nbad = %d \n",
        *qual,*finalden,geo.avecb,*avecb2,*aveco,*nbad);
#endif
quitbest:;              
}
#endif

void callbestcomp(phead,float ang,float perpv[3],float u[3],int n0,int ica,float v[3],
    float *topden,float *secondden,int *iboundary,float *aveco,
    int *nbad,int *btype, const char helsheet[],float *avecb2,int ***set,
    int resbad[],int checkdist,int canfuse[2][3])
/*
NEW 19oct00- returns canfuse[0][0,1]= fitmet number and geo.nend[1] for cterm extension
                     canfuse[1][0,1]= fitmet number and geo.nend[0] for nterm extension
NEW 23jun00 - if checkdist = 0 do not check  dist ends moved -
     This case is used if have good forward fit, want to make sure try
        backward fit.
   for idir = 1 (reverse
New (16feb99) do not count O bad after bestden
New:  14dec98 If fiting sheet:
    If Ca end moves too far (>geo.maxenddist) then use this as inciator that
       that bones is too curved for fitting sheet and quit fit in both directions
Note: secondden in no longer used
Modified from callbest 0 generate complete best fit extended in both directions
   Define best fit as follows:
      1) Fit with max = finalden + avecb2  
      2)   Must have nbad <= geo.nbadwhole (strong condition = 0)
             where nbad counts only internal main chain (not CO) atoms
      3) Return this best fit
      4) If no satisfactory fit, geo.nbad is left original value  (originally = -1) 
      5) Use geo.nbad as signal of fit:
           geo.nbad = -31;  indicates Ca end moved too far
           geo.nbad = -32;  indicates bad angle
           geo.nbad = -33   met wrong end or bad for other reasons
*/
{
    
   float finaldentor,finalden;
//   float qualboth,finaldenboth;
//   float spos[NAFIT][NAA][3];
   float tpos[NAFIT][NAA][3];
   int i,k,nbadtor,nbadtemp,ipowell;
//   int nbadboth;
   int icheck,useglob;
   float ca1[2][3],dist[2];
   float qualtor; 
//static int count=0;

//   count = count+1;
   icheck = 1;  // indicates check set for contacts
   for(i=0;i<=1;i++){ // store initial Ca end positions
      for(k=0;k<=2;k++)
         ca1[i][k]=fpos[geo.nend[i] ][1][k];
   }
//   useglob = 0;  // Just do tordyn in bestden
   useglob = 1;  // Use both glob tordyn in bestden
   copypos(geo.iside,n0,1,1,fpos,tpos);
//   qualboth = -100.0;
   qualtor= -100.0;  // set to bad values - reset if good value in bestden
   bestden(pfunc,ang,perpv,u,n0,ica,v,&finaldentor,iboundary,aveco,
           &nbadtor,avecb2,useglob,&qualtor,resbad); //NOTE: this sets geo.nide = 2; Return fpos = best positon Finds maxdensity for this orientation (use u1 for forward, u7 for reverse)   
//   nbadtemp = nbadtor; // do not use alternative bestden
   if(geo.obadn>0)//New (16feb99) allow 1 bad O here
      nbadtemp = nbadtor-1; 
   else
      nbadtemp = nbadtor;
   finalden = finaldentor;
#if 0 //if = 0  do no use both altenative bestden
   useglob = 1;  //  Do both global and tordyn in bestden
   geo.nside = 1; // must reset since set = 2 in bestden
   for(i=geo.nend[0];i<=geo.nend[1];i++)
      geo.iside[i] = geo.nside;
   copypos(geo.iside,n0,1,1,fpos,spos); 
   copypos(geo.iside,n0,1,1,tpos,fpos); 
   bestden(pfunc,ang,perpv,u,n0,ica,v,&finaldenboth,iboundary,aveco,
           &nbadboth,avecb2,useglob,&qualboth,resbad); //NOTE: this sets geo.nide = 2; Return fpos = best positon Finds maxdensity for this orientation (use u1 for forward, u7 for reverse)   
   if(verbose>=1)
       printf("qualtor = %f  qualboth = %f\n",qualtor,qualboth);
   if(qualtor>qualboth){ // then use spos
       copypos(geo.iside,n0,1,1,spos,fpos);
       nbadtemp =nbadtor;
       finalden = finaldentor; 
   }
   else{ //qualboth>qualtor
      nbadtemp = nbadboth;
      finalden = finaldenboth;
   }
#endif     
#if 0 // debug  SKIP rest
goto endcall;
#endif
//if(checkdist==1){ //NEW 16feb01 - now check alway check distance and for sheet discard both forward and bakc if mvoe too far Do not checkdist for reverse fit if good forward fit
   for(i=0;i<=1;i++){
      dist[i]=0.0;
      for(k=0;k<=2;k++)
        dist[i] = dist[i] + sqr(fpos[ geo.nend[i] ][1][k]-ca1[i][k]);
      dist[i] = sqrt(dist[i]);
   }// i
   if(verbose>=1)
      printf("Distance Ca ends moved during bestden = %5.3f %5.3f\n",dist[0],dist[1]);
   if(geo.itype ==2 ){ // If fitting sheet do not allow ends to move too far
     if( (dist[0]>geo.maxenddist) || (dist[1]>geo.maxenddist) ){ // If moves too far, assume bone is not alligned correctly
         geo.nbad = -31;
         goto endcall;
     }
   } // if sheet
//} // checkdist
#if 0 // Note - I do not think iboundary is used anymore
   if(iboundary ==0) // not in boundary - go to another point
      goto endcall;
#endif
if(verbose>=2)
  fprintf(fpout,"\n %s finalden = %6.3f nbad = %d  \n",
       helsheet,finalden,nbadtemp);
#if 0 //for debugging: quit after initial forward fit 
 copypos(geo.iside,n0,1,geo.nend[0],fpos,geo.pos);// copy temppos to geo.pos
 goto endcall;
#endif
#if 1 // check angles for initial fit - discard if 1 or 2 angles are bad
   float phi,psi,psimin,psimax,phimin,phimax;
    int ii,nbadang;
    nbadang=0;   
    for(ii=geo.nend[0];ii<=geo.nend[1]-2;ii++){
       findphipsi(geo.pos,ii,&phi,&psi);
       if(checkangrange(geo,phi,psi,geo.itype,&phimin,&phimax,&psimin,&psimax)==0){
          nbadang= nbadang+1;
if(verbose >=1)
            fprintf(fpout,"ANGLE ERR ii %d: PHI= %6.3f/PSI=%6.3f NOT IN RANGE (type = %d: %5.3f %5.3f %5.3f %5.3f)\n",
                ii,phi*180.0/PI,psi*180.0/PI,geo.rtype[i],phimin*180.0/PI,phimax*180.0/PI,psimin*180.0/PI,psimax*180.0/PI);
       }
    }
//    if(nbadang>=2){
    if(nbadang>=1){
       geo.nbad = -32; // Indicator in "testfit" of bad fit - set qualfor (in testfit)  to terrible value
//if(verbose >=1)
       fprintf(fpout," Quitting because 1 bad angles in initial fit\n");
       goto badang;
   }
#endif
   if( (finalden> geo.extendden)&&(nbadtemp <=geo.nbadwhole) ){ // then extend
      geo.nend[0] = NAFIT/2; // Place N terminal end at center so can at residue at Nterm
      geo.nend[1] = geo.nend[0]+n0;
      for(i=geo.nend[0]+1;i<geo.nend[1];i++) // set side for shifted geo 
        geo.iside[i]=geo.iside[i-geo.nend[0]+1];      
      copypos(geo.iside,n0,1,geo.nend[0],fpos,geo.pos);// copy temppos to geo.pos
      for(i=geo.nend[0];i<=geo.nend[1];i++)
         geo.rtype[i] = geo.itype;
      ipowell = 1;
      nvar = 2; //nvar is passed in pfunc,  Number of variables used in powell
      avectermden(geo.usecb,den1,geo,geo.nend[1]-1,geo.pos,&finalden,&geo.nbad); //1 = do use Cb ave cterm density 
printf("AFTER AVECTERM FINALDEN = %3.5f\n",finalden); 
      canfuse[0][0] =canfuse[1][0] = -1; // default - cannot fuse
      extendcterm(pfunc,nvar,&finalden,geo.frden,icheck,ipowell,set,canfuse[0]); // if fusefit>0 then fused fwith fitt # = fusefit
      if(canfuse[0][0]== -100){ // indicates met wrong end
          geo.nbad = -33;
          goto badang;
      }
      extendnterm(pfunc,nvar,&finalden,geo.frden,icheck,ipowell,set,canfuse[1]);
      if ( (geo.nend[1]-geo.nend[0])<3 ){//NEW 27aug01 Tru64 compiler crashes here if too short
          geo.nbad = -33;  // Too short
          goto badang;
      }
      if(canfuse[1][0]== -100){ // indicates met wrong end
          geo.nbad = -33;
          goto badang;
      }
   }
   else{ // did not extend, never copied fpos to geo.pos
      geo.nbad = -33; // Indicator in "testfit" of bad fit - set qualfor (in testfit)  to terrible value
   }
   badang:; 
   endcall:;
}


int testfit(struct griddata& den1,struct geometry& geo,
      float *aveco,float *lastden,float *avecb2,int *nbad,int resbad[])
/* 
  New - min helix lenght 1 more than min sheet length
returns 0 if bad fit, 1 if OK
Test if fit meets minimum stardard to be used:
 1) geo.nend[1]-geo.nend[0])>geo.savlen  (or was never extended)
 2) avecb2 >geo.minavecb2
 3) nbad < (geo.nend[1]-geo.nend[0])*geo.minfrbad;
 4) check angles, discard if 2 angles in row
*/
{
   int i,iangerr;
   float phi,psi;
   float psimin,psimax,phimin,phimax;
   float savlen;

   iangerr=1; // if = 0, indicates previous angle was bad
   if(geo.nbad <= -20){ // never extended - set qualfor to terrible value
if(verbose >=1)
  fprintf(fpout," Bad fit because never extended\n");
      return 0;
   }
   savlen = geo.savlen;
#if 0 // allow sheet to be 1 shorter
   if(geo.itype==2)
       savlen = geo.savlen-1;
   else
       savlen = geo.savlen;
#endif
#if 0 // allow helix to be 1 shorter
   if(geo.itype==1)
       savlen = geo.savlen-1;
   else
       savlen = geo.savlen;
#endif
   if ( (geo.nend[1]-geo.nend[0])<savlen ){
if(verbose >=1)
  fprintf(fpout," Bad fit because extended fit = %d not long enough\n",geo.nend[1]-geo.nend[0]);
      return 0;
   }
   for(i=geo.nend[0];i<=geo.nend[1]-2;i++){// length OK, check angles
       findphipsi(geo.pos,i,&phi,&psi);
       if(checkangrange(geo,phi,psi,geo.rtype[i],&phimin,&phimax,&psimin,&psimax)==0){// anglebad
if(verbose >=1)
            fprintf(fpout,"ANGLE ERR i %d: PHI= %6.3f/PSI=%6.3f NOT IN RANGE (type = %d: %5.3f %5.3f %5.3f %5.3f)\n",
                i,phi*180.0/PI,psi*180.0/PI,geo.rtype[i],phimin*180.0/PI,phimax*180.0/PI,psimin*180.0/PI,psimax*180.0/PI);
          if(iangerr == 0){ // previous angle also bad
if(verbose >=1)
    fprintf(fpout,"Bad fit because 2 bad angle in row\n");
             return 0;
          }
          else // set iangerr = 0
             iangerr=0;
       }// checkang
       else{  // angle OK, set iangerr = 1
          iangerr=1;
       }
   } // check angles
   aveden(den1,geo,geo.pos,lastden,avecb2,aveco,nbad,resbad); // Find average density (ave) for initial orientation 
#if 1  // 2 criteria for deleting helix
   if(geo.itype==1){// Add 2 new criteria for cutting helix - These routine Simply remove the bad fit - they do not cut out bad
        if(cadel(geo)==1){// NEW (17feb00) cut helix if bad Cai-1 to Cai+1 dist
            printf(" DELETING HELIX FIT BECAUSE BAD CA(i+1)--CA(i-1) dist\n");
             return 0;
        }
        if(ca_caang3(geo)==1){// Find angle between successive Ca-Ca vectors
            printf(" DELETING HELIX FIT BECAUSE BAD angle between successive Ca-Ca vectors\n");
             return 0;
        }
   }
#endif
#if 0 // Deletes short sheet if bad ratio of cbden to cb2den
   if( (geo.itype==2)&&((geo.nend[1]-geo.nend[0]) <= geo.savlen+2) ){ // if short sheet
         if(geo.avecb/(*avecb2)  < 0.8){ // delete fit if cb/cb2 den ratio is small
             if(verbose>=1)
                printf("Bad fit because  avecb/avecb2 == %5.3f< geo.savlen+2\n",geo.avecb/(*avecb2));
             return 0;
         }
   }
#endif      
#if 1
   if(geo.obadn==1)   // New, if only 1 bad CO, subtract from nbad
      *nbad = *nbad -1;
#endif
//   if( (*nbad +0.001)>= (geo.nend[1]-geo.nend[0]-1)*geo.minfrbad){

#if 0 // This was used up to 30may00
if(*nbad > geo.nbadend){
#endif
   if((float)*nbad/(geo.nend[1]-geo.nend[0]) > 0.2){
      if(verbose >=1){
        fprintf(fpout,"Bad fit because nbad too large:len=%d nbad=%d lastden= %5.3f avecb2=%5.3f\n",
          geo.nend[1]-geo.nend[0],*nbad,*lastden,*avecb2);
        for(i=geo.nend[0];i<geo.nend[1];i++)
          printf("resbad[%d] = %d\n",i,resbad[i]);
      }
      return 0;
   } // bad nbad

#if 1  //NEW use again 7jul00 - with frpoor = 0.39 for sheet -  OLD 30may00 Comment this out test if too many poor residues
   if( (geo.itype==2) && 
         ((float)geo.npoor >= geo.frpoor*(geo.nend[1]-geo.nend[0])) ){
      if(verbose >=1)
          fprintf(fpout," Bad sheet fit because npoor = %d >geo.frpoor*length = %5.3f is too big\n",
                     geo.npoor,geo.frpoor*(geo.nend[1]-geo.nend[0]));
      return 0;
   }     
#endif
#if 0 //Commented out 24aug00 - caused trouble for fah protein - NEW CRITERIA ADDED for sheet (7jul00) looks at ave O den relative Ca + N den
   if( (geo.itype==2) && 
       (2.0*geo.aveatom[3]/(geo.aveatom[1]+geo.aveatom[4]) > 1.1) ){
           if(verbose >=1)
              printf("BAD SHEET FIT because  coave/(ca + n ave) = %5.3f > 1.1\n",2.0*geo.aveatom[3]/(geo.aveatom[1]+geo.aveatom[4]));
           return 0;
    }
#endif
#if 1 // if = 0 debug
   if(geo.avecb<= geo.minavecb){
if(verbose >=1)
  fprintf(fpout," Bad fit because avecb = %5.3f too small\n",geo.avecb);
      return 0;
   }
fprintf(fpout," avecb2 = %5.3f\n",*avecb2);
   if(*avecb2<= geo.minavecb2){
if(verbose >=1)
  fprintf(fpout," Bad fit because avecb2 = %5.3f too small\n",*avecb2);
      return 0;
   }
//   if(*aveco<= 0.9*geo.minavecb2){
   if(*aveco<= 0.6*geo.minavecb2){
if(verbose >=1)
  fprintf(fpout," Bad fit because aveco = %5.3f too small\n",*aveco);
      return 0;
   }
#endif
   return 1;
}

void initialfit(struct griddata& den1,struct geometry& geo,struct point& pt,
     int nm,int *quittrace,struct pepfit fit[NFIT],int fitnum[NFIT],int ***set,struct bonedata& bone1)
/* New Version - find initial fit with Ca1 at pt 1 and Ca(n0+1) near pt nm
quittrace = 1  - quit each previous nexpt and then quit tracepep
quittrace = 2   -found bad fit on trace - quit each previous nexp and go to next branch point
quittrace = 3    pt on boundary   quit each previous nexp and go to next branch point 
quittrace = 4   -found good fit on trace -savefit  - quit each previous nexp and go to next branch point
  New procedure - May 27 - find complete fit using geo.nside = 2 (serine)
     as default for all residues.
    Then - go though this complete fit and adjust number of side chain atoms
      to optimal number
  Checks Forward, backward sheet and helix
    characterixed by  1) finalden (aveagede density); 2)nbad = # of atoms
      that have density < geo.minrigid;  and  3) avecb2 = aveage density
      at Cb2 atoms. Cb2 is added after best fit found - thus this is 
      an independent check.

  
   Define best fit as follows:
      1) First find fit with maximum avecb2.
      2) If nbad for this fit <= geo.nabwhole and finalden is = best
           or second best den, the  use it.  If not, there is no acceptable 
           fit.
      3) Return either this best fit, quittrace =1 (indicates no acceptable fit)

 New version:
      1) Make initial fit and find best fit using nside=1 (just Cb)
      2) Then - add run bestcb - this adds Cb2, rotates to find best fit
      3) Then choose fit that has some ave of best mainch density and best Cb2 density
         aveden  =    finalden + *avecb2
           where finalden is ave. mainch and avecb2 is ave cb2 -
        This places alot (too much?) weight on cb2.
       
Define  1=ca,2=c,3=o;4=n,5=cb; 6=cb2 in geo.pos[i]...
1. run maketestpep(geo,nres,..) make nres rsidues:
   geo.nend[0]=1;
   geo.nend[1]=nres+1;
   geo.nafit=geo.nend[1]-geo.nend[0]+1;
    ca (geo.pos[1,2,3,4][1][x,yu,z]
    c  geo.pos[1,2,3][2][x,yu,z]
    n   geo.pos[2,3,4][4][x,yu,z]
    0   geo.pos[1,2,3][3][x,yu,z]
    cb  geo.pos[2,3][5][x,yu,z]
    cb2  geo.pos[2,3][6][x,yu,z]
2. POsition nres sheet peptide as follows:
   a) Place Ca1 on pt[1]
   b) find: v = vector from ca1 to caend 
            u = vector from ca1 to pt[nm]
      define perpv =  v cross u
      ang = v dot u
      Rotate all atoms by ang about perpv.
3. For reverse direction, Place Ca1 on pt[nm]
     and rotate by -(PI-ang) about perpv.
4. Helix, step back from nm (nm-1,etc. = nmh) to find dist < helix +0.3;
    Then do same as sheet for helix alligned between pt 1 and pt nmh
*/   
{
   int i,n0,ica,cafix,nrigid,btype,iboundary,nvar;
   int nbadfor,nbadbak,nendsav[2],sside[NAFIT];
   float u[3],v[3],perpv[3],ang,dist,dist1,dist2,qualfor,qualbak;
   float xaxis[3],zaxis[3],origphi[3],origpsi[3];//Note origpsi is not used, just defined becaue pased in head
   float ipos[NAFIT][NAA][3],fpos[NAFIT][NAA][3],pp[NDIM];
   float spos[NAFIT][NAA][3],opos[5][NAA][3];
   float topden,secondden,avecb2,avecb2for,avecbfor,avecbbak,avecb2bak,avecofor,aveco,avecobak;
   float lastdenfor,lastdenbak;
   int icheckhelsh,resbadfor[NAFIT],resbadbak[NAFIT];
   int origsavlen;
   int testshortforward,testshortback;
   int forwardlen,backwardlen;
   float avenbak,avenfor;
   struct pepfit fit1,fit2; //These are not used but are needed in pfunc
   int checkdist,quitcond;
   float finallen,initlen;
   int canfuse[2][2][3],ifuse; // canfuse[0,1][][]= details about fusion for forward (0) and backward (1) directon
//static int count=0;

//count = count+1;
  avenfor= lastdenfor=lastdenbak=  -1000.0;
  avecb2=avecb2for=avecbfor = avecbbak = avecb2bak=avecofor=aveco=avecobak=avenbak= -1000.0;
  nendsav[0]=nendsav[1]=nbadfor=nbadbak= -1000;
  ifuse = -1; // if >0 then have fused and made new fit  = ifuse
  icheckhelsh =1; // if =1 then check sheet angles in checkextendfit()
//  icheckhelsh =0; // if =1 then check sheet angles in checkextendfit()
  nrigid = 6; // number of adjustable parameters for rigid minimization
// nrigid = 8; //(DOES NOT WORK WELL BECAUSE PERIODIC) Includes rotations of Cb2 about Cb1 (ONLY if geo.nside = 2)
   n0 = geo.nstartres; // initial number of residues =(Ca 1 to Ca n0+1)
   cafix = 1; //In global and powell - do rotations with ca1 at origin of rotation vector
   for(i=0;i<=2;i++)// stpos is used to positon residue in maketestpep
      geo.stpos[i] = pt.fpos[1][i];
   geo.nend[0] = 1; // this is passed to aveden, etc. so know # of residues in peptide
   geo.nend[1] = n0+1;
   geo.nafit = n0+1;
   nvar = nrigid; //nvar is passed in pfunc,  Number of variables used in powell

   topden = secondden =  -1000.0; // Set to terrible valuable
   geo.nside =1; // This sets number of side chains atoms in testpep
   maketestpep(geo,geo.pos,n0,geo.phi[geo.itype],geo.psi[geo.itype]); //Now sets geo.iside[]   make sheet witn Ca1 on geo.stpos = pt.fpos[1]
//goto finishrout;
   for(i=0;i<=2;i++){
      u[i] =  pt.fpos[nm][i] - geo.pos[1][1][i];// vector from Ca1 to point nm 
      v[i] =  geo.pos[n0+1][1][i] - geo.pos[1][1][i];// vector from Ca1 to Caend
   }
   crossprod(v,u,perpv);
   dist = sqrt( dot(perpv,perpv) );
   for(i=0;i<=2;i++)
      perpv[i] = perpv[i]/dist;
   dist1 = sqrt( dot(u,u) );   
   dist2 = sqrt( dot(v,v) );   
   ang = acos( dot(v,u)/(dist1*dist2) );
   trancapep(geo,geo.pos,n0,1,pt.fpos[1]); // translates Ca[1] to pt[1]  -- this should not be necessary since maketest already does it
   copypos(geo.iside,n0,geo.nend[0],1,geo.pos,opos);//(geo.nend[0] = 1) save this pos for making reverse peptide
   //Next step rotates with ica (=1) fixed to place Cend in forward or reverse direction
   rotcapepnew(geo,geo.pos,fpos,n0,perpv,geo.pos[1][1],ang); //Returns fpos:  rotate by ang about perpv  with ca1 fixed 
   ica =1; // the Ca that is placed pos[1] in bestden
   geo.nbad = 100;  //Initial value, if no satisfactory fits, then it remains at this value
   geo.avecb2 = -1000.0;
   checkdist =1;  // Forward direction, always check dist
   callbestcomp(pfunc,ang,perpv,u,n0,ica,v,&topden,&secondden,&iboundary,
      &aveco,&geo.nbad,&btype,"FORWARD",&avecb2,set,resbadfor,
      checkdist,canfuse[0]); //NOTE: this sets geo.nside = 2; 
   if( (geo.nbad == -31)||(geo.nbad == -32)||(geo.nbad == -33) ){ // could not extend or indicates fitting sheet and end moved too far or bad angle, quit this fit
      *quittrace = 2;
       qualfor = -1100.0;
       if(verbose>=1)
           fprintf(fpout, "Quitting forward trace because bad bestden\n");
       if( (geo.itype==2)&&(geo.nbad == -31) ){
          qualbak = -1100.0;
          if(verbose>=1)
             printf("Quitting this sheet fit because moved too far during forward fit\n");
          goto skipreverse;
       }
       goto tryreverse;
   }

   aveden(den1,geo,geo.pos,&lastdenfor,&avecb2for,&avecofor,&nbadfor,resbadfor); //Need to find resbad Find average density (ave) for initial orientation 
   avecbfor = geo.avecb; //avecb is global variable
//if( (pt.val[1]!=9174) || (pt.val[nm]!=12015) )
#if 1  //run dynamics on all residues (Probably should not run here because bad residues will influnece others
   geo.fixend = 0;
   quitcond = 30;
   float lastden,origrfor;
   int nbad;
   origrfor = tordata.rfor;
   tordata.rfor = 0;
   if(tordata.adata[1]>2) //This restarts interactive tor dyn each time called   
               tordata.adata[1] = 2; 
   tordynbat(quitcond,den1,geo,tordata,&lastden,&nbad);// "1" means use N term density as criteria for q;uiting
   tordata.rfor = origrfor;
   sidenum(0,den1,geo); //find optimal side num: "0 or 1 " delete(1) N or C term  side end if long side chain
#endif
//*quittrace= 1;
   testshortforward = testshortback = 0; // Defalult  this indicates do not test short backward fit 
   checkextendedfit(icheckhelsh,geo,den1,resbadfor,quittrace); // recheck (recursion)
   initlen = geo.nend[1]-geo.nend[0];
#if 0 // 16feb01 -- this is moved until after all cuts have been made
   if(*quittrace==2){ //Fit too short - save pos and number of residues to compare with backfit in specialcase
      qualfor = -1100.0; // default value
      forwardlen = geo.nend[1]-geo.nend[0]; 
      if( (forwardlen == geo.savlen-1) && (geo.rtype[ geo.nend[0]+1 ]==2) ){ // then refine and find quality inc case backkward get cut too short
          origsavlen = geo.savlen;
          geo.savlen = geo.savlen-1;
          refine(geo,den1,geo.savlen,quittrace); // must refine, because end was cut and not refined previous to this 
          if(testfit(den1,geo,&avecofor,&lastdenfor,&avecb2for,&nbadfor,resbadfor)==1){ // fit meets minimum standard
             qualfor = qualfunc(geo,nbadfor,lastdenfor,avecbfor);
             copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],geo.pos,spos);
             for(i=geo.nend[0]+1;i<geo.nend[1];i++) // save side data 
                sside[i] = geo.iside[i];
             nendsav[0]=geo.nend[0];
             nendsav[1]=geo.nend[1];
             testshortforward =1; // this means have the potential to test short forward if need to
          } // testfit OK
          geo.savlen = origsavlen;
       }// if may use later
   }
   else{ // quittrace!=2   //NOTE geo.savlen is set on lower in next to tests
#endif
   if(*quittrace==2){
       qualfor = -1100.0; // default value
   }
   else{ // quittrace !=2
     origsavlen = geo.savlen;
     geo.savlen = geo.savlen-1;
     checkoneenden(den1,geo,quittrace);// New recursive funtion calls once - allows end to bereduced one belows savlen
     if(*quittrace==2){ //Bad fit
       qualfor = -1100.0; // default value
     }
     else{// quittrace!=2
       checkoneendbranch(den1,geo,bone1,quittrace);
       if(*quittrace==2){ //Bad fit
          qualfor = -1100.0; // default value
       }
       else {  //*quittrace!=2 indicates checkextendefit found an OK fit
         bonedistgeo(den1,geo,bone1,quittrace);
         if(geo.frcon<0.999)
            bonedistgeo2(den1,geo,bone1,quittrace);
         if(*quittrace==2){ //Bad fit
          qualfor = -1100.0; // default value
         }
         else if(testfit(den1,geo,&avecofor,&lastdenfor,&avecb2for,&nbadfor,resbadfor)==1){ // fit meets minimum standard
            qualfor = qualfunc(geo,nbadfor,lastdenfor,avecbfor);
            avenfor = geo.aveatom[4]; // Ave N density
            copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],geo.pos,spos);
            for(i=geo.nend[0]+1;i<geo.nend[1];i++) // save side data 
              sside[i] = geo.iside[i];
            nendsav[0]=geo.nend[0];
            nendsav[1]=geo.nend[1];
            forwardlen = geo.nend[1]-geo.nend[0];
            if(forwardlen == geo.savlen)// if at minimum (= orig. geo.savlen-1) need to test bad short back
               testshortback =1;
         } //testfit
         else {// bad testfit
           qualfor = -1100.0;
         }
       } // quitrase !=2
     } // quitrase !=2
     geo.savlen=origsavlen;
   }// quitrace!=2
   finallen = geo.nend[1]-geo.nend[0];
   if( (*quittrace!=2)&&(finallen!=initlen) ){ // NEW 16oct00 - call checkextfitagain
        checkextendedfit(icheckhelsh,geo,den1,resbadfor,quittrace); // recheck (recursion)
   }
#if 1 // 16feb01 -- check after after all cuts have been made
   forwardlen = geo.nend[1]-geo.nend[0];  // NOTE - allow 1 less than geo.savlen above - thus use savlen-2 below
   if( (forwardlen == geo.savlen-2) && (geo.rtype[ geo.nend[0]+1 ]==2) ){ // then refine and find quality inc case backkward get cut too short
          qualfor = -1100.0; // default value
          origsavlen = geo.savlen;
          geo.savlen = geo.savlen-2;
          refine(geo,den1,geo.savlen,quittrace); // must refine, because end was cut and not refined previous to this 
          if(testfit(den1,geo,&avecofor,&lastdenfor,&avecb2for,&nbadfor,resbadfor)==1){ // fit meets minimum standard
             qualfor = qualfunc(geo,nbadfor,lastdenfor,avecbfor);
             copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],geo.pos,spos);
             for(i=geo.nend[0]+1;i<geo.nend[1];i++) // save side data 
                sside[i] = geo.iside[i];
             nendsav[0]=geo.nend[0];
             nendsav[1]=geo.nend[1];
             testshortforward =1; // this means have the potential to test short forward if need to
          } // testfit OK
          geo.savlen = origsavlen;
   }
#endif
//goto finishrout;  // quit and use this fit
#if 0
idebug=1; // This will skip reverse
if(idebug == 1){
  qualbak = -100;
  fprintf(fpout," SKIPPING REVERSE/n");
  goto skipreverse;
}
#endif
// REVERSE DIRECTION
tryreverse:;
if(verbose>=1)
  fprintf(fpout,"STARTING BACKWARD FIT\n");
   geo.nend[0] = 1; // this is passed to aveden, etc. so know # of residues in peptide
   geo.nend[1] = n0+1;
   geo.nafit = n0+1;
   geo.nside = 1; //   do not use Cb2 until call bestcb
   for(i=2;i<=n0;i++)
       geo.iside[i]= geo.nside;
   copypos(geo.iside,n0,1,geo.nend[0],opos,geo.pos);// save this pos for making reverse peptide
   trancapep(geo,geo.pos,n0,1,pt.fpos[nm]); // translates Ca[1] to pt[nm]
   ang = -(PI - ang);
   //Next step rotates with ica (=1) fixed to place Cend in forward or reverse direction
   rotcapepnew(geo,geo.pos,fpos,n0,perpv,geo.pos[1][1],ang); //Returns fpos:  rotate by ang about perpv  with ca1 fixed
   if(qualfor>0) // If good forward fit, do not check dist ends moved so that alwys get fit to compare
      checkdist = 0;
   else
      checkdist = 1;
   callbestcomp(pfunc,ang,perpv,u,n0,ica,v,&topden,&secondden,&iboundary,
      &aveco,&geo.nbad,&btype,"BACKWARD",&avecb2,set,resbadbak,
      checkdist,canfuse[1]);
   if( (geo.nbad == -31)||(geo.nbad == -32)||(geo.nbad == -33) ){ //could not extend or  indicates fitting sheet and end moved too far, quit this fit
      *quittrace = 2;
       qualbak = -1100.0;
       if(verbose>=1)
          fprintf(fpout, "Quitting backward trace because bad bestden\n");
       if( (geo.itype==2)&&(geo.nbad == -31) ){
          if(verbose>=1)
            printf("SHEET  MOVED TOO FAR FOR BACKWARD FIT SETTING BOTH  qualbak and qualfor  = -1100\n");
          qualfor = -1100.0;
       } 
       goto skipreverse;
   }
   aveden(den1,geo,geo.pos,&lastdenbak,&avecb2bak,&avecobak,&nbadbak,resbadbak); // Find average density (ave) for initial orientation 
   avecbbak = geo.avecb;
#if 1  //run dynamics on all residues
   geo.fixend = 0;
   quitcond = 30;
   origrfor = tordata.rfor;
   tordata.rfor = 0;
   if(tordata.adata[1]>2) //This restarts interactive tor dyn each time called   
               tordata.adata[1] = 2; 
   tordynbat(quitcond,den1,geo,tordata,&lastden,&nbad);// "1" means use N term density as criteria for q;uiting
   tordata.rfor = origrfor;
   sidenum(0,den1,geo); //find optimal side num: "0 or 1 " delete(1) N or C term  side end if long side chain
#endif
//*quittrace= 1;
#if 1 // do not check
   checkextendedfit(icheckhelsh,geo,den1,resbadbak,quittrace); // recheck (recursion)
#endif
   initlen = geo.nend[1]-geo.nend[0];
#if 0 // 16feb01 - moved to point after all cuts have been made
   if(*quittrace==2){ // if bad, will want to compare forward and backward if forward get ends cut too short
     qualbak = -1100.0; // default value
     backwardlen = geo.nend[1]-geo.nend[0];
     if( (testshortback==1)&&  (geo.rtype[ geo.nend[0]+1 ]==2) ){ // then refine and find quality inc case backkward get cut too short
          origsavlen = geo.savlen;
          geo.savlen = geo.savlen-2;
          refine(geo,den1,geo.savlen,quittrace); // quitrace is pointer
          if(testfit(den1,geo,&avecobak,&lastdenbak,&avecb2bak,&nbadbak,resbadbak)==1){ // fit meets minimum standard
             qualbak = qualfunc(geo,nbadbak,lastdenbak,avecbbak);
             if(qualbak>= qualfor){ // do not use short forward 
                printf(" Not using short foward fit because bad shortbackward had better qual\n");
                qualbak = qualfor = -1100.0;
             }
             else // set qualbak bad to bad value
                qualbak = -1100.0;
          }
          geo.savlen = origsavlen;
     } // if (back..
   } // quittrace = 2
   else { //if(*quittrace!=2) indicates checkextendefit found a good fit
#endif
   if(*quittrace==2){
       qualbak = -1100.0; // default value
   }
   else{ //if(*quittrace!=2)
     origsavlen = geo.savlen;
     geo.savlen = geo.savlen-1;
     checkoneenden(den1,geo,quittrace);// only calls once - allows end to bereduced one belows savlen
     if(*quittrace==2){ //Bad fit
       qualbak = -1100.0; // default value
     }
     else{// quittrace!=2
       checkoneendbranch(den1,geo,bone1,quittrace);
       if(*quittrace==2){ //Bad fit
          qualbak = -1100.0; // default value
       }
       else {  //*quittrace!=2 indicates checkextendefit found an OK fit
         bonedistgeo(den1,geo,bone1,quittrace);
         if(geo.frcon<0.999)
             bonedistgeo2(den1,geo,bone1,quittrace);
         if(*quittrace==2){ //Bad fit
          qualbak = -1100.0; // default value
         }
         else if(testfit(den1,geo,&avecobak,&lastdenbak,&avecb2bak,&nbadbak,resbadbak)==1){ // fit meets minimum standard
            qualbak = qualfunc(geo,nbadbak,lastdenbak,avecbbak);
            backwardlen = geo.nend[1]-geo.nend[0]; 
            avenbak = geo.aveatom[4]; // Ave N density
            if( (backwardlen ==geo.savlen)&&(testshortforward==1) ){ // If back OK then do not use short forward
                if(qualfor > 0.95*qualbak){ // Do not use back if close to short forward
                   printf(" Not using short back fit because bad shortforward had better qual\n");
                   qualbak = qualfor = -1100.0;
                }
            }
            finallen = geo.nend[1]-geo.nend[0];
            if( (*quittrace!=2)&&(finallen!=initlen) ){ // NEW 16oct00 - call checkextfitagain
                 checkextendedfit(icheckhelsh,geo,den1,resbadfor,quittrace); // recheck (recursion)
                if(*quittrace==2)
                   qualbak = -1100.0;
            }        
         } // testfit
         else
            qualbak = -1100.0;
       } // quitrase !=2
     } // quitrase !=2
     geo.savlen=origsavlen;
   }// quitrace!=2
   backwardlen = geo.nend[1]-geo.nend[0];
   if(backwardlen == geo.savlen-2){// NOTE - allow 1 less than geo.savlen above - thus use savlen-2 below
     qualbak = -1100.0; // default value      
     if( (testshortback==1)&& (geo.rtype[ geo.nend[0]+1 ]==2)&&
            (testshortforward!=1) ){ // then refine and find quality inc case backkward get cut too short
          origsavlen = geo.savlen;
          geo.savlen = geo.savlen-2;
          refine(geo,den1,geo.savlen,quittrace); // quitrace is pointer
          if(testfit(den1,geo,&avecobak,&lastdenbak,&avecb2bak,&nbadbak,resbadbak)==1){ // fit meets minimum standard
             qualbak = qualfunc(geo,nbadbak,lastdenbak,avecbbak);
             if(qualbak>=  0.95*qualfor){ // do not use backward if close to short back
                printf(" Not using short foward fit because bad shortbackward had better qual\n");
                qualbak = qualfor = -1100.0;
             }
             else // set qualbak bad to bad value
                qualbak = -1100.0;
          }
          geo.savlen = origsavlen;
     }//if testshort etc.
   } // if back
skipreverse:;
   if(testshortforward==1) // this means that fit is too short short but found a qualfor to use for comparison to qualbak
       qualfor = -1100.0;

   if(geo.itype==2){ // for sheet = add co and n den to qual:
        if(qualfor> -900.0)
           qualfor = qualfor + avenfor + avecofor;
        if(qualbak> -900.0)
           qualbak = qualbak + avenbak+ avecobak;
   }
   if(verbose>=1){
       fprintf(fpout," After forward refinement: qualfor = %5.3f #residue = %d lastdenfor = %6.3f avenfor=%5.3f avecbfor= %6.3f  avecb2for = %6.3f avecofor=%6.3f  nbadfor = %d\n",
               qualfor,nendsav[1]-nendsav[0]-1,lastdenfor,avenfor,avecbfor,avecb2for,avecofor,nbadfor);
       fprintf(fpout," After backward refinement: qualbak = %5.3f  #residue = %d lastdenbak = %6.3f avenbak=%5.3f avecbbak=%6.3f avecb2bak = %6.3f avecobak=%6.3f   nbadbak = %d\n",
               qualbak, geo.nend[1]-geo.nend[0]-1,lastdenbak,avenbak,avecbbak,avecb2bak,avecobak,nbadbak);
    }
#if 0 // debug - force bakfit to be best fit
qualfor = -1000; 
#endif 
  forwardlen = nendsav[1]-nendsav[0]-1;
  backwardlen = geo.nend[1]-geo.nend[0]-1;

#if 0 // 16feb01 - New for sheet - always add o and n den to qual to determine best direction     
  if(geo.itype==2){//For sheet 0  if quality nearly identical, pick based on length and best Co density
      if( (qualfor>0.0)&&(qualbak>0.0) ){
        if( fabs(qualfor - qualbak)/( (qualfor+qualbak)/2.0) < 0.1 ){// then use whatever direction has best coden
#if 0 // Old 
          if(forewardlen>backwardlen){
             if(verbose>=1)
                 fprintf(fpout,"SHEET: qual nearly identical - picking direction with most residues\n");
             qualbak = -100.0;
          }
          else if(forwardlen<backwardlen){
             if(verbose>=1)
                 fprintf(fpout,"SHEET: qual nearly identical - picking direction with most residues\n");
              qualfor = -100.0;
          }
          else{ //Same length, pick the one with best aveco
             if(verbose>=1)
                fprintf(fpout,"SHEET: qual nearly identical - picking direction with bestqual+ aveco\n");
             if((qualfor+avecofor) > (qualbak+avecobak) )
                 qualbak = -100.0;
             else
                 qualfor = -100.0;
          } // same length
#endif
#if 1 // New - after 1feb00 -  alway pick the fit with best (O + N) cen
          if(verbose>=1)
                 fprintf(fpout,"SHEET: qual nearly identical - picking direction with best (aveO + aneN) density\n");
          if( (avenfor + avecofor) > (avenbak+ avecobak) )
             qualbak = -100.0;
          else 
             qualfor = -100.0;
#endif
       } // qual within 10% of each other
     } // both qual >0
  } // sheet
#endif

  if( (qualfor < -1000.0)&&(qualbak < -1000.0) ){ // bad fit in both directions
        *quittrace = 2; // found bad fit
fprintf(fpout," Quit because could not extend fit in either direction\n");
   }
   else if(qualfor >=qualbak){// used saved forward fpos
fprintf(fpout," Best fit in forward direction: qualfor = %5.3f #residue = %d lastdenfor = %6.3f avecbfor= %6.3f avecb2for = %6.3f avecofor = %6.3f nbadfor = %d\n",
         qualfor,nendsav[1]-nendsav[0]-1,lastdenfor,avecbfor,avecb2for,avecofor,nbadfor);  
         geo.nend[0]=nendsav[0];
         geo.nend[1]= nendsav[1];
         for(i=geo.nend[0]+1;i<geo.nend[1];i++) // used saved side data
                 geo.iside[i]=sside[i];
         copypos(geo.iside,geo.nend[1]-geo.nend[0],geo.nend[0],geo.nend[0],spos,geo.pos);
         sidenum(0,den1,geo); //find optimal side num: "0 or 1 " delete(1) N or C term  side end if long side chain
         *quittrace = 4; // indicates found good fit, save in routine tracepts()
         checkfuse(den1,geo,canfuse[0],&ifuse); //canfuse[0] = forward fit array - check if met another fit and can still fuse - return ifuse = the few fit
   } // qualfor > qualbak
   else{ // qual bak better  -use the last fit
fprintf(fpout," Best fit in backward direction (nend[1]=%d): qualbak = %5.3f  #residue = %d lastdenbak = %6.3f avecbbak= %6.3f  avecb2bak = %6.3f  avecobak = %6.3f nbadbak = %d\n",
        geo.nend[1],qualbak, geo.nend[1]-geo.nend[0]-1,lastdenbak,avecbbak,avecb2bak,avecobak,nbadbak);       
         sidenum(0,den1,geo); //find optimal side num "0 or 1 " delete(1) N or C term  side end if long side chain
         *quittrace = 4; // found good point -  Go to next 3 branch pt
         checkfuse(den1,geo,canfuse[1],&ifuse); // check if met another fit and can still fuse - return ifuse = the few fit
         for(i=geo.nend[0];i<=geo.nend[1];i++){ // Set resbadfor = which ever is best direction
              resbadfor[i]=resbadbak[i];
        }
   } // qualbak > qualfor
   if(ifuse>0){// if fused and returned new fit = ifuse
       fit[ifuse].val1 = pt.val[1];
       fit[ifuse].val2 = 99999;  // Use this as indicator that is a fused fit
       geo.setval = -ifuse; 
       setptsfit(den1,geo,fit[ifuse],geo.set,2); //NOTE: New def. sideside - setside -=1 means set 2 pts  set points for fit
       *quittrace = 20; // indicates fused and already formed fit
   }     
   finishrout:;
  quitrout:;
}      


void  findcurverad(struct point pt,int ni,float *radius,float *torsion)
/*  Find curvature and torsion of a curve - 
  points run from  i=1,2,...ni  with position pt.fpos[i]
  Define vectors:
         vec[i] = pos[i+1] - pos[i] = vector from pt i to i+1; i=1,ni-1;
         tang[i] = (vec[i-1]+vec[i])/2   = tangent at point i;  i = 2,ni-1
         dtang[i] = (tang[i+1]-tang[i])/dist[i] = dT/ds; i=2,ni-2;
           = derivative of tangent  = corresponds to point midway between i and i+1.
         where dist[i] = mag(vec[i]);
   Then:  curvature = mag(dtang);  radius of curv = 1/curvature
     and pricipal normal = norm[i] = dtang[i]/curv
   For torsion:
       define tave[i] = (tang[i]+tang[i+1)/2.0 = vector at point between i and i+1,(i=2,ni-2)
       b[i] = tave[i] X norm[i]    i=2,ni-2
       db[i] = (b[i+1-b[i])/avedist[i]  i=2; .. ni-3
         where avedist[i] = (dist[i]+dist[i+1])/2.0
   Now, db[i] should paralel to norm[i]  - Actually  to avenorm = (norm[i]+norm[i+1])/2
      and magniture of torsion = mag(db) and sign of torsion
        = + if db and avenorm in opposite directions
        = - if db and avenorm in same direction
*/
{
   int i,k;
   float mag,dist[30],curv[30],vec[30][3],tang[30][3],dtang[30][3];
   float ang,tave[30][3],b[30][3],db[30][3],norm[30][3],avedist,tor[30];

   for(i=1;i<=ni-1;i++){
     for(k=0;k<3;k++)
       vec[i][k] = pt.fpos[i+1][k]-pt.fpos[i][k];
     dist[i] = sqrt( dot(vec[i],vec[i]) );
     for(k=0;k<3;k++)
       vec[i][k] = vec[i][k]/dist[i];
   }
   for(i=2;i<=ni-1;i++){
     for(k=0;k<3;k++)
       tang[i][k]=(vec[i-1][k]+vec[i][k])/2.0;
     mag = sqrt( dot(tang[i],tang[i]) );
     for(k=0;k<3;k++)
       tang[i][k]=tang[i][k]/mag;
   }
   for(i=2;i<=ni-2;i++){
     for(k=0;k<3;k++){
       dtang[i][k]=(tang[i+1][k]-tang[i][k])/dist[i];
       tave[i][k] = (tang[i][k]+tang[i+1][k])/2.0;
     }
     mag = sqrt( dot(tave[i],tave[i]) );
     for(k=0;k<3;k++)
       tave[i][k]=tave[i][k]/mag;
     curv[i] = sqrt( dot(dtang[i],dtang[i]) );
printf(" curv[%d] = %5.3f\n",i,curv[i]);
     for(k=0;k<3;k++)
       norm[i][k]=dtang[i][k]/curv[i];
     crossprod(tave[i],norm[i],b[i]);      
   } // i
   for(i=2;i<=ni-3;i++){// find torsion
     avedist = (dist[i]+dist[i+1])/2.0;
     for(k=0;k<3;k++)
       db[i][k] = (b[i+1][k]-b[i][k])/avedist;
     tor[i] = sqrt( dot(db[i],db[i]) );
     for(k=0;k<3;k++)
        db[i][k] = db[i][k]/tor[i];
     ang = acos(  dot(db[i],norm[i]) );
     if(ang < PI/2.0) // db and norm in same directon
        tor[i] = -tor[i];
     else  // db and nor in opposite directon
        tor[i] = tor[i];
printf(" ang[%d] = %5.3f   tor = %5.3f\n",i,ang,tor[i]);    
   }       
}   


void nextpt(struct griddata& den1,struct geometry& geo,
      struct bonedata& bone1,struct point pt,int ppt,int nm,int nii[2],int ***set,
     int *quittrace,float curdist,struct pepfit fit[NFIT],
     int fitnum[NFIT],int *testpt)
/* Recursive function
New - 26apr99 - add variable testpt - used to keep for checking
   for helix along same set of bonepts
NOTE: IMPORTANT:  KEEP TRPTS SMALL (=20) SINCE IF GETS BIGGER THEN THIS
   BEGIN TO HAVE LARGE LOOPS THAT SCREW THINGS UP
   STILL MAY BE A PROBLEM IF LOOP < 17 (TRPT=3) PTS.
On  10dec98 - modified - needed for fitting sheets
  The old version efined quittrace as follows:
quittrace = 0  - go to next point in chain
NOTE: I think quittrace 1 and 4   and quitrace 2 and 3 have identical effects
quittrace = 1  - quit each previous nexpt and then quit tracepep
quittrace = 2   -found bad fit on trace - quit each previous nexp and go to next branch point
quittrace = 3    pt on boundary   quit each previous nexp and go to next branch point 
quittrace = 4   -found good fit on trace -savefit  - quit each previous nexp and go to next branch point
NOTE: For quittace = 2,3,4 It jumps to completely new branch point 
  However, actually, should continue on same chain, just go back next previous branch pt
    Do this by  by resetting quittrace = 0 if it equal 2 or 3, when entering previous nextpt

 nm = number of this point in the list (ie 1,2,3 ...)
 ni = nm+1 is number of next point passed to routine nextpoint
 ppt = pt.number (i.e. 4350) of the previous point
         used to keep from going backward
 ipt = pt. number of this pt. - passed to nextpt as = previou point = ppt
Note: nm and ppt are passed when enter nextpt and are
   local to this routine, changing value in other nextpt routines
    down the list do not affect 
  structure previous prev  should be only locally defined
*/
{ 
  int i,icon,npt,ivec[3],ipt,ni,iset;
  float stdist,prevstdist;
  int jj; // used in new test for helix

if(writelog==1){// Then close and reopen fpout so will update logfile
  fclose(fpout);
  if( (fpout=fopen("maid.log","a")) == NULL){
         fprintf(fpout,"ERROR:  file %s cannot be found\n","maid.log");
         exit(0);
  }
}
   ipt = pt.val[nm];
if(verbose>=2){
  fprintf(fpout,"At start of nextpt: nm =%d:   ipt = %d  list = ",nm,ipt);
  fprintf(fpout," (quittrace=%d)",*quittrace);
  for(int i= 1;i<=nm;i++)
    fprintf(fpout,"  %d",pt.val[i]);
  fprintf(fpout,"\n");
}
   for(icon=0;icon< bone1.ptv[ipt].num;icon++){ // try all points connected to ipt
      ni = nm+1;  // counts total number of points from nm = 1 = pt in  tracept
      if(ni>TRPTS-3){
if(verbose>=2)
        fprintf(fpout,"ERROR: ni>TRPTS-3\n");
#if 1
        *quittrace=2;
        goto poorpt;
#endif
//        goto endmake;
     }
     npt = bone1.ptv[ipt].con[icon]; // the number of the next connected pt
     d1tod3(bone1.cmax,bone1.ptv[npt].pos,ivec);
     iset = (int)set[ivec[0]][ivec[1]][ivec[2]];
     if( (iset< 0)|| (iset == pt.val[1]) )// point is allready fit (-1) or used for current trace (startpt= pt.val[1]) 
             goto poorpt;
     else 
             set[ivec[0]][ivec[1]][ivec[2]]=pt.val[1]; // label all pts on trace = startpt= pt.val[1]
     pt.val[ni] = npt;
if(verbose>=2){
  fprintf(fpout,"End nextp:ncon=%d  icon=%d:  ",bone1.ptv[ipt].num,icon);
  for(i=1;i<=ni;i++)
    fprintf(fpout," %d",pt.val[i]);
  fprintf(fpout,"\n"); 
}
     imcv(den1,ivec,pt.fpos[ni]);// convert int grid ivec to float world co-ord fvec
#if 0 // Delete this check - it is wrong if non-rectangular grid
     for(i=0;i<=2;i++){
       if( (pt.fpos[ni][i]< den1.ximin[i]+geo.arange) ||
              (pt.fpos[ni][i]> den1.ximax[i]-geo.arange) ){
          *quittrace=3; // Indicates on boundary go to next 3 branch pt
if(verbose>=2)
  fprintf(fpout," ON Boundary in nextpt, goint to next branchpt \n");
           goto poorpt;
       }     
     }
#endif
     stdist = distv(pt.fpos[1],pt.fpos[ni]);
     curdist = curdist+ distv(pt.fpos[ni-1],pt.fpos[ni]);
if(verbose>=2){
  fprintf(fpout,"ni = %d pt.val[1]  %d  pt.val[ni] = %d \n",ni,pt.val[1],pt.val[ni]);
  fprintf(fpout,"stdist = %5.3f  curdist = %5.3f  cur/staight = %5.3f\n",
    stdist,curdist,curdist/stdist);
}    

     prevstdist = distv(pt.fpos[1],pt.fpos[ni-1]);
#if 0 // used before 23apr99
     if( (stdist>geo.stdist[1])&&(prevstdist<=geo.stdist[1]) ){ // first time greater
        curdist = curdist*geo.stdist[1]/stdist;  // scale cur dist for actual st dist
#endif
#if 1 // tried 23apr99
     for(jj=1;jj<=ni;jj++){ // See if tested for helix using bones through this testpt
       if(pt.val[jj]== *testpt)
          goto testsheet;
     }  
#endif
     if(stdist>geo.stdist[1]) { // anytime greater       
        if(curdist >= geo.curlimdist[1]){ // if curvdist > minimum
           nhelfits = nhelfits+1; 
           *testpt = pt.val[ni]; 
           fprintf(fpout," FITTING HELIX: %d  to %d\n",pt.val[1],pt.val[ni]);
           geo.itype =1;
           geo.nstartres = 3; // number of residues in initial fit  
//if(pt.val[1]==8403 && pt.val[ni]==7922)
//  printf("\n");
           initialfit(den1,geo,pt,ni,quittrace,fit,fitnum,set,bone1);
           fprintf(fpout,"FINISHED FITTING HELIX: %d  to %d\n",pt.val[1],pt.val[ni]);
           nii[0] =pt.val[1];
           nii[1] = pt.val[ni];
           if( ( *quittrace==4)||(*quittrace==20) ) // a good fit (if = 20 - already formed fit
              goto endmake; 
        } // if curdist
      } // if stdist
      testsheet:;
      if( (stdist>geo.stdist[2])&&(prevstdist<=geo.stdist[2]) ){ // first time greater
       curdist = curdist*geo.stdist[2]/stdist;  // scale cur dist for actual st dist
       if(curdist <= geo.curlimdist[2]){ // if curvdist < max
            nshfits = nshfits+1;     
            fprintf(fpout," FITTING SHEET: %d  to %d\n",pt.val[1],pt.val[ni]);
//if( (pt.val[1]==6894)&&(pt.val[ni]==8692) )
//  printf("\n");
            geo.itype =2;
            geo.nstartres = 3;
            initialfit(den1,geo,pt,ni,quittrace,fit,fitnum,set,bone1);
            fprintf(fpout,"FINISHED  FITTING SHEET: %d  to %d\n",pt.val[1],pt.val[ni]);
            nii[0] =pt.val[1];
            nii[1] = pt.val[ni]; 
         }
         else //trace no good, go to previous branch point
            *quittrace=2;
      }
      else{ // OK to go to next pt  - set nm = ni in next call
            nextpt(den1,geo,bone1,pt,ipt,ni,nii,set,quittrace,curdist,
              fit,fitnum,testpt);// recursive call next point on trace 
      }
      poorpt:; // skip to here if short loop or backward step or reached pt where helix or sheet condition satisfied or on boundary
      if( (*quittrace == 1)||(*quittrace==4)||(*quittrace==20) ) // if found good fit or want to end procedure       }
                goto endmake;
      else if( (*quittrace==2)||(*quittrace==3) ) //if  bad fit or on boundary, go to previous branch pt
           *quittrace = 0;

    } // icon
endmake:;
}    

void tracepts(struct griddata& den1,struct geometry& geo,
        struct bonedata& bone1,struct point pt,int totnum,
        int startpt,float sprad2[NSPHERES],int nii[2],
        int *quittrace)
/* Cut routine for tracepep - runs through all bone pts
*/
{
   int i,ipt,iset,nm,ivec[3],testpt;
   int ppt;

   float curdist;
//float xx[2];

   for(ipt =startpt;ipt<totnum;ipt++){
//    srand48(ipt+5); // Used up to 6dec00
  srand48(ipt+geo.addseed); // NEW
    if(bone1.ptv[ipt].num >=3){// if 3 or more connected points - i.e. potenital branch point where expect Ca
      d1tod3(bone1.cmax,bone1.ptv[ipt].pos,ivec);
      iset = geo.set[ivec[0]][ivec[1]][ivec[2]];
      if(iset >=0) {//point not previously fit by another peptide
        if(verbose>=1){
          fprintf(fpout," STARTING NEW  ipt = %d \n",ipt);
        }
        nm = 1; // This is first pt on this trace 
        pt.val[1] = ipt;  //(NOTE: pt.val[nm=1] = startpt of trace) the point number of this pt       
        imcv(den1,ivec,pt.fpos[nm]);// convert int grid ivec to float world co-ord fvec
        if( (geo.spherelim!=1)||(checksphere(pt.fpos[nm],sprad2)==1) ){ // in spheres
           *quittrace =0;  
           curdist = 0.0;// measures distance along mainchain
           ppt= -1000;  // Give "previous point" an impossible value
           geo.set[ivec[0]][ivec[1]][ivec[2]]=pt.val[1]; // label all pts on trace = startpt= pt.val[1]
           testpt = -10; // nonsense valule
           nextpt(den1,geo,bone1,pt,ppt,nm,nii,geo.set,quittrace,curdist,
              fit,fitnum,&testpt); 
   	   if( *quittrace==4 ){ // Indicates found good fit
      	      for(i=1;i<NFIT;i++){ // find bin num = ii to save fit in
       	         if(fitnum[i]<0){ // indicates is empty
                    goto quitsearch;
                 }
              } // i
              fprintf(fpout,"ERROR: MORE THAN NFIT SAVED FITS, CANNOT SAVE ANYMORE\n");// if reach here - no empty fits     
              goto skipcopy;
              quitsearch:;
              geo.setval = -i; 
//      	      setpts(den1,geo,geo.set,1); //sets all side pts set points around geo = -1
//      	      setpts(den1,geo,geo.set,2); //used after 22oct00:sets 3 side pts set points around geo = -1
      	      setpts(den1,geo,geo.set,2); //NEW 1feb01 - changed definition of setside, now setside = 1 means set 1 side ptssets 2 side pts set points around geo = -1
              if(verbose>=1)
                 fprintf(fpout," SAVE THIS EXTENDED FIT in bin %d\n",i);
              fitnum[0]= fitnum[0]+1; // add another fit
              fitnum[ fitnum[0] ] = i;
              fit[i].nalloc = -10; // initial default - indicates have not yet allocated 
              copygeotofit(geo,fit[i],nii);
              geo.nend[0]=geo.nend[1]=0; // set so 0 length
              savefit();
              skipcopy:;     
           }
           else if( *quittrace==20){ // found fit and fused, forming new fit - already set pts 
              if(verbose>=1)
                 fprintf(fpout," SAVE THIS FUSED EXTENDED FIT as old fit\n");
              geo.nend[0]=geo.nend[1]=0; // set so 0 length
              savefit();
          }
#if 0 // used for debugging - quit after one or two good fits
           if(fitnum[0]==1)
//           if(fitnum[0]==2)
           *quittrace=1;
#endif

           if (*quittrace ==1) // Quit the entire routine
                  goto quitrout;
         } // in sphere 
       } // if iset!=1
     }// if bone.num>3
#if 0 // used for debugging - quit after frist point
       goto quitrout;
#endif
   } // ipt
   quitrout:;
}


void tracepep(struct griddata& den1,
        struct geometry& geo,struct bonedata& bone1)
/*
SEE trace.notes   (II)
*/
{
   int i,j,k,totnum,startpt,quittrace;
   struct point pt;
   float sprad2[NSPHERES],origminrigid,origrfor,origtorconst;
//   int ***set;
   int nii[2],origrepeat,origsavlen,origbadend; // the number of points on the trace (maximum of 9), 
   int origendmove,orignprelim,origuseset,origsetrad,origsetval;
   float origgeohelix[10],origmaxline;
   char fitpdbfile[300],savfile[300];
   clock();

origsavlen = geo.savlen;
origendmove = geo.endmove;
origtorconst = tordata.torconst;
origminrigid =geo.minrigid;
origbadend = geo.nbadend;
orignprelim =tordata.nprelim;
origrfor = tordata.rfor;
origrepeat = tordata.irepeat;
origuseset = geo.useset;
origmaxline = geo.maxline;
origsetval = geo.setval;

geo.addseed=0; 
printf("/n/n STARTING NEW TRACEPEP USING BONE %s\n",bone1.bonename);
origsetrad = geo.setrad;
#if 0 // NOT used - setrad = 1 seems to work OK at high resolution
geo.deldist = sqrt( dot(den1.delx,den1.delx) ); // length of den1.delx vector = 1.445 for shad , res = 2.5
if(geo.deldist < 1.15) // resolution < about 2.0
   geo.setrad = 2;
else
   geo.setrad = 1; // the usual standard value
#endif
printf(" geo.deldist = %5.3f  Setting geo.setrad = %d\n",geo.deldist,geo.setrad);
geo.useset = 0; // this is needed for checkifbranch
geo.nbadend = 0;
for(i=0;i<=7;i++)
   origgeohelix[i] = geo.sheet[1][i]; 
#if 1 // Used after  30may00 - smaller allowed range seems to work better  - used only while tracing - then go back to original
   geo.sheet[1][0]= -DEGTORAD*110.0; /*phi min*/
   geo.sheet[1][1]= -DEGTORAD*50.0;  /* phi max*/
   geo.sheet[1][2]= -DEGTORAD*45.0; /*psi min*/
   geo.sheet[1][3]= DEGTORAD*10.0; /*psi max*/
   geo.sheet[1][4]= DEGTORAD*10.0; //  range of which mag varies from 0 to 1
   geo.sheet[1][7] = DEGTORAD*30.0; //New 30may00 - try smaller range +/- range 
#endif

//geo.nbadend = 1;  // 3mar00 - debug using larger value
//geo.maxside = 1; //DO NOT USE!! NOTE: maxside is not used in trace - see trace.notes 9jun99
dynquit=0;  // if = 0, then use stand. quitcond - save best end density; if = N, just run N steps (no repeat) and save last 
#if 0 // do not repeat
tordata.rfor3 = origrfor;  // this the value used in bestden - which always repeats with rfor=0
tordata.rfor2 =1.0*origrfor; // Value used when run tordyn at lower temp
tordata.rfor = tordata.rfor2; //NOTE: this is used in everything but bestden, which uses different values
tordata.irepeat = 0; // if =1 then repeat tordyn at lower temp
#endif
#if 1 //repeat tordyn at lower temp
tordata.rfor3 = origrfor;  // this the value used in bestden - which always repeats with rfor=0
//tordata.rfor = 1.5*origrfor;
//tordata.rfor = 1.0*origrfor; // USed up to 1dec99
tordata.rfor = 0.5*origrfor; // WORKED WELL - USED UPTO 18oct00 --Try smaller value
tordata.rfor = 1.0*origrfor; // Try larger value  - 18oct00
tordata.rfor = 0.5*origrfor; // Try old -smaller  value  - 26oct00
tordata.rfor2 =0.1*origrfor; //- USED UPTO 18oct00 Value used when run tordyn at lower temp
tordata.rfor2 =0.0*origrfor; // - 18oct00  Value used when run tordyn at lower temp
tordata.irepeat =1; // if =1 (repeat in extendc or n and checkextended fit) or 2 (repeat only in checkextendfit) then repeat tordyn at lower temp in extendc or n
printf("USING repeat:  rfor = %5.3f*origrfor   rfor2 =  %5.3f*origrfor\n",
              tordata.rfor/origrfor,tordata.rfor2/origrfor);
#endif
fprintf(fpout," STARTING TRACEPEP: irepeat = %d rfor = %5.3f  rfor2 = %5.3f\n",
                       tordata.irepeat,tordata.rfor,tordata.rfor2); 
fprintf(fpout,"    dynquit = %d  maxside = %d  savlen = %d \n",
                   dynquit,geo.maxside,geo.savlen); 
//geo.minrigid = 0.25*maidfile.denscale; //Try increasing from old value = 0;  the value used to define nbad   
tordata.nprelim = 20; // # preliminary runs in tordynbat befor
   if(geo.spherelim==1){ // read sphere radius and pos
          recallspheresbat(geo);
          for(i=1;i<=maidfile.nsphere;i++) // find square of radius
            sprad2[i]=sqr(sp[i].radius);
   }
   if(maidfile.nsphere<=0){
      printf("USING COMPLETE MAP FOR trace - NOT USING SPHERES\n");
   }
   else{
      printf("USING %d SPHERES:\n",maidfile.nsphere);
      for(i=1;i<=maidfile.nsphere;i++){
         printf("   radius = %5.3f  Center x,y,z  = %5.3f %5.3f %5.3f\n",
                  sp[i].radius,sp[i].cenpos[0],sp[i].cenpos[1],sp[i].cenpos[2]);
      }
   }
   printgeopar(geo);
   if(geo.nowset == 0){ // set not already allocated
      imat3(geo.set,den1.griddim[0],den1.griddim[1],den1.griddim[2]);// allocates array 3 dim array (mat)
      geo.nowset = 1;
   }
   finddist(geo); // Find straight and curved distance along residue
   geo.errcurv[1]= (geo.curdist[1]/geo.stdist[1] + geo.curdist[2]/geo.stdist[2])/2.0; //if cur/st ? errcurv, the helix, else sheet
//   geo.curlimdist[1]= 12.5;  // minnimum helix curdist - This misses 3 out of 10 helices
   geo.curlimdist[1]= 11.0;  // minnimum helix curdist
   geo.curlimdist[2]= 16.0;  // maximu sheet curdist
//   geo.curlimdist[2]= 24.5;  //debug - too many false tries
//   fprintf(fpout,"Error curve ratio (curvedist/straight dist) = %6.3f\n",geo.errcurv[1]);
  fprintf(fpout," Mininum helix curdist = %5.3f   maximum sheet curdist = %5.3f\n",
          geo.curlimdist[1],geo.curlimdist[2]);
   geo.nend[0]=geo.nend[1]=0; // set so 0 length
   totnum = bone1.ptv.end()-bone1.ptv.begin();
fprintf(fpout,"totnum = %d\n",totnum); 
float avegrid=0.0;
  for(i=0;i<=2;i++)
    avegrid = avegrid+den1.delx[i];
  avegrid = avegrid/3.0;
  geo.nihel = 0.5 + geo.curdist[1]/(1.414*avegrid); // 0.5 so that rounds to nearest int
  geo.nisheet = geo.curdist[2]/(1.414*avegrid);
printf("\nGRID SIZE:  %5.3f %5.3f %5.3f avegrid = %5.3f  nihel = %d\n", 
      den1.delx[0],den1.delx[1],den1.delx[2],avegrid,geo.nihel);

#if 0
printf("WARNING WARNIG FOR DEGUGGING SETTING geo.newfit = 2\n");;
geo.newfit=2;
#endif

   for(i=0;i<den1.griddim[0];i++) //NEW set = 0 set all grid points = 0
     for(j=0;j<den1.griddim[1];j++)
       for(k=0;k<den1.griddim[2];k++)
          geo.set[i][j][k] = 0;
   if(geo.newfit ==0){ // start over - do no use fits in fitfile
      for(i=1;i<NFIT;i++) //(This is repeated in main???) set fitnum < 0 - indicate is empty
        fitnum[i]= -10;
      fitnum[0]=0;
      pt.val[0] = -5; // set the bone number of the zero point to some impossible value
      startpt = 1;
      fprintf(fpout,"STARTING NEW FIT: startpt = %d\n",startpt);
   }
   else if (geo.newfit>=1){ 
       for(i=0;i<NFIT;i++)
         fit[i].nalloc = -10; // initial default - indicates have not yet allocated 
       readfit(geo,maidfile.fitfile);
       printf("Setting points for %d fits\n",fitnum[0]);
       for(i=1;i<=fitnum[0];i++){ // set points for each fit
           copyfittogeo(geo,fit[i]);
           geo.setval = -i;      
//           setpts(den1,geo,geo.set,1); // set all side pts  set = 1 (NOTE: IF fits have a.a. assigne, cannot use set value = 1)
//      	   setpts(den1,geo,geo.set,2); //used after 22oct00:sets 3 side pts set points around geo = -1
      	   setpts(den1,geo,geo.set,2); //used after 1feb01:New definitino of setside = 1 sets 1 side pts set points around geo = -1
       }
       if(geo.newfit==1) // continue from bonept used for last fit
          startpt = fit[fitnum[0]].val1+1; // Use this if continuing at last bonept
       else // start over
          startpt = 1;
       pt.val[0] = -5; // set the bone number of the zero point to some impossible value
//       startpt = 1;
       fprintf(fpout," CONTINUING FIT USING FITFILE with %d fits and startpt = %d\n",fitnum[0],startpt);
   }
#if 0
//startpt = 8778;
startpt = 6894;
//startpt = 1;
//geo.savlen = geo.savlen-1;
//  geo.addseed = 10;
//verbose=2;
#endif

#if 0
printf("Enter value  of startpt\n");
   scanf("%d",&startpt);
#endif
#if 0 //debug: ASUMES fitting sheet -  just call initialfit and quit 
     int ni,ivec[3];
   geo.thtot = PI/6.0; //  range over which theta is varied
   geo.trandel = 0.3; // translatino step in angstroms
   geo.tstep = 2; // number of translation steps  (max tran = tstep*trandel)
//   geo.tstep = 3; // number of translation steps  (max tran = tstep*trandel)
   geo.axstep = 1; // step + or -1 large step of geo.axdel along Ca to Ca axis
   geo.axdel = 1.2;  // = Angstrom step along axis
   geo.rotdel = 1.0; // maximu distance furthers point move during a rotation step
   geo.thtot = geo.thtot/2.0;
   geo.rotdel = geo.rotdel/2.0;
     ni = 2;
     pt.val[1]=8550;
     pt.val[ni]=12598;
     geo.itype=2;
     d1tod3(bone1.cmax,bone1.ptv[ pt.val[1] ].pos,ivec);
     imcv(den1,ivec,pt.fpos[1]);// convert int grid ivec to float world co-ord fvec
     d1tod3(bone1.cmax,bone1.ptv[ pt.val[ni] ].pos,ivec);
     imcv(den1,ivec,pt.fpos[ni]);// convert int grid ivec to float world co-ord fvec
     fprintf(fpout," FITTING SHEET: %d  to %d\n",pt.val[1],pt.val[ni]);
     initialfit(den1,geo,pt,ni,&quittrace,fit,fitnum,geo.set,bone1);
     fitnum[0]=1; // add another fit
     fitnum[ fitnum[0] ] = 1;
     i=1;
     fit[i].nalloc = -10; // initial default - indicates have not yet allocated 
     nii[0] =pt.val[1];
     nii[1] = pt.val[ni]; 
     copygeotofit(geo,fit[i],nii);
     geo.nend[0]=geo.nend[1]=0; // set so 0 length
     savefit();
  goto quitrout;
#endif
#if 0 // For debugging - chech routine "checkextendfit"
int ifit,resbad[200];
float avecb2,aveco;
int icheckhelsh = 1;
    readfit(geo,maidfile.fitfile);
//    ifit = 3;
    for(ifit = 1;ifit<=fitnum[0];ifit++){
      printf(" Checking fit %d\n",ifit);
      geo.itype=fit[ifit].itype[2];
      copyfittogeo(geo,fit[ifit]);
//      aveden(den1,geo,geo.pos,&lastden,&avecb2,&aveco,&nbad,resbad); // Find average density (ave) for initial orientation 
      checkextendedfit(icheckhelsh,geo,den1,resbad,&quittrace); //Recursive fuction - keeps calling
//      checkoneenden(den1,geo,quittrace);// only calls once - allows end to bereduced one belows savlen
//      checkoneendbranch(den1,geo,bone1,quittrace);
    }
  goto endrout;
#endif

#if 0 // Use ideal helix, check findcurvrad
float radius = 2.0;
float pitch = 5.0/(2.0*PI);
float ang = 0.0;
float torsion;
int ni=7;
for(i= 1;i<=ni;i++){
  ang = ang+ 2.0*PI/10.0;
  pt.fpos[i][0] = radius*cos(ang);
  pt.fpos[i][1] = radius*sin(ang);
  pt.fpos[i][2] = pitch*ang;
}
findcurverad(pt,ni,&radius,&torsion);  //Find curvature and torsion of curve
#endif

printf("\n\n STARTING FRIST SEARCH USING geo.savlen = %d startpt = %d addseed = %d\n",
     geo.savlen,startpt,geo.addseed);
tracepts(den1,geo,bone1,pt,totnum,startpt,sprad2,nii,
      &quittrace);// Use original geo.savlen
//NOTE HAVE CUT OUT routine to checkend -  see trace.c13sep00
#if 1 // Repeat using shorter savlen
  geo.savlen = geo.savlen -1;
  geo.maxline = 0.48;  //15feb01  - no longer use linedist condition in bonedistgeo Max. allowed value of aveline in bonedistgeo - Use strong condition for short fits
  geo.addseed = 10;
  printf("\n\n REPEATING USING geo.savlen of 1 less = %d addseed = %d\n",
       geo.savlen,geo.addseed);
  startpt = 1;
  pt.val[0] = -5; // set the bone number of the zero point to some impossible value
  tracepts(den1,geo,bone1,pt,totnum,startpt,sprad2,nii,
      &quittrace);// Use original geo.savlen
#endif
avemaxbatch(den1,geo); //NEW - 13sep00 - find fits with bad ratio aveden/avemax
//savefit(); // Already saved by avemaxbatch - Save the finalfit
for(i=0;i<=7;i++)
   geo.sheet[1][i]=origgeohelix[i];
geo.maxline = origmaxline; 
geo.useset=origuseset;
geo.minrigid=origminrigid; 
geo.nbadend=origbadend;
geo.endmove = origendmove;
geo.setrad=origsetrad;
tordata.nprelim=orignprelim;
tordata.rfor = origrfor;
tordata.torconst = origtorconst;
tordata.irepeat=origrepeat;
geo.savlen=origsavlen;
geo.setval=origsetval;
printf("Number of attemtps to fit helix = %d   and sheet =%d\n",nhelfits,nshfits);
strcpy(savfile,maidfile.fitfile); //Save the fit file as fit_trace...
strcat(savfile,"_trace");
savebackupfit(savfile); // copies fitfile to savfile      
strcpy(fitpdbfile,maidfile.fitfile); // Save the fit as fitfile.pdb
strcat(fitpdbfile,"_trace");
strcat(fitpdbfile,".pdb");
writefittopdbgen(den1,geo,fit,fitnum,fitpdbfile);
endrout:;
}

void tracepepbatch(struct griddata& den1,
        struct geometry& geo,struct bonedata& bone1)
/* 
 Calls tracepep using different den values for bones
Uses bone.c++:  float fminden[10]= {0.8,1.0,1.2,1.4,1.6,1.8,2.0,2.2,2.4,2.6}
 [0] = 0.8,   [4] = den1.6
*/
{
   int iden;
   char ch[10];
   FILE *fp;

   geo.newfit =0; //First time Start over with all new fit
//   for(iden = 4;iden>=2;iden--){// start with den[1.6] and reduce to 1.4 and 1.2
   for(iden = 3;iden>=1;iden--){// start with den[1.4] and reduce to 1.2 and 1.0
     bone1.minden = fminden[iden]; 
     strcpy(bone1.bonename,den1.mapname);
     strcat(bone1.bonename,".bone"); // bone  name is mapname with .bone_minden appended
     sprintf(ch,"%1.1f",bone1.minden);
     strcat(bone1.bonename,ch);
     fp=fopen(bone1.bonename,"r");
     if(fp == NULL){ // file does not exist - NOTE - closing NULL causes crash in Linux
//         fclose(fp);
         findbone(den1,bone1);
     }
     else{
       fclose(fp);
       readbonefile(bone1);
     } 
     tracepep(den1,geo,bone1);
     geo.newfit = 1;  // Subsequent calls, start with previous set of fits
  } // iden
  geo.newfit = 0;
}
