CCL Home Page
Up Directory CCL proja.c
/**************************************************************************/
/********************  Projected Area calculations  ***********************/
/**************************************************************************/

#include 
#include 
#include 
#include 
#include "sterdefn.h"
#include "integrat.h"
#include "stermem.h"
#include "steraid.h"
#include "stercalc.h"
#include "stertext.h"
#include "craig.h"
#include "proja.h"

/**************************************************************************/
/******************  circle memory management  ***************************/
/**************************************************************************/

Pover *New_Pover(Pover *old)
{
  Pover *new=NULL;
  if((new=(Pover *)malloc(sizeof(Pover)))==NULL)
  {
    Error_Message(E_NOMEM,"New Pover");
    return(NULL);
  }
  new->next=NULL;
  new->prev=NULL;
  if(old==NULL) return(new);
  new->next=old->next;
  new->prev=old;
  if(old->next) old->next->prev=new;
  old->next=new;
  return(new);
}

/**************************************************************************/

Circ *New_Circ(Circ *old)
{
  Circ *new=NULL;
  if((new=(Circ *)malloc(sizeof(Circ)))==NULL)
  {
    Error_Message(E_NOMEM,"New Circ");
    return(NULL);
  }
  new->next=NULL;
  new->prev=NULL;
  if(old==NULL) return(new);
  new->next=old->next;
  new->prev=old;
  if(old->next) old->next->prev=new;
  old->next=new;
  return(new);
}

/**************************************************************************/

Mint *New_Mint(Mint *old)
{
  Mint *new=NULL;
  if((new=(Mint *)malloc(sizeof(Mint)))==NULL)
  {
    Error_Message(E_NOMEM,"New Mint");
    return(NULL);
  }
  new->next=NULL;
  new->prev=NULL;
  if(old==NULL) return(new);
  new->next=old->next;
  new->prev=old;
  if(old->next) old->next->prev=new;
  old->next=new;
  return(new);
}

/**************************************************************************/
/**************************************************************************/

Pover *First_Pover(Pover *current)
{
  if(current==NULL) return(NULL);
  while(current->prev!=NULL) current=current->prev;
  return(current);
}

/**************************************************************************/

Pover *Last_Pover(Pover *current)
{
  if(current==NULL) return(NULL);
  while(current->next!=NULL) current=current->next;
  return(current);
}

/**************************************************************************/

Circ *First_Circ(Circ *current)
{
  if(current==NULL) return(NULL);
  while(current->prev!=NULL) current=current->prev;
  return(current);
}

/**************************************************************************/

Circ *Last_Circ(Circ *current)
{
  if(current==NULL) return(NULL);
  while(current->next!=NULL) current=current->next;
  return(current);
}

/**************************************************************************/

Mint *First_Mint(Mint *current)
{
  if(current==NULL) return(NULL);
  while(current->prev!=NULL) current=current->prev;
  return(current);
}

/**************************************************************************/

Mint *Last_Mint(Mint *current)
{
  if(current==NULL) return(NULL);
  while(current->next!=NULL) current=current->next;
  return(current);
}

/**************************************************************************/
/**************************************************************************/

int Get_Pover_Number(Pover *current)
{
  int count=0;
  if(current==NULL) return(0);
  while(count++,current->prev!=NULL) current=current->prev;
  return(count);
}

/**************************************************************************/

int Get_Circ_Number(Circ *current)
{
  int count=0;
  if(current==NULL) return(0);
  while(count++,current->prev!=NULL) current=current->prev;
  return(count);
}

/**************************************************************************/

int Get_Mint_Number(Mint *current)
{
  int count=0;
  if(current==NULL) return(0);
  while(count++,current->prev!=NULL) current=current->prev;
  return(count);
}

/**************************************************************************/
/**************************************************************************/

Pover *Goto_Pover(Pover *current, int num)
{
  int count=0;
  current=First_Pover(current);
  if(current==NULL) return(NULL);
  while(count++,(current->next!=NULL)&&(count!=num)) current=current->next;
  return(current);
}

/**************************************************************************/

Circ *Goto_Circ(Circ *current, int num)
{
  int count=0;
  current=First_Circ(current);
  if(current==NULL) return(NULL);
  while(count++,(current->next!=NULL)&&(count!=num)) current=current->next;
  return(current);
}

/**************************************************************************/

Mint *Goto_Mint(Mint *current, int num)
{
  int count=0;
  current=First_Mint(current);
  if(current==NULL) return(NULL);
  while(count++,(current->next!=NULL)&&(count!=num)) current=current->next;
  return(current);
}

/**************************************************************************/
/**************************************************************************/

Pover *Next_Pover(Pover *current)
{
  if(current==NULL) return(NULL);
  if(current->next==NULL) return(current);
  return(current->next);
}

/**************************************************************************/

Pover *Previous_Pover(Pover *current)
{
  if(current==NULL) return(NULL);
  if(current->prev==NULL) return(current);
  return(current->prev);
}

/**************************************************************************/

Circ *Next_Circ(Circ *current)
{
  if(current==NULL) return(NULL);
  if(current->next==NULL) return(current);
  return(current->next);
}

/**************************************************************************/

Circ *Previous_Circ(Circ *current)
{
  if(current==NULL) return(NULL);
  if(current->prev==NULL) return(current);
  return(current->prev);
}

/**************************************************************************/

Mint *Next_Mint(Mint *current)
{
  if(current==NULL) return(NULL);
  if(current->next==NULL) return(current);
  return(current->next);
}

/**************************************************************************/

Mint *Previous_Mint(Mint *current)
{
  if(current==NULL) return(NULL);
  if(current->prev==NULL) return(current);
  return(current->prev);
}

/**************************************************************************/
/**************************************************************************/

Pover *Close_Pover(Pover *current)
{
  Pover *old;
  if(current==NULL) return(NULL);
  if(current->prev==NULL)
  {
    if(current->next==NULL)
    {
      free(current);
      return(NULL);
    }
    current=current->next;
    free(current->prev);
    current->prev=NULL;
    return(current);
  }
  if(current->next==NULL)
  {
    current=current->prev;
    free(current->next);
    current->next=NULL;
    return(current);
  }
  old=current;
  current=old->prev;
  old->prev->next=old->next;
  old->next->prev=old->prev;
  free(old);
  return(current);
}

/**************************************************************************/

Circ *Close_Circ(Circ *current)
{
  Circ *old;
  if(current==NULL) return(NULL);
  if(current->prev==NULL)
  {
    if(current->next==NULL)
    {
      free(current);
      return(NULL);
    }
    current=current->next;
    free(current->prev);
    current->prev=NULL;
    return(current);
  }
  if(current->next==NULL)
  {
    current=current->prev;
    free(current->next);
    current->next=NULL;
    return(current);
  }
  old=current;
  current=old->prev;
  old->prev->next=old->next;
  old->next->prev=old->prev;
  free(old);
  return(current);
}

/**************************************************************************/

Mint *Close_Mint(Mint *current)
{
  Mint *old;
  if(current==NULL) return(NULL);
  if(current->prev==NULL)
  {
    if(current->next==NULL)
    {
      free(current);
      return(NULL);
    }
    current=current->next;
    free(current->prev);
    current->prev=NULL;
    return(current);
  }
  if(current->next==NULL)
  {
    current=current->prev;
    free(current->next);
    current->next=NULL;
    return(current);
  }
  old=current;
  current=old->prev;
  old->prev->next=old->next;
  old->next->prev=old->prev;
  free(old);
  return(current);
}

/**************************************************************************/

Circ *Close_All_Circles(Circ *circ)
{
  for(circ=First_Circ(circ);circ!=NULL;circ=Close_Circ(circ));
  return(circ);
}

/**************************************************************************/

Mint *Close_All_Mints(Mint *mint)
{
  for(mint=First_Mint(mint);mint!=NULL;mint=Close_Mint(mint));
  return(mint);
}

/**************************************************************************/

Pover *Close_Current_Pover(Pover *over)
{
  over->Cr=Close_All_Circles(over->Cr);
  over->Cr=Close_All_Circles(over->Cr);
  return(Close_Pover(over));
}

/**************************************************************************/

void Close_All_Poverlaps(Pover *over, char *title, unsigned short mode)
{
  Pover *o=NULL;
  char line[LINELEN];
  int count=0;
  for(o=First_Pover(over),count=0;o!=NULL;count++,o=o->next);
  if((count>0)&&(mode&VIS_BIT))
  {
    sprintf(line,"Closing temporary overlap calculation memory for %d %s overlaps",count,title);
    Out_Message(line,O_NEWLN);
  }
  for(over=First_Pover(over);over!=NULL;over=Close_Current_Pover(over));
}

/**************************************************************************/
/**************************************************************************/

void Initialize_Mint(Mint *mint, Atms *A, Atms *B)
{
  mint->I=Vequal(0.0,0.0,0.0);
  mint->A[0]=A;
  mint->A[1]=B;
#ifdef DEBUG
  mint->num=0;
#endif
}

/**************************************************************************/

void Initialize_Circle(Circ *circ, Atms *at)
{
  circ->radius=0.0;                /* circle radius                       */
  if(at!=NULL) circ->radius=at->tradius;
  circ->delta=0.0;                 /* atom distance from position G       */
  circ->A=at;                      /* pointer to atom memory              */
  circ->I[0]=Vequal(0.0,0.0,0.0);
  circ->I[1]=Vequal(0.0,0.0,0.0);
  circ->theta=0.0;                 /* angle between intersepts            */
  circ->phi=0.0;                   /* angle between i[0] and g            */
  circ->gamma=0.0;                 /* angle between gi[0] and gi[1]       */
  circ->mode=0;                    /* for special circle modes            */
#ifdef DEBUG
  circ->num=0;
#endif
}

/**************************************************************************/

int Add_Circle(Pover *over, Atms *A)
{
  Circ *cr=NULL;
  if(over==NULL) return(0);
  if((cr=New_Circ(over->Cr))==NULL) return(0);
  over->Cr=cr;
  Initialize_Circle(over->Cr,A);
  return(1);
}

/**************************************************************************/

int Make_Circles(Pover *over, Atms *A[], int order)
{
  int i=0;
  if(order>MAX_OVER) order=MAX_OVER;
  if(over==NULL) return(0);
  over->Cr=Close_All_Circles(over->Cr);
  for(i=0;(incir=order;
  return(1);
}

/**************************************************************************/

int Initialize_Pover(Pover *over, int order)
{
  if(order>MAX_OVER) order=MAX_OVER;
  if(over==NULL) return(0);
  over->Cr=NULL;
  over->Mi=NULL;
  over->G=Vequal(0.0,0.0,0.0);       /* vector to center of overlap       */
  over->order=order;                 /* overlap order (eg. 3=triple       */
  over->ncir=order;                  /* number of circles bounding over   */
  over->area=0.0;                    /* area calculated                   */
#ifdef DEBUG
  over->num=0;
#endif
  return(1);
/* next and prev pointers have been set so don't touch                    */
}

/**************************************************************************/

void Copy_Mint(Mint *new, Mint *old)
{
  new->I=VequalV(old->I);
  new->A[0]=old->A[0];
  new->A[1]=old->A[1];
}

/**************************************************************************/

void Copy_Circle(Circ *new, Circ *old)
{
  new->radius=old->radius;
  new->delta=old->delta;
  new->A=old->A;
  new->I[0]=VequalV(old->I[0]);
  new->I[1]=VequalV(old->I[1]);
  new->theta=old->theta;
  new->phi=old->phi;
  new->gamma=old->gamma;
  new->mode=old->mode;
}

/**************************************************************************/

void Copy_Pover(Pover *new, Pover *old)
{
  Circ *cr=NULL;
  Circ *ncr=NULL;
  Mint *mi=NULL;
  Mint *nmi=NULL;

  if((new!=NULL)&&(old!=NULL))
  {
    new->Cr=Close_All_Circles(new->Cr);
    for(cr=First_Circ(old->Cr);cr!=NULL;cr=cr->next)
    {
      if((ncr=New_Circ(new->Cr))==NULL) break;
      new->Cr=ncr;
      Copy_Circle(new->Cr,cr);
    }
    new->Mi=Close_All_Mints(new->Mi);
    for(mi=First_Mint(old->Mi);mi!=NULL;mi=mi->next)
    {
      if((nmi=New_Mint(new->Mi))==NULL) break;
      new->Mi=nmi;
      Copy_Mint(new->Mi,mi);
    }
    new->G=VequalV(old->G);
    new->order=old->order;
    new->ncir=old->ncir;
    new->area=old->area;
  }
}

/**************************************************************************/
/*******************  circle calculations  ********************************/
/**************************************************************************/

double deltaAB(Atms *A, Atms *B)
{
  double d=0.0, dx, dy;
  dx=A->tv.x-B->tv.x;
  dy=A->tv.y-B->tv.y;
  d = msqrt(dx*dx+dy*dy,"deltaAB");
  return(d);
}

/**************************************************************************/

int Find_2atom_Intersepts_P(double rA, double rB, Vector V[2], Vector I[2])
{
  double dAB, dx, dy;
  double cosP, sinP, cosT, sinT;
  int q=0;
  double a, l, p, t, s, m;
  static double Qx[4]={ 1,-1,-1, 1};
  static double Qy[4]={ 1, 1,-1,-1};

/* test for unusual cases */

  if((AlmostZero(rA))||(AlmostZero(rB)))
  {
    if(rA>=rB) return(1);
    else return(2);
  }
  dx=fabs(V[0].x-V[1].x);
  dy=fabs(V[0].y-V[1].y);
  dAB = msqrt(dx*dx+dy*dy,"dAB in Find 2atom Intersepts P");
  if(dAB>=(rA+rB))
  {
    Error_Message(E_NOOVER,"Find 2atom Intersepts P");
    return(-1);
  }
  if(AlmostZero(dAB))
  {
    if(rA>=rB) return(1);
    else return(2);
  }

/* find quadrant for B coords centred on xA, yA */

  if(V[1].y>=V[0].y) { if(V[1].x>=V[0].x) q=0; else q=1; }
  else               { if(V[1].x>=V[0].x) q=3; else q=2; }

/* now start actual intersept calculation */

  a = (rA*rA - rB*rB + dAB*dAB) / (2*dAB);
  l = msqrt(rA*rA - a*a,"Find 2atom Intersepts P");
                           /* above tests should ensure no error */

  cosP = a/rA;
  sinP = l/rA;
  cosT = dx/dAB;
  sinT = dy/dAB;
  
  p = cosT * cosP;
  t = sinT * sinP;
  s = sinT * cosP;
  m = cosT * sinP;
  
  I[0].z = 0.0;
  I[0].x = V[0].x + Qx[q] * rA * (p-t);
  I[0].y = V[0].y + Qy[q] * rA * (s+m);

  I[1].z = 0.0;
  I[1].x = V[0].x + Qx[q] * rA * (p+t);
  I[1].y = V[0].y + Qy[q] * rA * (s-m);

  return(0);
}

/**************************************************************************/

int Calculate_Circle_Intersept_Angles(Circ *circ, Vector *G, Vector *A)
{
  Vector i[2], g;
  double dAG, g2;


/**/
/* first to calculate gamma for checking purposes */
/**/
/* calculate i[] at G origin */

  i[0].x=circ->I[0].x-G->x;
  i[0].y=circ->I[0].y-G->y;
  i[0].z=0.0;
  i[1].x=circ->I[1].x-G->x;
  i[1].y=circ->I[1].y-G->y;
  i[1].z=0.0;

/* calculate angle between two intersept vectors */

  circ->gamma=VangleV(i[0],i[1]);

/**/
/* now to calculate the usable values, theta and phi */
/**/
/* calculate g at A origin */

  g.x=G->x-A->x;
  g.y=G->y-A->y;
  g.z=0.0;

  dAG = msqrt(g.x*g.x+g.y*g.y,"dAG in Calculate Circle Intersept Angles");
  if(dAG>=circ->radius)
  {
    Error_Message(E_BAD_G,"Calculate Circle Intersept Angles");
    return(0);
  }

/* calculate i[] at A origin */

  i[0].x=circ->I[0].x-A->x;
  i[0].y=circ->I[0].y-A->y;
  i[0].z=0.0;
  i[1].x=circ->I[1].x-A->x;
  i[1].y=circ->I[1].y-A->y;
  i[1].z=0.0;

/* calculate angle between two intersept vectors */

  circ->theta=VangleV(i[0],i[1]);

  if(circ->mode&A_NEGS) circ->theta=2*PI-circ->theta;

  if(AlmostZero(dAG))
  {
    circ->phi=0.0;
    circ->mode|=A_GCENT;     /* G centred on A */
    return(1);
  }

/* if G not at A calculate G */

  g2 = dot_product(g,i[1]);

  circ->phi=VangleV(i[0],g);
  
  if(((circ->mode&A_NEGS)&&(g2>=0.0))
   ||((!(circ->mode&A_NEGS))&&(g2<0))) circ->phi=2*PI-circ->phi;

/**/
/* first to calculate gamma for checking purposes */
/**/
/* calculate i[] at G origin */

  i[0].x=circ->I[0].x-G->x;
  i[0].y=circ->I[0].y-G->y;
  i[0].z=0.0;
  i[1].x=circ->I[1].x-G->x;
  i[1].y=circ->I[1].y-G->y;
  i[1].z=0.0;

/* calculate angle between two intersept vectors */

  circ->gamma=VangleV(i[0],i[1]);

  return(1);
}

/**************************************************************************/

int Find_2atom_G_P(Pover *over)
{
  Vector V[2]={{0.0,0.0,0.0},{0.0,0.0,0.0}};
  double gap=0.0;
  int n=0;
  Circ *Cr[2]={NULL,NULL};
  Mint *mint=NULL;
  
  if(((Cr[0]=Goto_Circ(over->Cr,1))==NULL)
   ||((Cr[1]=Goto_Circ(over->Cr,2))==NULL)
   ||(Cr[0]->A==NULL)||(Cr[1]->A==NULL))
    return(Error_Message(E_BDCIRC,"Find 2atom G P"));
  V[0]=VequalV(Cr[0]->A->tv);
  V[1]=VequalV(Cr[1]->A->tv);
  if((n=Find_2atom_Intersepts_P(Cr[0]->radius,Cr[1]->radius,V,Cr[0]->I))!=0) return(n);
  Cr[1]->I[0]=VequalV(Cr[0]->I[0]);
  Cr[1]->I[1]=VequalV(Cr[0]->I[1]);

/* add extra intersept memory here */

  over->Mi=Close_All_Mints(over->Mi);
  if((mint=New_Mint(over->Mi))==NULL) return(0);
  Initialize_Mint(mint,Cr[0]->A,Cr[1]->A);
  mint->I=VequalV(Cr[0]->I[0]);
  over->Mi=mint;
  if((mint=New_Mint(over->Mi))==NULL) return(0);
  Initialize_Mint(mint,Cr[0]->A,Cr[1]->A);
  mint->I=VequalV(Cr[0]->I[1]);
  over->Mi=mint;

/* end of new addition 6/12/95 */

  over->G=SxV(0.5L,Vsum(Cr[0]->I[0],Cr[0]->I[1]));
  Cr[0]->delta=seperate(over->G,V[0]);
  Cr[1]->delta=seperate(over->G,V[1]);
  Cr[0]->mode=A_NORMAL;
  Cr[1]->mode=A_NORMAL;
  gap=Cr[0]->delta+Cr[1]->delta-seperate(V[0],V[1]);
  if((gap>0.0)&&!(Small(gap)))  /* case where theta is greater than PI */
  {
    if(Cr[0]->deltadelta) Cr[0]->mode|=A_NEGS;
    else Cr[1]->mode|=A_NEGS;
  }
  Calculate_Circle_Intersept_Angles(Cr[0],&over->G,&V[0]);
  Calculate_Circle_Intersept_Angles(Cr[1],&over->G,&V[1]);
  return(0);
}

/**************************************************************************/

void Get_Circle_Mode(Circ *circ, Vector G)
{
  Vector V={0.0,0.0,0.0};                  /* vector to intersept average */
  double dAG=0.0;                          /* distance between A and G    */
  double dAV=0.0;                          /* distance between A and V    */
  double aVG=0.0;                          /* angle between AG and AV     */

/* work out whether circle is +ve or -ve                                  */

  V=SxV(0.5,Vsum(circ->I[0],circ->I[1]));
  dAG=seperate(circ->A->tv,G);
  dAV=seperate(circ->A->tv,V);
  if(dAG>dAV)
  {
    aVG=VangleV(Vdif(V,circ->A->tv),Vdif(G,circ->A->tv));
                                               /* angle between AV and AG */
    aVG=cos(aVG);
    if((!AlmostZero(aVG))&&(aVG>0.0)&&(dAG>dAV/aVG)) circ->mode|=A_NEGS;
  }
}

/**************************************************************************/

void Setup_Two_Circles(Pover *over, Atms *A[MAX_OVER], char mode)
{
  Atms *at[2]={NULL,NULL};

  while(mode)
  {
    switch(mode)
    {
      case FIRST :
        at[0]=A[0];
        Make_Circles(over,at,1);
        over->G=VequalV(A[0]->tv);
        mode=0;
        break;
      case SECOND : 
        at[0]=A[1];
        Make_Circles(over,at,1);
        over->G=VequalV(A[1]->tv);
        mode=0;
        break;
      case BOTH : 
        Make_Circles(over,A,2);
        switch(Find_2atom_G_P(over))
        {
          case 0 : mode=0; break;        /* normal */
          case 1 : mode=FIRST;  break;   /* FIRST  */
          case 2 : mode=SECOND; break;   /* SECOND */
          default: mode=0; break;
        }
        break;
      default : mode=0; break;
    }
  }
}

/**************************************************************************/
/**************************************************************************/
/******************  area calculations  ****************************/
/**************************************************************************/
/**************************************************************************/

double Single_Atom_Area(Atms *A, unsigned mode)
{
  double area;
  char line[LINELEN];
  area=PI*A->tradius*A->tradius;
  if(mode&VIS_BIT)
  {
    sprintf(line,"single(%s[%d]): [%f]",A->name,Get_Atom_Number(A),area);
    Out_Message(line,O_BLANK);
  }
  return(area);
}

/**************************************************************************/
/******************  single atom calculations  ****************************/
/**************************************************************************/

double Get_All_Single_Areas(Mol *M, unsigned mode)
{
  int count=0;
  double area=0.0;
  Atms *A=NULL;
  char line[LINELEN];

  for(A=M->atoms,count=0;A!=NULL;A=A->next)
  {
    count++; if(count>M->num_atoms) Error_Message(E_ATMNUM,"Get All Single Areas");
    if(A->stat&CALC_BIT)
    {
      if(mode&VIS_BIT) Out_Message("+ ",O_BLANK);
      area+=Single_Atom_Area(A,mode);
      if(mode&VIS_BIT)
      {
        sprintf(line,"= %f",area);
        Out_Message(line,O_NEWLN);
      }
      A->count=1;
    }
    else A->count=0;
  }
  return(area);
}

/**************************************************************************/
/****************  two atom overlap calculation  **************************/
/**************************************************************************/

double Double_Poverlap_Area(Pover *over, unsigned mode)
{
  double totgamma=0.0;
  double area=0.0;
  char line[150];
  Circ *cr=NULL;

/* check for excessively large theta range                                  */

  for(cr=First_Circ(over->Cr);cr!=NULL;cr=cr->next) totgamma+=cr->gamma;
  totgamma-=2.0*PI;
  if(!AlmostZero(totgamma))
  {
    if(mode&VIS_BIT)
    {
      sprintf(line,"Double Poverlap Area [%7.4f]",totgamma);
      Error_Message(E_GNOTPI,line);
    }
  }

/* calculate areas                                                        */

  for(cr=First_Circ(over->Cr);cr!=NULL;cr=cr->next)
  {
    if(cr->mode&A_IGNORE) continue;
    area+= 0.5 * cr->radius * (cr->theta * cr->radius
               - cr->delta * (sin(cr->phi) + sin(cr->theta-cr->phi)));
  }

/* display answers if in normal total calculation                         */

  if(mode&VIS_BIT)
  {
    if((cr=Goto_Circ(over->Cr,1))==NULL) Error_Message(E_BDCIRC,"Double Poverlap Area");
    else
    {
      sprintf(line,"double(%s[%d]",cr->A->name,Get_Atom_Number(cr->A));
      Out_Message(line,O_BLANK);
    }
    if((cr=Goto_Circ(over->Cr,2))==NULL) Error_Message(E_BDCIRC,"Double Poverlap Area");
    else
    {
      sprintf(line,"-%s[%d]):[%f] ",cr->A->name,Get_Atom_Number(cr->A),area);
      Out_Message(line,O_BLANK);
    }
  }

  if(area<0.0)
  {
    Error_Message(E_NEGARE,"Double Poverlap Area");
    return(0.0);
  }
  return(area);
}

/**************************************************************************/

double Remove_All_Double_Poverlaps(Mol *M, Pover **current
                               ,unsigned mode, double area)
{
  int count,i;
  Pover *new=NULL;
  Pover *over=NULL;
  double delta=0.0;
  Atms *A[MAX_OVER];
  char line[LINELEN];

  for(i=0;iatoms,count=0;A[0]!=NULL;A[0]=A[0]->next)
  {
    count++; if(count>M->num_atoms) Error_Message(E_ATMNUM,"Remove All Double Poverlaps");
    if((!AlmostZero(A[0]->tradius))&&(A[0]->stat&CALC_BIT))
    {                                     /* count A[1] though whole list */
      for(A[1]=A[0]->next,i=0;A[1]!=NULL;A[1]=A[1]->next)
      {
        i++; if(i>M->num_atoms) Error_Message(E_ATMNUM,"Remove All Double Poverlaps");
        if ((A[0]!=A[1])&&(!AlmostZero(A[1]->tradius))&&(A[1]->stat&CALC_BIT))
        {
          delta=deltaAB(A[0],A[1]);
          if (delta<(A[0]->tradius+A[1]->tradius))
          {                           /* A[0]-A[1] steric overlap found   */
            if((new=New_Pover(over))!=NULL)
            {
              over=new;          /* create the memory for counted doubles */
              Initialize_Pover(over,2);
              if(mode&VIS_BIT) Out_Message("- ",O_BLANK);
              if (delta<=fabs(A[0]->tradius-A[1]->tradius))
              {                                   /* total overlap found  */
                Error_Message(E_UNSING,"Remove All Double Poverlaps");
                if(mode&VIS_BIT) Out_Message("- ",O_BLANK);
                if (A[0]->tradius>=A[1]->tradius)
                {                                   /* A[0] overlaps A[1] */
                  Setup_Two_Circles(over,A,SECOND);
                  area-=Single_Atom_Area(A[1],mode);
                }
                else
                {                                   /* A[1] overlaps A[0] */
                  Setup_Two_Circles(over,A,FIRST);
                  area-=Single_Atom_Area(A[0],mode);
                }
                if(mode&VIS_BIT)
                {
                  sprintf(line,"= %f",area);
                  Out_Message(line,O_NEWLN);
                }
              }
              else                               /* partial overlap found */
              {
                Setup_Two_Circles(over,A,BOTH);
                area-=Double_Poverlap_Area(over,mode);
                if(mode&VIS_BIT)
                {
                  sprintf(line,"= %f",area);
                  Out_Message(line,O_NEWLN);
                }
              }
            }
          }
        }
      }
    }
  }
  *current=over;
  return(area);
}

/**************************************************************************/
/**************************************************************************/
/****************  multiple atom overlap calculation  *********************/
/**************************************************************************/
/**************************************************************************/

/**************************************************************************/
/** test for case where one atom is enveloped by another atom            **/

int Inside_Atom_P(Atms *A, Atms *B)
{
  double dAB, dR;
  if(A==B) return(1);
  dAB=deltaAB(A,B);
  dR=B->tradius-A->tradius;
  if(dAB<=dR) return(1);
  if((AlmostZero(dAB))&&(AlmostZero(dR))) return(1);
  return(0);
}

/**************************************************************************/
/** test for that atom is not enveloped by any other atom                **/

int Outside_All_Atoms_P(Atms *A)
{
  Atms *atoms;
  if(A==NULL) return(0);
  for(atoms=First_Atom(A);atoms!=NULL;atoms=atoms->next)
  {
    if(atoms==A) atoms=atoms->next;
    if(atoms==NULL) break;
    if(!atoms->stat&CALC_BIT) continue;
    if(Inside_Atom_P(A,atoms)) return(0);
  }
  return(1);
}

/**************************************************************************/
/** test for case where overlap region in entirely within an atom        **/

int Atom_Covers_Poverlap(Atms *A, Pover *O)
{
  Circ *cr=NULL;
  for(cr=First_Circ(O->Cr);cr!=NULL;cr=cr->next)
  {
    if(seperate(cr->I[0],A->tv)>A->tradius) return(0);
    if(seperate(cr->I[1],A->tv)>A->tradius) return(0);
  }
  return(1);
}

/**************************************************************************/
/* find overlap region that doesn't involve specified atom               **/

int Find_Pover_Without_Atom(Pover *po[MAX_OVER], Atms *at, int o[2]
                          ,int order, int start)
{
  int i,a;
  Circ *cr=NULL;
  
  for(i=start;iCr);cr!=NULL;cr=cr->next)
    {                                                  /* find extra atom */
      if(at==cr->A) a++;
    }
    if(a>1) return(0);                       /* found same atom twice ??  */
    if(a==0)
    {
      if(at==NULL) return(0);
      else
      {
        o[1]=i;                                             /* found it ! */
        return(1);
      }
    }
  }
  return(0);
}
/**************************************************************************/
/* swap positions of two pointers to overs in the array po                */

void Swap_Povers(Pover *po[MAX_OVER], int o[2])
{
  Pover *temp;
  temp=po[o[1]];
  po[o[1]]=po[o[0]];
  po[o[0]]=temp;
}

/**************************************************************************/
/* Remove redundant intersepts                                            */

Mint *Clean_Mints(Mint *mint, Atms *A[MAX_OVER], int order)
{
  Mint *mi=NULL;
  Mint *mp=NULL;
  int i;
  double sep=0.0;

/* check that all intersepts are within every atom */
  
  for(mi=First_Mint(mint);mi!=NULL;)
  {
    for(i=0;itv,mi->I)-A[i]->tradius)>0.0)
       &&(!AlmostZero(sep))) break;
    if(iprev==NULL) mi=mint;
      else mi=mint->next;
    }
    else mi=mi->next;
  }

/* check for redundant intersepts */

  for(mi=First_Mint(mint);mi!=NULL;mi=mi->next)
  {
    for(mp=mi->next;mp!=NULL;)
    {
      if((((mp->A[0]==mi->A[0])&&(mp->A[1]==mi->A[1]))
        ||((mp->A[0]==mi->A[1])&&(mp->A[1]==mi->A[0])))
       &&(AlmostZero(seperate(mp->I,mi->I))))     /* identical intersepts */
      {
        mint=Close_Mint(mp);
        if(mint==NULL) break;
        else mp=mint->next;
      }
      else mp=mp->next;
    }
    if(mint==NULL) break;
  }
  return(mint);
}

/**************************************************************************/
/* Sort the mints to facilitate multi atom feature                        */

Mint *Sort_Mints(Mint *mint)
{
  Mint *m=NULL;
  Mint *new=NULL;
  Mint *smallest=NULL;
  double mag, cosphi, sinphi;

  for(m=First_Mint(mint);m!=NULL;m=m->next)
  {
    mag=Vmag(m->I);
    cosphi=m->I.x/mag;
    sinphi=m->I.y/mag;
    m->phi=arcCos(cosphi);
    if(sinphi<0.0) m->phi=2*PI-m->phi;
  }
  while(mint!=NULL)
  {
    for(m=First_Mint(mint);m!=NULL;m=m->next)
    {
      if(smallest==NULL) smallest=m;
      else if(smallest->phi>m->phi) smallest=m;
    }
    if(smallest==NULL) break;
    if(mint==smallest)
    {
      if(smallest->prev!=NULL) mint=smallest->prev;
      else if(smallest->next!=NULL) mint=smallest->next;
      else mint=NULL;
    }
    if(smallest->next!=NULL) smallest->next->prev=smallest->prev;
    if(smallest->prev!=NULL) smallest->prev->next=smallest->next;
    smallest->next=NULL;
    smallest->prev=NULL;
    if(new==NULL) new=smallest;
    else
    {
      new->next=smallest;
      smallest->prev=new;
      new=smallest;
    }
    smallest=NULL;
  }
  return(new);
}

/**************************************************************************/
/* Sort the circles, determining their intersepts and there modes         */

int Sort_Circles_Using_Mints(Pover *over)
{
  int i,n,a,numseg=0;
  Circ *cr=NULL, *multi=NULL, *new=NULL;
  Mint *m[2]={NULL,NULL};
  Atms *com[2]={NULL,NULL};
  
  for(cr=First_Circ(over->Cr);cr!=NULL;cr=cr->next)
  {
    a=0;
    cr->mode=A_NORMAL;
    for(m[0]=First_Mint(over->Mi);m[0]!=NULL;m[0]=m[0]->next)
    {
      i=-1;
      if(m[0]->A[0]==cr->A) { i=0; n=1; }
      if(m[0]->A[1]==cr->A) { i=1; n=0; }
      if(i<0) continue;
      if(a<2) cr->I[a]=VequalV(m[0]->I);
      a++;
    }
    switch(a)
    {
      case 0 :                    /* multi atom situation on another atom */
        cr->mode=A_IGNORE;
        break;
      case 1 : 
        Error_Message(E_BDCIRC,"Sort Circles Using Mints");
        cr->mode=A_IGNORE;
        break;
      case 2 : break;    /* normal situation each atom has two intersepts */
      default:
        if((a/2)*2!=a)        /* should be multiple of two for multi atom */
        {
          Error_Message(E_BDCIRC,"Sort Circles Using Mints");
          cr->mode=A_IGNORE;
          break;
        }
        if(multi!=NULL)                  /* should be only one multi atom */
        {
          Error_Message(E_BDCIRC,"Sort Circles Using Mints");
          cr->mode=A_IGNORE;
          break;
        }
        numseg=a;
        multi=cr;
        cr->mode|=A_MULTI;
        break;
    }
    Get_Circle_Mode(cr,over->G);
  }

  /* deal with multi atom circle */
  
  if(multi!=NULL)
  {
    over->Mi=Sort_Mints(over->Mi);
    for(m[0]=First_Mint(over->Mi);m[0]!=NULL;m[0]=m[0]->next)
    {
      com[0]=NULL;
      com[1]=NULL;
      if(m[0]->next!=NULL) m[1]=m[0]->next;
      else m[1]=First_Mint(over->Mi);
      if((m[0]->A[0]==m[1]->A[0])
       ||(m[0]->A[0]==m[1]->A[1])) com[0]=m[0]->A[0];
      if((m[0]->A[1]==m[1]->A[0])
       ||(m[0]->A[1]==m[1]->A[1])) com[1]=m[0]->A[1];

      if((com[0]==NULL)&&(com[1]==NULL))
      {
        Error_Message(E_BDMINT,"Sort Circles Using Mints");
        continue;
      }
      if((com[0]!=NULL)&&(com[1]!=NULL)) continue;
      if((com[0]!=NULL)&&(com[1]==NULL)) i=0;
      if((com[0]==NULL)&&(com[1]!=NULL)) i=1;
      if(com[i]!=multi->A) Error_Message(E_BDMINT,"Sort Circles Using Mints");

      if((new=New_Circ(over->Cr))==NULL) break;
      Initialize_Circle(new,multi->A);
      new->I[0]=VequalV(m[0]->I);
      new->I[1]=VequalV(m[1]->I);
      new->mode=A_NORMAL|A_TEMP;
      over->Cr=new;
    }
  }
  
  /* count number of usable circles and calculate their info */

  for(i=0,cr=First_Circ(over->Cr);cr!=NULL;cr=cr->next)
  {
    if(cr->mode==A_IGNORE) continue;
    i++;
    cr->delta=seperate(cr->A->tv,over->G);
    if(!(cr->mode&A_MULTI)) Calculate_Circle_Intersept_Angles(cr,&over->G,&cr->A->tv);
  }
  over->ncir=i;
  return(over->ncir);
}

/**************************************************************************/
/* order the n* "(n-1) overlaps" to facilitate discovery of nth overlap   */

int Order_Previous_Poverlaps(Pover *po[MAX_OVER], Atms *at[MAX_OVER], int order)
{
  Atms *atom=NULL;
  Circ *cr=NULL;
  int i,o[2],a=0;
  
  if(order<3) return(0);             /* only triple or greater considered */
  for(i=0;iCr);(inext,i++)
  {                                      /* map po[0] to last (n-1) atoms */
    at[i]=cr->A;
    if(at[i]==NULL) return(0);
  }                                 /* find appropriate overlap for at[1] */
  if(!Find_Pover_Without_Atom(po,at[1],o,order,1)) return(0);
  o[0]=1;
  Swap_Povers(po,o);                             /* swap over 1 and o[1]  */
  for(cr=First_Circ(po[1]->Cr);cr!=NULL;cr=cr->next)
  {                                                    /* find extra atom */
    a=0;
    atom=cr->A;
    if(atom==NULL) return(0);
    if(at[1]==atom) return(0);        /* Find_Pover_Without_Atom() failed */
    for(i=2;i1) return(0);                       /* found same atom twice ??  */
    if(a==0)
    {
      if(at[0]==NULL) at[0]=atom;
      else return(0);                               /* two unknowns found */
    }
  }
                                        /* order the rest of the overlaps */  
  for(i=2;iCr);cr!=NULL;cr=cr->next)
    {
      for(a=0;aA==at[a]) break;
      if(a==order) return(0);
    }
  }
  
  return(1);
}

/**************************************************************************/
/* find the correct atomic intersepts for particular pair of atoms        */

int Find_Atomic_Intersepts_P(Pover *dover, Atms *A[MAX_OVER],
                             int a, int b,
                             Vector I[2], int inter[2])
{
  int i;
  double delta;
  Circ *dCr[2]={NULL,NULL};

  I[0]=Vequal(0.0,0.0,0.0);
  I[1]=Vequal(0.0,0.0,0.0);
  inter[0]=0;
  inter[1]=0;
  
  for(dover=First_Pover(dover);dover!=NULL;dover=dover->next)
  {                                                    /* find ab overlap */
    if(((dCr[0]=Goto_Circ(dover->Cr,1))==NULL)
     ||((dCr[1]=Goto_Circ(dover->Cr,2))==NULL)
     ||(dCr[0]->A==NULL)||(dCr[1]->A==NULL))
      return(Error_Message(E_BDCIRC,"Find Atomic Intersepts P"));
    if(((dCr[0]->A==A[a])&&(dCr[1]->A==A[b]))
     ||((dCr[1]->A==A[a])&&(dCr[0]->A==A[b])))
    {
      inter[0]=1;      /* check that both intersepts are within all atoms */
      inter[1]=1;
      for(i=0;((iI[0],A[i]->tv)-A[i]->tradius;
        if((delta>0.0)&&(!AlmostZero(delta))) inter[0]=0;
        delta=seperate(dCr[0]->I[1],A[i]->tv)-A[i]->tradius;
        if((delta>0.0)&&(!AlmostZero(delta))) inter[1]=0;
      }
      if(inter[0]) I[0]=VequalV(dCr[0]->I[0]);
      if(inter[1]) I[1]=VequalV(dCr[0]->I[1]);
      return(1);
    }
  }
  return(0);
}

/**************************************************************************/
/* determine the nature and parameters of the new nth order overlap       */

int Get_All_Relevant_Intersept_Vectors(Pover *over, int order,
                                       Pover *O[MAX_OVER], Atms *A[MAX_OVER])
{
  int i=0;
  Mint *mint=NULL;
  Mint *new=NULL;

  for(i=0;iMi);mint!=NULL;mint=mint->next)
    {
      if((new=New_Mint(over->Mi))==NULL) return(0);
      Copy_Mint(new,mint);
      over->Mi=new;
    }
  }

  if((over->Mi=Clean_Mints(over->Mi,A,order))==NULL) return(0);

/* calculate G as average of intersept vectors */

  over->G=Vequal(0.0,0.0,0.0);
  for(i=0,mint=First_Mint(over->Mi);mint!=NULL;mint=mint->next,i++)
    over->G=Vsum(over->G,mint->I);
  over->G=SxV(1.0/(double)i,over->G);

  if(!Sort_Circles_Using_Mints(over)) return(0);

  return(1);
}

/**************************************************************************/
/* determine the nature and parameters of the new nth order overlap       */

Pover *New_Multiple_Poverlap(Pover *over, int order
                          ,Pover *O[MAX_OVER], Atms *A[MAX_OVER])
{
  int i=0;
  Circ *cr=NULL;

  for(i=0;iCr))==NULL) return(Close_Current_Pover(over));
    over->Cr=cr;
    Initialize_Circle(cr,A[i]);
  }

  if(!Get_All_Relevant_Intersept_Vectors(over,order,O,A))
    return(Close_Current_Pover(over));
  
  return(over);
}

/**************************************************************************/
/* perform the necessary calculation on the new nth order overlap         */

double Multiple_Poverlap_Area(Pover *over, int order, unsigned mode)
{
  double totgamma=0.0;
  double area=0.0;
  double multi_area=0.0;                   /* extra area for A_GCENT mode */
  char line[LINELEN];
  Circ *cr=NULL;
#ifdef DEBUG
  char type[LINELEN];
  type[0]=0;
#endif

/* check for excessively large theta range                                  */

  for(cr=First_Circ(over->Cr);cr!=NULL;cr=cr->next)
    totgamma+=cr->gamma;
  totgamma-=2.0*PI;
  if(!AlmostZero(totgamma))
  {
    if(mode&VIS_BIT)
    {
      sprintf(line,"Multiple Poverlap Area [%7.4f]",totgamma);
      Error_Message(E_GNOTPI,line);
    }
  }

/* calculate area from each of the circles present                        */

  for(cr=First_Circ(over->Cr);cr!=NULL;cr=cr->next)
  {
    if(cr->mode&A_IGNORE) continue;
    if(cr->mode&A_MULTI) continue;
#ifdef DEBUG
    if(cr->mode&A_TEMP) strcat(type,"|m|");
    else if(cr->mode&A_GCENT) strcat(type,"|c|");
    else strcat(type,"|n|");
#endif
    if(cr->mode&A_GCENT)
      multi_area=cr->theta/(2*PI)*Single_Atom_Area(cr->A,0);
    else
      area+= 0.5 * cr->radius * (cr->theta * cr->radius
                 - cr->delta * (sin(cr->phi) + sin(cr->theta-cr->phi)));
  }

/* display answers if in normal total calculation                         */

  if(mode&VIS_BIT)
  {
    sprintf(line,"[%f] ",area);
#ifdef DEBUG
    strcat(line,type);
#endif
    Out_Message(line,O_BLANK);
  }

  if(area<0.0)
  {
    Error_Message(E_NEGARE,"Multiple Poverlap Area");
    return(0.0);
  }
  return(area);
}

/**************************************************************************/
/* find nth order overlap and calculate the relevant area                 */

double Calc_Multiple_Poverlap(Pover *po[MAX_OVER], Pover **over,
                              int order, unsigned mode,
                              char *multiple, double area)
{
  Pover *new=NULL;
  char line[LINELEN];
  char atmstr[25];
  char atomsline[LINELEN];
  Atms *A[MAX_OVER];
  Pover *O[MAX_OVER];
  int i;
  short sign=1;
  
  /* initialize */
  
  if(order/2*2==order) sign=1; else sign=-1;
  for(i=0;iname,Get_Atom_Number(A[i]));
          strcat(atomsline,atmstr);
        }
        atomsline[strlen(atomsline)-1]=0;
        if(sign>0) sprintf(line,"+ %s[%d](%s) ",multiple,new->ncir,atomsline);
        else sprintf(line,"- %s[%d](%s) ",multiple,new->ncir,atomsline);
        Out_Message(line,O_BLANK);
      }
      if(new->area==0.0) 
        area+=sign*Multiple_Poverlap_Area(new,new->ncir,mode);
      else area+=sign*new->area;
      if(mode&VIS_BIT)
      {
        sprintf(line,"= %f",area);
        Out_Message(line,O_NEWLN);
      }
    }
  }
  return(area);
}

/**************************************************************************/
/******* recursive routine to search possible (n-1) combinations **********/
/**************************************************************************/

double Multiple_Poverlap(Pover *pover, Pover **over,
                         int order, int level, unsigned mode,
                         char *multiple, double area)
{
  static Pover *po[MAX_OVER];
  int i;

  if(pover==NULL) return(area);               /* miss call               */
  if(level==0)                                 /* initialize              */
  {
    while(pover->prev!=NULL) pover=pover->prev;
    for(i=0;iorder)
  {
    Error_Message(E_LEVHI,"Multiple Poverlap");
    return(area);                             /* miss call               */
  }
  if(pover->order!=order)
  {
    Error_Message(E_BADORD,"Multiple Poverlap");
    return(area);                             /* miss call               */
  }
  
  for(po[level]=pover;po[level]!=NULL;pover=pover->next,po[level]=pover)
  {
    if(levelnext,over,order,1+level,mode,multiple,area);
    }
    else                                       /* final depth, calculate  */
    {
      area=Calc_Multiple_Poverlap(po,over,order,mode,multiple,area);
    }
  }
  return(area);
}

/**************************************************************************/
/**************************************************************************/
/******  Main Counting algorithm to look for all steric overlaps  *********/
/**************************************************************************/
/**************************************************************************/

double New_Craig_Counting_P(Mol *M, unsigned mode)
{
  Pover *over[MAX_OVER];
  char multiple[10][MAX_OVER];
  double area=0.0;
  char line[LINELEN];
  Atms *at=NULL;
  int i=0;
#ifdef DEBUG
  Pover *o=NULL;
  Circ *c=NULL;
  int numo, numc;
#endif
  
  if(M->multi>MAX_OVER) M->multi=MAX_OVER;
  for(i=0;imulti;i++)
  {
    over[i]=NULL;
    switch(i+1)
    {
      case 2  : strcpy(multiple[i],"double"); break;
      case 3  : strcpy(multiple[i],"triple"); break;
      case 4  : strcpy(multiple[i],"quadruple"); break;
      case 5  : strcpy(multiple[i],"quintuple"); break;
      case 6  : strcpy(multiple[i],"sextuple"); break;
      case 7  : strcpy(multiple[i],"septuple"); break;
      case 8  : strcpy(multiple[i],"octuple"); break;
      case 9  : strcpy(multiple[i],"nonuple"); break;
      case 10 : strcpy(multiple[i],"dectuple"); break;
      default : sprintf(multiple[i],"order=%d",i+1); break;
    }
  }
  M->atoms=First_Atom(M->atoms);        /* start main loops at first atom */

/****************** ignore all fully overlapped atoms *********************/
   
  for(at=M->atoms;at!=NULL;at=at->next)
    if(at->stat&MAIN_BIT) at->stat=at->stat|CALC_BIT;
  for(at=M->atoms;at!=NULL;at=at->next)
  {
    if((at->stat&MAIN_BIT)&&(Outside_All_Atoms_P(at)))
    at->stat=at->stat|CALC_BIT; else at->stat=at->stat&(FULL_BIT^CALC_BIT);
  }

/****************** add all single atom areas *****************************/

  if(mode&VIS_BIT) Out_Message("Calculating all single atom projected areas",O_NEWLN);
  area=Get_All_Single_Areas(M,mode);

/****************** remove all double atom overlaps ***********************/

  if(mode&VIS_BIT) Out_Message("Removing all double overlaps",O_NEWLN);
  area=Remove_All_Double_Poverlaps(M,&over[1],mode,area);

#ifdef DEBUG
  for(numo=1,o=First_Pover(over[1]);o!=NULL;o=o->next,numo++)
  {
    for(numc=1,c=First_Circ(o->Cr);c!=NULL;c=c->next,numc++)
    {
      c->num=numc;
    }
    o->num=numo;
  }
#endif

/****************** add/subtract all higher order overlaps ****************/

  for(i=2;imulti;i++)
  {
    if(mode&VIS_BIT)
    { 
      if(i/2*2==i) sprintf(line,"Adding all %s overlaps",multiple[i]);
      else sprintf(line,"Removing all %s overlaps",multiple[i]);
      Out_Message(line,O_NEWLN);
    }
    area=Multiple_Poverlap(over[i-1],&over[i],i,0,mode,multiple[i],area);
    if(over[i]==NULL) break;
#ifdef DEBUG
    for(numo=1,o=First_Pover(over[i]);o!=NULL;o=o->next,numo++)
    {
      for(numc=1,c=First_Circ(o->Cr);c!=NULL;c=c->next,numc++)
      {
        c->num=numc;
      }
      o->num=numo;
    }
#endif
  }

/**************************** finish off **********************************/

  for(i=1;imulti;i++) Close_All_Poverlaps(over[i],multiple[i],mode);
   
  if (area<0.0)  { Error_Message(E_ATOSML,"New Craig Counting P"); area=0.0; }
  return(area);
}

/**************************************************************************/
/******************  The End ...  *****************************************/
/**************************************************************************/

Modified: Fri Dec 8 17:00:00 1995 GMT
Page accessed 1212 times since Sat Apr 17 22:00:04 1999 GMT