CCL Home Page
Up Directory CCL crystal.c
/**************************************************************************/
/**************************************************************************/
/**************************   "steric"   **********************************/
/**************************************************************************/
/*************     Program to calculate ligand cone    ********************/
/*************     angles as a measure of steric size  ********************/
/**************************************************************************/
/**************************************************************************/

/**************************************************************************/
/******************  Atom manipulation functions **************************/
/**************************************************************************/
/******************        This module is        **************************/
/******************      system independant      **************************/
/**************************************************************************/

#include 
#include 
#include 
#include 

#include "sterdefn.h"      /* declaration of structures and globals       */
#include "stercomm.h"      /* definitions of all menu command options     */
#include "crystal.h"       /* functions for all file manipulations        */
#include "stermem.h"       /* dynamic memory management module            */
#include "stercalc.h"      /* main calculation routines                   */
#include "sterfile.h"      /* functions for all file manipulations        */
#include "stertext.h"      /* all text functions for text mode            */
#include "stergrp.h"       /* group manipulation functions                */
#include "steraid.h"       /* additional functions needed                 */

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

int Initialize_Symmetry(Symm *symm, char *S, Matrix M, Vector t, unsigned type)
{
  strncpy(symm->S,S,SYM_LEN);
  symm->M.x=VequalV(M.x);
  symm->M.y=VequalV(M.y);
  symm->M.z=VequalV(M.z);
  symm->t=VequalV(t);
  symm->mode=0;
  switch(type)
  {
    case S_NORM : symm->mode=0; break;
    case S_CENT : symm->mode|=CENT_BIT; break;
    default     : break;
  }
  return(1);
}

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

int Copy_Atom(Atms *A, Atms *B)
{
  strcpy(A->name,B->name);
  strcpy(A->type,B->type);
  A->v=VequalV(B->v);
  A->fv=VequalV(B->fv);
  A->distance=B->distance;
  A->theta=B->theta;
  A->phi=B->phi;
  A->radius=B->radius;
  A->SVangle=B->SVangle;
  A->stat=B->stat;
  return(1);
/* next and prev pointers have already been assigned, do not fiddle !!!   */
}

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

int Identity_Operator(Symm *symm)
{
  if(Vcmp(symm->M.x,Vequal(1.0,0.0,0.0))) return(0);
  if(Vcmp(symm->M.y,Vequal(0.0,1.0,0.0))) return(0);
  if(Vcmp(symm->M.z,Vequal(0.0,0.0,1.0))) return(0);
  if(Vcmp(symm->t,  Vequal(0.0,0.0,0.0))) return(0);
  return(1);
}

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

int Convert_to_Cartesian(Mol *M)
{
  double cral, crbe, crga, srga;
  double r,p,pa,qa;
  double cab,cac,cbb,cbc,ccc;
  Atms *A=NULL;
  
  if(M==NULL)
  {
    Error_Message(E_NOMOL,"Convert_to_Cartesian");
    return(0);
  }
  cral=cos(Radians(M->al));
  crbe=cos(Radians(M->be));
  crga=cos(Radians(M->ga));
  srga=sin(Radians(M->ga));
  pa = crbe * crga;
  r = (cral - pa) / srga;
  p = crbe;
  qa = sqrt((double)1. - p * p - r * r);
  cab = M->b * crga;
  cac = M->c * crbe;
  cbb = M->b * srga;
  cbc = M->c * r;
  ccc = M->c * qa;
  for(A=First_Atom(M->atoms);A!=NULL;A=A->next)
  {
    A->v.x = A->fv.x * M->a + A->fv.y * cab + A->fv.z * cac;
    A->v.y = A->fv.y * cbb  + A->fv.z * cbc;
    A->v.z = A->fv.z * ccc;
  }
  return(1);
}

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

int Create_Unit_Cell_Atoms(Mol *M)
{
  Atms *atom=NULL;
  Atms *new=NULL;
  int i;

  if(M==NULL) return(0);
  atom=Last_Atom(M->atoms);
  for(i=0;i<8;i++)
  {
    if((new=New_Atom(atom))==NULL) return(0);
    atom=new;
    M->num_atoms++;
    Initialize_Atom(atom);
    sprintf(atom->name,"A%d",i);
    sprintf(atom->type,"A");
    atom->group=FULL_BIT;
    atom->stat|=GRP_BIT;
    switch(i)
    {
      case 0  : atom->fv=Vequal(0.0,0.0,0.0); break;
      case 1  : atom->fv=Vequal(1.0,0.0,0.0); break;
      case 2  : atom->fv=Vequal(0.0,1.0,0.0); break;
      case 3  : atom->fv=Vequal(0.0,0.0,1.0); break;
      case 4  : atom->fv=Vequal(0.0,1.0,1.0); break;
      case 5  : atom->fv=Vequal(1.0,0.0,1.0); break;
      case 6  : atom->fv=Vequal(1.0,1.0,0.0); break;
      case 7  : atom->fv=Vequal(1.0,1.0,1.0); break;
      default : break;
    }
  }
  return(1);
}

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

int Remove_Duplicate_Atoms(Mol *M, Set *set)
{
  Atms *A=NULL;
  Atms *B=NULL;
  Grps *group=NULL;
  int i,n;
  char line[LINELEN];
  
  if(M==NULL) return(0);
  if((A=First_Atom(M->atoms))==NULL) return(0);
  
  while(A!=NULL)
  {
    B=A->next;
    while(B!=NULL)
    {
      if((A!=B)
       &&((!(set->modev&SNAM_BIT))||(strcmp(A->name,B->name)==0))
       &&(strcmp(A->type,B->type)==0)
       &&(!Vcmp(A->fv,B->fv)))
      {
        sprintf(line,"Removing duplicate atom %s",A->name);
        Out_Message(line,O_NEWLN);
        B=Close_Atom(B);
      }
      if(B!=NULL) B=B->next;
    }
    A=A->next;
  }
  for(i=0,A=First_Atom(M->atoms);A!=NULL;A=A->next,i++);
  M->num_atoms=i;
  for(group=First_Group(M->groups);group!=NULL;group=group->next)
  {
    n=Get_Group_Number(group);
    for(i=0,A=First_Atom(M->atoms);A!=NULL;A=A->next)
    {
      if(A->group==n) i++;
    }
    group->num_atoms=i;
  }
  return(1);
}

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

/* void Add_New_Bond(Atms *atomA, Atms *atomB, short unsigned type) */
/* double Get_Atomic_Radius(int bonds, char *name, Parm *parm, unsigned mode) */

int Find_All_Bonds(Mol *M, Set *set, int gnum, unsigned mode)
{
  Atms *A=NULL;
  Atms *B=NULL;
  double rA,rB,rD;
  char line[LINELEN];
  int num=0;

  if(M==NULL) return(0);
  if(M->atoms==NULL) return(0);
  for(A=First_Atom(M->atoms);A!=NULL;A=A->next)
  {
    if((gnum!=0)&&(A->group!=gnum)) continue;
    rA=Get_Atomic_Radius(0,A->type,set->parm,CVL_BIT);
    for(B=A->next;B!=NULL;B=B->next)
    {
      if((gnum!=0)&&(B->group!=gnum)) continue;
      rB=Get_Atomic_Radius(0,B->type,set->parm,CVL_BIT);
      rD=Vmag(Vdif(A->v,B->v));
      if((((double)set->bond_minf*rA)+((double)set->bond_minf*rB)bond_maxf*rA)+((double)set->bond_maxf*rB)>rD))
      {
        Add_New_Bond(A,B,SINGLE_B);
        if(mode&VIS_BIT)
        {
          sprintf(line,"Atom %s (r=%4.2f) bonded to atom %s (r=%4.2f), with %8.4f seperation)"
                      ,A->name,rA,B->name,rB,rD);
          Out_Message(line,O_NEWLN);
        }
        num++;
      }
    }
  }
  if(num)
  {
    sprintf(line,"%d individual bonds were found in %s",num,M->name);
    Out_Message(line,O_NEWLN);
  }
  return(1);
}

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

int Perform_Symmetry(Mol *M, Symm *S)
{
  Atms *A=NULL;
  if(M==NULL) return(0);
  if(S==NULL) return(0);
  for(A=First_Atom(M->atoms);A!=NULL;A=A->next)
  {
    A->fv=Mtransform(S->M,A->fv);
    A->fv=Vsum(S->t,A->fv);
  }
  return(1);
}

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

Atms *Merge_Atom_Lists(Atms *A, Atms *B)
{
  if(B==NULL) return(First_Atom(A));
  if(A==NULL) return(First_Atom(B));
  if(((A=Last_Atom(A))!=NULL)&&((B=First_Atom(B))!=NULL))
  {
    B->prev=A;
    A->next=B;
  }
  return(First_Atom(A));
}

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

Atms *New_Atom_Symmetry(Mol *M, Symm *S, Atms *B, char *string)
{
  Atms *A=NULL;
  char line[LINELEN];

  if(M==NULL) return(B);
  if(S==NULL) return(B);
  if(M->atoms==NULL) return(B);
  sprintf(line,"%sAdding atoms with symmetry:",string); Out_Message(line,O_NEWLN);
  sprintf(line,"%5.1f%5.1f%5.1f%8.3f",S->M.x.x,S->M.x.y,S->M.x.z,S->t.x); Out_Message(line,O_NEWLN);
  sprintf(line,"%5.1f%5.1f%5.1f%8.3f",S->M.y.x,S->M.y.y,S->M.y.z,S->t.y); Out_Message(line,O_NEWLN);
  sprintf(line,"%5.1f%5.1f%5.1f%8.3f",S->M.z.x,S->M.z.y,S->M.z.z,S->t.z); Out_Message(line,O_NEWLN);
  for(A=First_Atom(M->atoms);A!=NULL;A=A->next)
  {
    if(strcmp(A->type,"A")==0) continue;
    if((B=New_Atom(B))==NULL) break;
    Initialize_Atom(B);
    Copy_Atom(B,A);
    B->fv=Mtransform(S->M,B->fv);
    B->fv=Vsum(S->t,B->fv);
  }
  return(B);
}

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

int Get_Symmetry_Matrix(char *S, Matrix *M, Vector *t)
{
  int i,len;
  M->x=Vequal(1.0,0.0,0.0);
  M->y=Vequal(0.0,1.0,0.0);
  M->z=Vequal(0.0,0.0,1.0);
  *t=Vequal(0.0,0.0,0.0);
  len=strlen(S);
  for(i=0;i'9'))) return(0);
  if(sscanf(S,"%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf"
            ,&M->x.x,&M->x.y,&M->x.z,&t->x
            ,&M->y.x,&M->y.y,&M->y.z,&t->y
            ,&M->z.x,&M->z.y,&M->z.z,&t->z)<12) return(0);
  return(1);
}

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

int do_M(Matrix *M, int row, int col, int val)
{
  if(row==2)
  {
    if(col==2) M->z.z=val;
    else if(col==1) M->z.y=val;
    else M->z.x=val;
  }
  else if(row==1)
  {
    if(col==2) M->y.z=val;
    else if(col==1) M->y.y=val;
    else M->y.x=val;
  }
  else
  {
    if(col==2) M->x.z=val;
    else if(col==1) M->x.y=val;
    else M->x.x=val;
  }
  return(1);
}

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

double Get_Tval(char *S, int *i)
{
  double value=0.0;
  double div=1.0;
  char str[LINELEN];
  int n;
  
  for(n=*i;(((S[n]=='+')&&(S[n+1]<=57)&&(S[n+1]>=46))
          ||((S[n]=='-')&&(S[n+1]<=57)&&(S[n+1]>=46))
          ||((S[n]<=57)&&(S[n]>=46)));n++);
  strncpy(str,S+*i,n-*i);
  str[n-*i]=0;
  sscanf(str,"%lf",&value);
  if(strchr(str,'/')!=NULL) sscanf(strchr(str,'/')+1,"%lf",&div);
  value/=div;
  *i=n-1;
  return(value);
}

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

int Get_Symmetry(char *S, Matrix *M, Vector *t)
{
  int i,len,p=0;
  double T[3]={0.0,0.0,0.0};
  len=strlen(S);
  strupr(S);
  M->x=Vequal(0.0,0.0,0.0);
  M->y=Vequal(0.0,0.0,0.0);
  M->z=Vequal(0.0,0.0,0.0);
  *t=Vequal(0.0,0.0,0.0);
  for(i=0;i=47))
     ||((S[i]=='-')&&(S[i+1]<=57)&&(S[i+1]>=47))
     ||((S[i]<=57)&&(S[i]>=47))) T[p]=Get_Tval(S,&i);
    else if((S[i]=='X')&&(S[i-1]!='-')) do_M(M,p,0,1);
    else if((S[i]=='-')&&(S[i+1]=='X')) do_M(M,p,0,-1);
    else if((S[i]=='Y')&&(S[i-1]!='-')) do_M(M,p,1,1);
    else if((S[i]=='-')&&(S[i+1]=='Y')) do_M(M,p,1,-1);
    else if((S[i]=='Z')&&(S[i-1]!='-')) do_M(M,p,2,1);
    else if((S[i]=='-')&&(S[i+1]=='Z')) do_M(M,p,2,-1);
  }
  *t=Vequal(T[0],T[1],T[2]);
  return(1);
}

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

int Transform_Data(Mol *M, char *SS, Set *set)
{
  Symm S;
  char line[LINELEN];

  if(M==NULL) return(0);
  if(M->atoms==NULL) return(0);

  if(strlen(SS)<2)
  {
    sprintf(SS,"Enter symmetry transform (x,y,z): ");
    if(Get_Input_Line(SS,set->input)==0) return(0);
    if(strlen(SS)<2) return(0);
  }
  strcpy(S.S,SS);
  
  if(!Get_Symmetry(S.S,&S.M,&S.t)) return(0);
  
  sprintf(line,"Symmetry Matrix and translation vector"); Out_Message(line,O_NEWLN);
  sprintf(line,"%5.1f%5.1f%5.1f%8.3f",S.M.x.x,S.M.x.y,S.M.x.z,S.t.x); Out_Message(line,O_NEWLN);
  sprintf(line,"%5.1f%5.1f%5.1f%8.3f",S.M.y.x,S.M.y.y,S.M.y.z,S.t.y); Out_Message(line,O_NEWLN);
  sprintf(line,"%5.1f%5.1f%5.1f%8.3f",S.M.z.x,S.M.z.y,S.M.z.z,S.t.z); Out_Message(line,O_NEWLN);
  
  Perform_Symmetry(M,&S);
  Convert_to_Cartesian(M);
  Calculate_Parameters(M,Vequal(0.0,0.0,0.0),set);
  return(1);
}

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

int Expand_Data(Mol *M, Set *set)
{
  int i;
  Symm *S=NULL;
  Atms *A=NULL;
  Symm C;
  char line[LINELEN];

  if(M==NULL) return(0);
  if(M->atoms==NULL) return(0);
  if(M->symmetry==NULL) return(0);

/* perform centrosymmetric symmetry operation                              */

  if(M->mode&CSSG_BIT)
  {
    C.M.x=Vequal(-1.0,0.0,0.0);
    C.M.y=Vequal(0.0,-1.0,0.0);
    C.M.z=Vequal(0.0,0.0,-1.0);
    C.t=Vequal(0.0,0.0,0.0);
    sprintf(line,"Centrosymmetric Operator - ");
    A=New_Atom_Symmetry(M,S,A,line);
    M->atoms=Merge_Atom_Lists(M->atoms,A);
    A=NULL;
  }

/* perform non centring symmetry operations                                */

  for(i=1,S=First_Symm(M->symmetry);S!=NULL;S=S->next,i++)
  {
    if(S->mode&CENT_BIT) continue;
    if(Identity_Operator(S)) continue;
    sprintf(line,"Symmetry operator %5d : ",i);
    A=New_Atom_Symmetry(M,S,A,line);
  }
  M->atoms=Merge_Atom_Lists(M->atoms,A);
  A=NULL;

/* perform centring symmetry operations (eg DU lines)                      */

  for(i=1,S=First_Symm(M->symmetry);S!=NULL;S=S->next,i++)
  {
    if(!(S->mode&CENT_BIT)) continue;
    if(Identity_Operator(S)) continue;
    sprintf(line,"Centring Condition %5d : ",i);
    A=New_Atom_Symmetry(M,S,A,line);
  }
  M->atoms=Merge_Atom_Lists(M->atoms,A);
  for(i=0,A=First_Atom(M->atoms);A!=NULL;A=A->next,i++);
  M->num_atoms=i;

/* remove now redundant symmetries                                         */

  M->symmetry=Close_All_Symmetries(M->symmetry);

  Remove_Duplicate_Atoms(M,set);

  Convert_to_Cartesian(M);
  Calculate_Parameters(M,Vequal(0.0,0.0,0.0),set);

  return(1);
}

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

int Box_Atoms(Mol *M, char *inline, Set *set)
{
  int i,n;
  char line[LINELEN];
  double a[3]={1.0,1.0,1.0};
  double m[3]={0.0,0.0,0.0};
  Symm S;
  Atms *A=NULL;
  Atms *B=NULL;

  if(M==NULL) return(0);
  if(M->atoms==NULL) return(0);

  n=sscanf(inline,"%lf%lf%lf%lf%lf%lf",&m[0],&m[1],&m[2],&a[0],&a[1],&a[2]);
  if(n<0) n=0;
  if(n==0) { m[0]=1.0; n=1; }
  if(n<3) m[2]=m[0];
  if(n<2) m[1]=m[0];
  if(n<4)
  {
    for(i=0;i<3;i++)
    {
      a[i]=m[i];
      if(m[i]<1.0) a[i]*=-1.0;
      else m[i]=0.0;
    }
  }
  
  sprintf(line,"Boxing from [%4.1f,%4.1f,%4.1f] to [%4.1f,%4.1f,%4.1f]"
              ,m[0],m[1],m[2],a[0],a[1],a[2]);
  Out_Message(line,O_NEWLN);

  S.S[0]=0;
  S.M.x=Vequal(1.0,0.0,0.0);
  S.M.y=Vequal(0.0,1.0,0.0);
  S.M.z=Vequal(0.0,0.0,1.0);
  S.t=Vequal(0.0,0.0,0.0);

/* box into first unit cell                                                */

  Expand_Data(M,set);
  for(A=First_Atom(M->atoms);A!=NULL;A=A->next)
    A->fv=Vwrap(A->fv,Vequal(0.0,0.0,0.0),Vequal(1.0,1.0,1.0));

  if((a[0]>=1.0)||(a[1]>=1.0)||(a[2]>=1.0))
  {
    for(S.t.x=m[0];S.t.xatoms=Merge_Atom_Lists(M->atoms,B);
  for(i=0,A=First_Atom(M->atoms);A!=NULL;A=A->next,i++);
  M->num_atoms=i;

  if(set->modev&REDU_BIT) Remove_Duplicate_Atoms(M,set);

  Convert_to_Cartesian(M);
  Calculate_Parameters(M,Vequal(0.0,0.0,0.0),set);

  return(1);
}

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

char *Get_Type(char *name, char *type)
{
  int len;
  int i;
  strcpy(type,name);
  len=strlen(type);
  for(i=0;imode&=(FULL_BIT^FRAC_BIT);
  }
  else
  {
    M->a=a;
    M->b=b;
    M->c=c;
    M->al=al;
    M->be=be;
    M->ga=ga;
    cal=cos(Radians(al));
    cbe=cos(Radians(be));
    cga=cos(Radians(ga));
    M->cellvol=a*b*c*msqrt(1 - cal*cal - cbe*cbe - cga*cga + 2*cal*cbe*cga,"Get Cell Parameters : cell volume");
  }
  return(1);
}

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

int Get_Lattice(Mol *M, char *line, unsigned mode)
{
  int i=0;
  char centro[5]="c";
  char centri[5]="p";
  char xlat[9]="pirfabc";

  if(M==NULL) return(0);
  if(line==NULL) return(0);
  switch(mode)
  {
    case F_SHELXL : sscanf(line,"%d",&i);
                    if(i<0)
                    {
                      M->mode|=CSSG_BIT;
                      i*=-1;
                    }
                    if((i>0)&&(i<8)) M->centring=xlat[i-1];
                    break;
    case F_XTAL   : sscanf(line,"%s%s",centro,centri);
                    if((i=(int)(strchr(xlat,centri[0])-xlat))>=0)
                    {
                      M->centring=xlat[i];
                      if(centro[0]=='c') M->mode|=CSSG_BIT;
                    }
                    break;
    default       : break;
  }
  return(1);
}

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

int Get_Atom_Coordinates(Mol *M, char *line, unsigned mode)
{
  char name[LINELEN];
  char type[LINELEN];
  Vector a={0.0,0.0,0.0};
  int stype;

  if(M==NULL) return(0);
  if(line==NULL) return(0);

  switch(mode)
  {
    case F_SHELXL : if(sscanf(line,"%s%d%lf%lf%lf",name,&stype,&a.x,&a.y,&a.z)<5) return(0);
                    Get_Type(name,type);
                    break;
    case F_ACRYST : if(sscanf(line,"%s%s%lf%lf%lf",name,type,&a.x,&a.y,&a.z)<5) return(0);
                    break;
    default       : if(sscanf(line,"%s%lf%lf%lf",name,&a.x,&a.y,&a.z)<4) return(0);
                    Get_Type(name,type);
                    break;
  }
  name[ATM_LEN]=0;
  type[ATM_LEN]=0;

  M->atoms=New_Atom(M->atoms);
  Initialize_Atom(M->atoms);
  if(!M->main_atom) M->main_atom=M->atoms;
  if (stricmp(name,"DUO")==0) M->origin=M->atoms;
  strcpy(M->atoms->name,name);
  strcpy(M->atoms->type,name);
  M->atoms->fv=VequalV(a);

  return(1);
}

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

int Get_Symmetry_Operator(Mol *M, char *line, unsigned mode, unsigned type)
{
  int i;
  Matrix T={{1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}};
  Vector t={0.0,0.0,0.0};
  Symm *new=NULL;

  if(M==NULL) return(0);
  if(line==NULL) return(0);
  if(strlen(line)>=SYM_LEN) line[SYM_LEN-1]=0;
  if(strchr(line,'\n')!=NULL) *(strchr(line,'\n'))=0;
  i=strlen(line);
  while(i--,line[i]==' ') line[i]=0;
  Last_Character(line,' ');
  if(mode==F_GSTCOR)
  {
    if(!Get_Symmetry_Matrix(line,&T,&t)) return(0);
  }
  else if(!Get_Symmetry(line,&T,&t)) return(0);

  if((new=New_Symm(M->symmetry))==NULL) return(0);
  M->symmetry=new;
  Initialize_Symmetry(M->symmetry,line,T,t,type);

  if(!Identity_Operator(M->symmetry))
  {
    if(type==S_NORM) M->geneq++;
    else if(type==S_CENT) M->geneq*=2;
  }
  return(1);
}

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

int Shelx_Card_Type(char *line)
{
  if(!strncmp(line,"ZERR",4))  return(BAD);
  if(!strncmp(line,"SFAC",4))  return(BAD);
  if(!strncmp(line,"UNIT",4))  return(BAD);
  if(!strncmp(line,"L.S.",4))  return(BAD);
  if(!strncmp(line,"ACTA",4))  return(BAD);
  if(!strncmp(line,"FREE",4))  return(BAD);
  if(!strncmp(line,"FMAP",4))  return(BAD);
  if(!strncmp(line,"GRID",4))  return(BAD);
  if(!strncmp(line,"FVAR",4))  return(BAD);
  if(!strncmp(line,"HKLF",4))  return(BAD);
  if(!strncmp(line,"AFIX",4))  return(BAD);
  if(!strncmp(line,"DFIX",4))  return(BAD);
  if(!strncmp(line,"TITL",4))  return(TIT);
  if(!strncmp(line,"CELL",4))  return(CEL);
  if(!strncmp(line,"LATT",4))  return(LAT);
  if(!strncmp(line,"SYMM",4))  return(SYM);
  if(!strncmp(line,"END",3))   return(END);
  return(ATM);
}

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

int End_Fractional_Coordinates(Mol *M)
{
  Atms *A=NULL;
  if(M==NULL) return(0);
  if(!(M->mode&FRAC_BIT)) return(1);
  Error_Message(E_ENDFRC,"End Fractional Coordinates");
  M->mode&=(FULL_BIT^FRAC_BIT);
  M->symmetry=Close_All_Symmetries(M->symmetry);
  for(A=First_Atom(M->atoms);A!=NULL;A=A->next) A->fv=VequalV(A->v);
  M->a=1.0;
  M->b=1.0;
  M->c=1.0;
  M->al=90.0;
  M->be=90.0;
  M->ga=90.0;
  M->cellvol=0.0;
  M->freevol=0.0;
  M->geneq=1;
  M->centring='p';
  return(1);
}

/***************************************************************************/
/*******************  Crystal Calculations  ********************************/
/***************************************************************************/

int Calculate_Free_Unit_Cell_Volume(Mol *M, char *line, Set *set)
{
  Vector min={0.0,0.0,0.0}, max={0.0,0.0,0.0}, d={0.0,0.0,0.0};
  double V;
  long total;
  double tot_val=0.0;
  double err_val=0.0;
  int gnum=0;

  Box_Atoms(M,"1 1 1",set);

/* define encompassing box */

  Find_Encompassing_Box(M,FULL_BIT,&min,&max,&d);

/* choose two ways of calulating volume */

  if(set->mode&MTC_BIT)   /* Monte Carlo approach */
  {
    tot_val=Monte_Carlo_Volume(M,set,gnum,&min,&d,VOL_UC);
    err_val=set->veps;
  }
  else                    /* systemmatic approach */
  {
    tot_val=Fixed_Grid_Volume(M,set,gnum,&min,&max,&d,&total,VOL_UC);
    err_val=V/(double)total;
  }
  M->freevol=M->cellvol-tot_val;
  sprintf(line,"Free Unit Cell Volume =%10.2f cubic Angstroms [Cell=%10.2f Atoms=%10.2f]"
              ,M->freevol,M->cellvol,tot_val);
  Out_Message(line,O_NEWLN);
  return(1);
}

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

int Calculate_Group_Volume(Mol *M, char *argline, Set *set, unsigned mode)
{
  int i,n;
  double value=0.0;
  char *args[MAXARG];
  int num=0;
  Grps *group;
  char line[LINELEN];
  char outline[LINELEN];

  if(M->groups==NULL)
  {
    Error_Message(E_NOGRPS,"Calculate Group Volume");
    return(0);
  }

/* load specified group names into memory                                 */

  if(strlen(argline)<1) return(0);
  strcpy(line,argline);
  if((num=Get_Group_Names(line,outline,args))<1) return(0);

  if((mode==CAVV)&&(set->modev&ABOX_BIT)) Box_Atoms(M,"-1",set);

/* loop through all molecule groups, comparing to loaded groups           */

  for(n=0;ngroups);group!=NULL;group=group->next,i++)
    {
      if(stricmp(group->name,args[n])==0)
      {
        if(mode==CAVV)
        {
          sprintf(line,"Calculating Volume of cavity of group %d (%s) at R=%4.1f"
                      ,i,group->name,group->volrad);
          Out_Message(line,O_NEWLN);

          group->mode|=CAVV_BIT;
          value=Molecular_Volume(M,NULL,set,group);
          group->mode&=(FULL_BIT^CAVV_BIT);

          sprintf(line,"%s Group %s R=%4.1f cavity volume = %f cubic angstroms"
                      ,M->name,group->name,group->volrad,value);
          Out_Message(line,O_NEWLN);
        }
        else
        {
          sprintf(line,"Calculating Volume of group %d (%s)",i,group->name);
          Out_Message(line,O_NEWLN);
          value=Molecular_Volume(M,NULL,set,group);
          sprintf(line,"%s Group %s volume = %f cubic angstroms"
                      ,M->name,group->name,value);
          Out_Message(line,O_NEWLN);
        }
        Out_Message("",O_NEWLN);
      }
    }
  }
  return(1);
}

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

int Exclude_Atoms_Outside_Groups(Mol *M, Set *set, char *argline)
{
  Atms *at=NULL;
  int i,n,g;
  char *args[MAXARG];
  int gnum[MAXARG];
  Grps *G[MAXARG];
  double volrad[MAXARG];
  double atsep;
  int num=0;
  Grps *group=NULL;
  char line[LINELEN];
  char outline[LINELEN];

  if(M->groups==NULL)
  {
    Error_Message(E_NOGRPS,"Calculate Group Volume");
    return(0);
  }

/* load specified group names into memory                                 */

  if(strlen(argline)<1) return(0);
  strcpy(line,argline);
  if((num=Get_Group_Names(line,outline,args))<1) return(0);

/* loop through all molecule groups, comparing to loaded groups           */

  sprintf(line,"Closing atoms outside groups");

  for(g=0,n=0;ngroups);group!=NULL;group=group->next,i++)
    {
      if(stricmp(group->name,args[n])==0)
      {
        if(strlen(line)volrad;
        g++;
        if(g>=MAXARG-1) break;
      }
    }
  }
  
  if(g) Out_Message(line,O_NEWLN);
  else
  {
    Out_Message("No matching groups found",O_NEWLN);
    return(0);
  }

/* delete all atoms not within specified groups range                      */

  for(at=First_Atom(M->atoms);at!=NULL;at=at->next)
  {
    at->bond=Close_All_Bonds(at->bond);
    at->bonds=0;
  }

  at=First_Atom(M->atoms);
  while((g!=0)&&(at!=NULL))
  {
    if(at==NULL) break;
    else M->atoms=at;
    if(strcmp(at->type,"A")==0) {at=at->next; continue; }
    for(i=0;imain==NULL)) continue;
      atsep=Vmag(Vdif(at->v,G[i]->main->v))-at->radius-volrad[i];
      if(atsep<=0.0) break;
    }
    if(i==g) at=Close_Current_Atom(at);
    else at=at->next;
  }

  for(i=0,at=First_Atom(M->atoms);at!=NULL;at=at->next,i++);
  M->num_atoms=i;

/* refind all bonded groups */

  for(i=0;i
  
Modified: Fri Dec 8 17:00:00 1995 GMT
Page accessed 1192 times since Sat Apr 17 22:00:04 1999 GMT