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

/**************************************************************************/
/******************  File 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 "sterfile.h"      /* functions for all file manipulations        */
#include "crystal.h"       /* crystallographic manipulations              */
#include "stermem.h"       /* dynamic memory management module            */
#include "stertext.h"      /* all text functions for text mode            */
#include "stergrp.h"       /* group manipulation functions                */
#include "steraid.h"       /* additional functions needed                 */
#include "stercalc.h"      /* main calculation function                   */
#include "craig.h"         /* craig's multiple overlap calculation        */

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

int Initialize_Molecule(Mol *M)
{
  if(M==NULL) return(0);
  M->name[0]=0;            /* molecule name                               */
  M->Fname[0]=0;           /* molecule filename without extension         */
  M->a=1.0;                /* unit cell parameters, if appropriate        */
  M->b=1.0;
  M->c=1.0;
  M->al=90.0;
  M->be=90.0;
  M->ga=90.0;
  M->cellvol=0.0;          /* unit cell volume                            */
  M->freevol=0.0;          /* free volume in unit cell                    */
  M->geneq=1;              /* number of general equivalent positions      */
  M->centring='p';         /* type of centring condition                  */
  M->num_atoms=0;          /* number of atoms                             */
  M->multi=MAX_OVER;       /* number of overlaps in multiple overlap calc.*/
  M->main_atom=NULL;       /* atom bonded to origin defining atom (if any)*/
  M->minR=0.0;
  M->maxR=10.0;            /* min,max molecule distance from apex         */
  M->plane=Vequal(0.0,0.0,1.0);
  M->plane_x=Vequal(1.0,0.0,0.0);
  M->plane_minT=0.0;
  M->plane_maxT=PI;        /* plane rotation theta range                  */
  M->plane_minP=0.0;
  M->plane_maxP=2*PI;      /* plane rotation theta range                  */
  M->plane_T=0.0;
  M->plane_P=0.0;          /* current plane theta and phi                 */
  M->basis_x=Vequal(1.0,0.0,0.0);
  M->basis_y=Vequal(0.0,1.0,0.0);
  M->basis_z=Vequal(0.0,0.0,1.0);
  M->main_atom=NULL;       /* pointer to main atom                        */
  M->origin=NULL;          /* pointer to origin defining atom             */
  M->atoms=NULL;           /* pointer to individual atoms memory          */
  M->groups=NULL;          /* pointer to definable atomic groups          */
  M->symmetry=NULL;        /* pointer to symmetry operator memory         */
  M->ster=NULL;            /* pointer to individual calculations memory   */
  M->mode=0;               /* molecule mode                               */
  return(1);
/* next and prev pointers have already been assigned, do not fiddle !!!   */
}

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

int Initialize_Atom(Atms *atom)
{
  if(atom==NULL) return(0);
  atom->name[0]=0;         /* atom lable                                  */
  atom->type[0]=0;         /* atom type label                             */
  atom->v=Vequal(0.0,0.0,0.0);    /* position rel. to apex                */
  atom->fv=Vequal(0.0,0.0,0.0);   /* position rel. to apex                */
  atom->tv=Vequal(0.0,0.0,0.0);   /* position in 2D, on projection plane  */
  atom->distance=0.0;	   /* distance from apex                          */
  atom->theta=0.0;
  atom->phi=0.0;           /* polar position with main atom at 0,0        */
  atom->radius=0.0;        /* atomic radius                               */
  atom->SVangle=0.0;       /* effective semi-vertix angle for calc.       */
  atom->bonds=0;           /* number of bonds                             */
  atom->count=0;           /* number of times counted in craig counting   */
  atom->stat=0;  	   /* status of atom for calculations             */
  atom->group=0;           /* group numbers                               */
  atom->bond=NULL;         /* pointer to one of the atoms bonds           */
  return(1);
/* next and prev pointers have already been assigned, do not fiddle !!!   */
}

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

int Initialize_Bond(Bond *bond)
{
  if(bond==NULL) return(0);
  bond->type=0;            /* bond type (0=not bonded, 1=single, 2=double */
  bond->atom=NULL;         /* pointer to atom bonded to                   */
  return(1);
/* next and prev pointers have already been assigned, do not fiddle !!!   */
}

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

Bond *Find_Bond(Atms *A, Atms *B)
{
  Bond *bond=NULL;
  if((A==NULL)||(B==NULL)) return(NULL);
  if((bond=First_Bond(A->bond))==NULL) return(NULL);
  for(bond=First_Bond(A->bond);bond!=NULL;bond=bond->next)
    if(bond->atom==B) return(bond);
  return(NULL);
}

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

int Bond_Exists(Atms *A, Atms *B, short unsigned type)
{
  Bond *bond=NULL;
  if((A==NULL)||(B==NULL)) return(0);
  if(A->bond==NULL)return(0);
  if((bond=Find_Bond(A,B))==NULL) return(0);
  if(bond->type!=type) Error_Message(E_BDBOND,"Bond Exists");
  return(1);
}

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

void Add_New_Bond(Atms *atomA, Atms *atomB, short unsigned type)
{
  if((atomA==NULL)||(atomB==NULL)) Error_Message(E_IMBOND,"Add New Bond");
  else
  {
    if(!Bond_Exists(atomA,atomB,type))
    {
      atomA->bond=New_Bond(atomA->bond);
      Initialize_Bond(atomA->bond);
      atomA->bond->type=type;
      atomA->bond->atom=atomB;
      atomA->bonds++;
    }
    if(!Bond_Exists(atomB,atomA,type))
    {
      atomB->bond=New_Bond(atomB->bond);
      Initialize_Bond(atomB->bond);
      atomB->bond->type=type;
      atomB->bond->atom=atomA;
      atomB->bonds++;
    }
  }
}

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

void Screen_Atom_Name(char *name)
{
  int i;
  int len=strlen(name);
  for (i=0;i122)||(name[i]=='_')) name[i]=0;
  }
}

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

int Load_Parameters(Set *set, FILE *PF, char *fname)
{
  char *args[MAXARG];
  int num=0;
  Parm *new=NULL;
  int n=0;
  char name[LINELEN];
  char line[LINELEN];

  if((fname!=NULL)&&(strlen(fname)>0)) strcpy(name,fname);
  else strcpy(name,"steric.par");
  sprintf(line,"%s",name);
  if((PF==NULL)&&((PF = fopen(line,"rt")) == NULL))
  {
    sprintf(line,"%s/%s",STERICHOME,name);
    if((PF==NULL)&&((PF = fopen(line,"rt")) == NULL))
    {
      sprintf(line,"Load Parameters [%s] | [%s/%s]",name,STERICHOME,name);
      Error_Message(E_NOPARM,line);
      return (0);
    }
  }
  if(set->parm!=NULL) set->parm=Close_All_Parms(set->parm);
  while(fgets(line,LINELEN,PF)!=NULL)
  {
    if(line[0]=='#') continue;
    if(strchr(line,'\n')!=NULL) strchr(line,'\n')[0]=0;
    if(strchr(line,'#')!=NULL) strchr(line,'#')[0]=0;
    if((num=Get_Arguements(line,args))<1) continue;
    if((new=New_Parm(set->parm))==NULL) { fclose(PF); return(0); }
    set->parm=new;
    set->parm->name[0]=0;
    set->parm->Vrad=0.0;
    set->parm->Crad=0.0;
    for(n=0;nparm->alias[n][0]=0;
    for(n=0;nparm->name,name);
                  break;
        case 1  : sscanf(args[n],"%lf",&set->parm->Vrad); break;
        case 2  : sscanf(args[n],"%lf",&set->parm->Crad); break;
        default : sscanf(args[n],"%s",name);
                  name[ATM_LEN]=0;
                  strcpy(set->parm->alias[n-3],name);
                  break;
      }
    }
  }
  fclose(PF);
  set->parm=First_Parm(set->parm);
  return(1);
}

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

double Get_Atomic_Radius(int bonds, char *name, Parm *parm, unsigned mode)
{
  Parm *pa=NULL;
  int i,n;
  if(parm==NULL)
  {
    Error_Message(E_BDPARM,"Get Atomic Radius");
    return(DEF_RAD);
  }
  for(i=0;i<2;i++)
  {
    for(pa=First_Parm(parm);pa!=NULL;pa=pa->next)
    {
      if((stricmp(name,pa->name))!=0)
      {
        for(n=0;nalias[n]))==0) break;
        }
        if(n==MAX_ALS) continue;
        strcpy(name,pa->name);
      }
      if(mode&VDW_BIT) return(pa->Vrad);
      if(mode&CVL_BIT) return(pa->Crad);
      else if (bonds<2) return(pa->Vrad);
      else return(pa->Crad);
    }
    Screen_Atom_Name(name);
  }
  return(0.0);
}

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

int Calculate_Polar_Positions(Mol *M)
{
  Atms *at=NULL;
  int n=0;
  struct vector flat={0.0,0.0,0.0};
  double x,y;
  char line[LINELEN];

  if((M==NULL)||(M->atoms==NULL)) return(0);
  Set_Projected_XY(M,0.0,0.0);
  Set_Total_SVAngles(M);
  Get_Theta_Positions(M);               /* <- basis_z is calculated here */
  M->tolman=Find_Max_Group_SVangles(M);    /* M->atoms for basis_x found */
  sprintf(line,"Tolman Cone Angle is %8.4f radians",M->tolman);
  Out_Message(line,O_NEWLN);
  M->basis_x=unit_vector(cross_product(M->basis_z,unit_vector(M->atoms->v)));
  M->basis_x=unit_vector(cross_product(M->basis_x,M->basis_z));
  if(!AlmostZero(dot_product(M->basis_z,M->basis_x)))
    Error_Message(E_BDBASE,"Calculate Polar Positions");

  M->basis_y=unit_vector(cross_product(M->basis_z,M->basis_x));

/* calculate phi positions                                               */

  for(n=0,at=First_Atom(M->atoms);at!=NULL;at=at->next)
  {
    n++; if(n>M->num_atoms) Error_Message(E_ATMNUM,"Calculate Polar Position");
    flat=cross_product(M->basis_z,unit_vector(at->v));
    if(AlmostZero(at->theta)) at->phi=0.0;
    else
    {
      flat=unit_vector(flat);
      if(!AlmostZero(dot_product(flat,M->basis_z))) Error_Message(E_BDPROJ,"Calculate Polar Position");
      flat=cross_product(flat,M->basis_z);
      if(!AlmostZero(dot_product(flat,M->basis_z))) Error_Message(E_BDPROJ,"Calculate Polar Position");
      flat=unit_vector(flat);
      y=dot_product(flat,M->basis_y);
      x=dot_product(flat,M->basis_x);
      if(x>=0)
      {
        if(y>=0) at->phi=asin(y);
        else at->phi=2*PI-asin(-y);
      }
      else
      {
        if(y>=0) at->phi=PI-asin(y);
        else at->phi=PI+asin(-y);
      }
    }
  }
  return(1);
}

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

int Get_Positions(Mol *M, struct vector origin, Set *set)
{
  Atms *at=NULL;
  double distance=0.0;
  double radius=0.0;
  int n;
  double maxR=0, minR=100;

  if(M==NULL) return(0);
  if((M->mode&FRAC_BIT)&&(Vcmp(origin,Vequal(0.0,0.0,0.0))!=0))
    End_Fractional_Coordinates(M);
  for(n=0,at=First_Atom(M->atoms);at!=NULL;at=at->next)
  {
    n++; if(n>M->num_atoms) Error_Message(E_ATMNUM,"Get Positions");
    at->v=Vsum(at->v,SxV(-1,origin));
    distance=sqrt(at->v.x*at->v.x
                 +at->v.y*at->v.y
                 +at->v.z*at->v.z);
    at->distance=distance;
    radius=at->radius;
    if ((strcmp(at->name,"DUO")!=0)&&(strcmp(at->type,"DUO")!=0))
    {
      if (maxR<(distance+radius)) maxR=(distance+radius);
      if (minR>(distance-radius)) minR=(distance-radius);
    }
  }
  M->maxR=maxR;
  M->minR=minR;
  set->min=fmin(set->min,minR);
  set->max=fmax(set->max,maxR);
  return(1);
}

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

int Calculate_Parameters(Mol *M, struct vector origin, Set *set)
{
  Bond *bond=NULL;

  if((M==NULL)||(M->atoms==NULL)) return(0);
  if(M->origin) Assign_Groups(M);
  Get_Positions(M,origin,set);
  if(M->origin)
  {
    for(bond=First_Bond(M->origin->bond);bond!=NULL;bond=bond->next) 
    {
      M->main_atom=bond->atom;
      if(M->main_atom->stat&MAIN_BIT) break;
    }
    M->origin->stat=M->origin->stat&(!MAIN_BIT);
  }
  if(!(M->mode&FRAC_BIT)) Calculate_Polar_Positions(M);
  return(1);
}

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

int Find_Atomic_Radii(Mol *M, Set *set)
{
  Atms *at=NULL;
  int n=0;
  if((M==NULL)||(M->atoms==NULL)) return(0);
  at=First_Atom(M->atoms);
  for(n=0,at=First_Atom(M->atoms);at!=NULL;at=at->next)
  {
    n++; if(n>M->num_atoms) Error_Message(E_ATMNUM,"Find Atomic Radii");
    at->stat=at->stat&(FULL_BIT^GRP_BIT);
    at->radius=Get_Atomic_Radius(at->bonds,at->type,set->parm,set->mode);
    if (at->radius!=0) at->stat=MAIN_BIT;
  }
  return(1);
}

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

int Setup_Atomic_Parameters(Mol *M, Set *set)
{
  if((M==NULL)||(M->atoms==NULL)) return(0);
  Find_Atomic_Radii(M,set);
  if(M->origin) Calculate_Parameters(M,M->origin->v,set);
  else Calculate_Parameters(M,Vequal(0.0,0.0,0.0),set);
  return(1);
}

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

void Save_Steric_Atoms(FILE *MF, Mol *M)
{
  char line[LINELEN];
  int i=0,n=0;
  Atms *at=NULL;
  Bond *bond=NULL;
  for(at=First_Atom(M->atoms);at!=NULL;at=at->next)
  {
    if(at==M->origin)
    {
      i=Get_Atom_Number(at);
      strcpy(line,"ORIGIN");
    }
    else strcpy(line,"ATOM");
    fprintf(MF,"%-6s  %-*s%-*s%10.6f%10.6f%10.6f\n"
              ,line,ATM_LEN,at->name,ATM_LEN,at->type
              ,at->fv.x,at->fv.y,at->fv.z);
  }
  for(at=First_Atom(M->atoms);at!=NULL;at=at->next)
  {
    if(at->bond==NULL) continue;
    i=Get_Atom_Number(at);
    fprintf(MF,"BOND  %4d",i);
    for(bond=First_Bond(at->bond);bond!=NULL;bond=bond->next)
    {
      n=Get_Atom_Number(bond->atom);
      fprintf(MF,"%4d",n);
    }
    fprintf(MF,"\n");
  }
}

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

int Save_Steric_Data(FILE *MF, Ster *ster)
{
  int i=0,n=0;
  Conf *conf=NULL;
  if(ster==NULL) return(0);
  fprintf(MF,"STERIC  %c %10.6f%10.6f%10.6f%10.6f%10.6f%10.6f%10.6f  %s\n",ster->type
            ,ster->tot_val,ster->err_val
            ,ster->tot_con,ster->err_con
            ,ster->max_val,ster->pr_area
            ,ster->peak_R,ster->name);
  if(ster->val!=NULL)
  {
    fprintf(MF,"PROFIL  %10.6f%10.6f%6d  %s\n"
              ,ster->min,ster->max,ster->size,ster->name);
    for(i=0;isize;)
    {
      for(n=0;n<10;n++,i++)
      {
        fprintf(MF,"%10.6f",ster->val[i]);
      }
      fprintf(MF,"\n");
    }
  }
  if(ster->conf!=NULL)
  {
    fprintf(MF,"CONFS   %10.6f%10.6f  %s\n"
              ,ster->tot_con,ster->err_con,ster->name);
    for(conf=First_Conformer(ster->conf);conf!=NULL;conf=conf->next)
    {
      fprintf(MF,"CONFOR  %10.6f%10.3f%10.6f%10.6f\n"
                ,conf->value,conf->temperature,conf->Ec,conf->mol);
    }
  }
  return(1);
}

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

void Save_Steric_Molecule(Mol *M, char *fname)
{
  FILE *MF=NULL;
  Ster *ster=NULL;
  char line[LINELEN];
  if(!strlen(fname)) strcpy(fname,M->Fname);
  New_Extension(fname,".stc");
  sprintf(line,"Saving molecule to file %s",fname);
  Out_Message(line,O_NEWLN);
  if((MF=fopen(fname,"wt"))==NULL)
  {
    Error_Message(E_OPNOUT,"Save Steric Molecule");
  }
  else
  {
    fprintf(MF,"STERIC %s\n",M->name);
    Save_Steric_Atoms(MF,M);
    for(ster=First_Steric(M->ster);ster!=NULL;ster=ster->next)
      Save_Steric_Data(MF,ster);
    fclose(MF);
  }
}

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

void Read_Steric_Atom(char *line, Mol *M)
{
  int n=0;
  char name[LINELEN],type[LINELEN];
  Vector a={0.0,0.0,0.0};

  if(sscanf(line,"%s%s%lf%lf%lf%s",name,type,&a.x,&a.y,&a.z,name)==6)
  {
    name[ATM_LEN]=0;
    type[ATM_LEN]=0;
    n++;
    M->atoms=New_Atom(M->atoms);
    Initialize_Atom(M->atoms);
    if(!M->main_atom) M->main_atom=M->atoms;
    strcpy(M->atoms->name,name);
    strcpy(M->atoms->type,type);
    M->atoms->v=VequalV(a);
    M->atoms->fv=VequalV(a);
  }
}

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

void Read_Steric_Bond(char *line, Mol *M)
{
  int A,b[12],i=0,num=0;             /* maximum coordination number of 12 */
  Atms *atomA=NULL, *atomB=NULL;

  if((num=sscanf(line,"%d%d%d%d%d%d%d%d%d%d%d%d%d",&A
		     ,&b[0],&b[1],&b[2],&b[3]
		     ,&b[4],&b[5],&b[6],&b[7]
		     ,&b[8],&b[9],&b[10],&b[11]))>1)
  {
    atomA=Goto_Atom(M->atoms,A);
    if((atomA)&&(atomA==M->origin)) M->main_atom=Goto_Atom(M->atoms,b[0]);
    for(i=0;iatoms,b[i]);
      Add_New_Bond(atomA,atomB,SINGLE_B);
      if((atomB)&&(atomB==M->origin)) M->main_atom=atomA;
    }
  }
}

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

Mol *Load_Steric_Molecule(FILE *MF, Mol *M)
{
  char line[LINELEN],name[LINELEN];
  int num,n;
  Atms *at=NULL;

/* test that file is really OK                                            */

  if((num=count_lines(MF,"ATOM"))==0)
  {
    Error_Message(E_NOATOM,"Load Steric Molecule");
	return(NULL);
  }
  num+=count_lines(MF,"ORIGIN");
  if(count_lines(MF,"BOND")==0) Error_Message(E_NOBOND,"Load Steric Molecule");
  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  rewind(MF);
  if(get_next_line(MF,"STERIC",line)==0)
  {
	Error_Message(E_NOTITL,"Load Steric Molecule");
	n=Get_Molecule_Number(M);
	sprintf(M->name,"M%d",n);
  }
  else sscanf(line,"%s%s",name,M->name);
  M->num_atoms=num;
  sprintf(line,"Loading steric data %s ...",M->name);
  Out_Message(line,O_NEWLN);

  while((fgets(line,LINELEN,MF)!=NULL)&&(!feof(MF)))
  {
    if(sscanf(line,"%s",name)<1) continue;
    if(strcmp(name,"ATOM")==0) Read_Steric_Atom(line+6,M);
    if(strcmp(name,"ORIGIN")==0)
    {
      Read_Steric_Atom(line+6,M);
      M->origin=M->atoms;
    }
    if(strcmp(name,"BOND")==0) Read_Steric_Bond(line+6,M);
  }

  if(M->atoms==NULL) n=0;
  else
  {
    for(at=First_Atom(M->atoms),n=0;at!=NULL;at=at->next,n++);
  }
  if(n!=num)
  {
	Error_Message(E_BDATOM,"Load Steric Molecule");
	M->num_atoms=n;
  }

/* read in bonding table                                                  */

  return(M);

}

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

Mol *Load_Alchemy_Molecule(FILE *MF, Mol *M)
{
  char line[LINELEN],name[LINELEN];
  int Natoms,Nbonds,n,i;
  char arb1[20],arb2[20],arb3[20];
  Vector a={0.0,0.0,0.0};
  int A,B;
  Atms *atomA=NULL, *atomB=NULL;

/* test that file is really OK                                            */

  if(fgets(line,98,MF)==NULL) return(NULL);
  if((n=sscanf(line,"%d%s%d%s%d%s%s"
     ,&Natoms,arb1,&Nbonds,arb2,&i,arb3,name))<3)
  {
    Error_Message(E_BDFILE,"Load Alchemy Molecule");
    return(NULL);
  }
  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  if(n<7)
  {
	Error_Message(E_NOTITL,"Load Alchemy Molecule");
	n=Get_Molecule_Number(M);
	sprintf(M->name,"M%d",n);
  }
  else strcpy(M->name,name);
  M->num_atoms=Natoms;
  sprintf(line,"Loading alchemy data %s ...",M->name);
  Out_Message(line,O_NEWLN);

/* read in atomic information                                             */

  n=0; i=0;
  while((nnum_atoms)&&(inum_atoms)&&(fgets(line,LINELEN,MF)!=NULL))
  {
    n++;
    M->atoms=New_Atom(M->atoms);
    Initialize_Atom(M->atoms);
    if(!M->main_atom) M->main_atom=M->atoms;
    sscanf(line,"%d%s%lf%lf%lf",&i,name,&a.x,&a.y,&a.z);
    name[ATM_LEN]=0;
    if (stricmp(name,"DUO")==0) M->origin=M->atoms;
    strcpy(M->atoms->name,name);
    strcpy(M->atoms->type,name);
    M->atoms->v=VequalV(a);
    M->atoms->fv=VequalV(a);
  }
  if(n!=i)
  {
	Error_Message(E_BDATOM,"Load Alchemy Molecule");
	M->num_atoms=Natoms;
  }

/* read in bonding table                                                  */

  n=0; i=0;
  while((natoms,A);
      atomB=Goto_Atom(M->atoms,B);
      if((atomA)&&(atomA==M->origin)) M->main_atom=atomB;
      if((atomB)&&(atomB==M->origin)) M->main_atom=atomA;
      if(strcmp(name,"SINGLE")==0) Add_New_Bond(atomA,atomB,SINGLE_B);
      else if(strcmp(name,"DOUBLE")==0) Add_New_Bond(atomA,atomB,DOUBLE_B);
      else if(strcmp(name,"TRIPLE")==0) Add_New_Bond(atomA,atomB,TRIPLE_B);
      else if(strcmp(name,"AROMATIC")==0) Add_New_Bond(atomA,atomB,AROMAT_B);
      else Add_New_Bond(atomA,atomB,UNKNOW_B);
    }
  }

  return(M);
}

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

Mol *Load_Biograph_Molecule(FILE *MF, Mol *M)
{
  char line[LINELEN],name[LINELEN];
  int num,n;
  char arb1[LINELEN];
  Vector a={0.0,0.0,0.0};

/* test that file is really OK                                            */

  if((num=count_lines(MF,"HETATM"))==0)
  {
    Error_Message(E_NOATOM,"Load Biograph Molecule");
    return(NULL);
  }
  if(count_lines(MF,"CONECT")==0) Error_Message(E_NOBOND,"Load Biograph Molecule");
  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  if(get_next_line(MF,"DESCRP",line)==0)
  {
    Error_Message(E_NOTITL,"Load Biograph Molecule");
    n=Get_Molecule_Number(M);
    sprintf(M->name,"M%d",n);
  }
  else sscanf(line,"%s%s",arb1,M->name);
  M->num_atoms=num;
  sprintf(line,"Loading biograph data %s ...",M->name);
  Out_Message(line,O_NEWLN);

/* read in atomic information                                             */

  if(get_next_line(MF,"HETATM",line)==0)
  {
    Error_Message(E_NOATOM,"Load Biograph Molecule");
    return(Close_Current_Molecule(M));
  }
  n=0;
  do
  {
    line[6]=0;
    if(strcmp(line,"HETATM")!=0) break;
    if(sscanf(line+12,"%s",arb1)<1) break;
    arb1[ATM_LEN]=0;
    if(sscanf(line+BGF_SPACE+1,"%lf%lf%lf%s",&a.x,&a.y,&a.z,name)<4) continue;
    name[ATM_LEN]=0;
    n++;
    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,arb1);
    strcpy(M->atoms->type,name);
    M->atoms->v=VequalV(a);
    M->atoms->fv=VequalV(a);
  } while(fgets(line,LINELEN,MF)!=NULL);
  if(n!=num)
  {
    Error_Message(E_BDATOM,"Load Biograph Molecule");
    M->num_atoms=n;
  }

/* read in bonding table                                                  */

  if(get_next_line(MF,"CONECT",line)==0)
  {
    Error_Message(E_NOBOND,"Load Biograph Molecule");
  }
  do
  {
    line[6]=0;
    if(strcmp(line,"CONECT")!=0) continue;
    Read_Steric_Bond(line+7,M);
  } while(fgets(line,98,MF)!=NULL);

  return(M);
}

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

Mol *Load_Biosym_Molecule(FILE *MF, Mol *M, char *file, Set *set)
{
  char line[LINELEN],name[LINELEN];
  int num,n,p;
  char arb1[LINELEN], arb2[LINELEN], arb3[LINELEN];
  Vector a={0.0,0.0,0.0};

  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  if(strrchr(file,'.')!=NULL) strrchr(file,'.')[0]=0;
  if(strlen(file)<1)
  {
    Error_Message(E_NOTITL,"Load Biosym Molecule");
    n=Get_Molecule_Number(M);
    sprintf(M->name,"M%d",n);
  }
  else strcpy(M->name,file);
  sprintf(line,"Loading biosymm data %s ...",M->name);
  Out_Message(line,O_NEWLN);

/* read in atomic information                                             */

  if(get_next_line(MF,"!DATE",line)==0)
  {
    Error_Message(E_NOATOM,"Load Biosym Molecule");
    return(Close_Current_Molecule(M));
  }
  n=0;
  while((fgets(line,LINELEN,MF)!=NULL)&&(!feof(MF)))
  {
    if(line[0]=='!') break;
    if(sscanf(line,"%s",name)<1) continue;
    strupr(name);
    if(strcmp(name,"END")==0) break;
    if((num=sscanf(line,"%s%lf%lf%lf%s%d%s%s",name,&a.x,&a.y,&a.z,arb3,&p,arb2,arb1))<6) continue;
    if(num<8)
    {
      strcpy(arb1,name);
      Screen_Atom_Name(arb1);
    }
    arb1[ATM_LEN]=0;
    name[ATM_LEN]=0;
    n++;
    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,arb1);
    M->atoms->v=VequalV(a);
    M->atoms->fv=VequalV(a);
  }
  M->num_atoms=n;

  Find_Atomic_Radii(M,set);
  Find_All_Bonds(M,set,0,0);

  return(M);
}

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

Mol *Load_PDB_Molecule(FILE *MF, Mol *M, char *file)
{
  char line[LINELEN],name[LINELEN];
  int num,n,p,q;
  char arb1[LINELEN];
  Vector a={0.0,0.0,0.0};
  Symm O,S;
  Atms *A=NULL;

  O.M.x=Vequal(1.0,0.0,0.0);
  O.M.y=Vequal(0.0,1.0,0.0);
  O.M.z=Vequal(0.0,0.0,1.0);
  O.t  =Vequal(0.0,0.0,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);

/* test that file is really OK                                            */

  if((num=count_lines(MF,"ATOM"))==0)
  {
    Error_Message(E_NOATOM,"Load PDB Molecule");
    return(NULL);
  }
  if(count_lines(MF,"CONECT")==0) Error_Message(E_NOBOND,"Load PDB Molecule");
  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  if(strrchr(file,'.')!=NULL) strrchr(file,'.')[0]=0;
  if(strlen(file)<1)
  {
    Error_Message(E_NOTITL,"Load PDB Molecule");
    n=Get_Molecule_Number(M);
    sprintf(M->name,"M%d",n);
  }
  else strcpy(M->name,file);
  M->num_atoms=num;
  sprintf(line,"Loading PDB data %s ...",M->name);
  Out_Message(line,O_NEWLN);

/* read in atomic information                                             */

  n=0;
  while((fgets(line,LINELEN,MF)!=NULL)&&(!feof(MF)))
  {
    if(sscanf(line,"%s",name)<1) continue;
    strupr(name);
    if(strcmp(name,"ATOM")==0)
    {
      if(sscanf(line+4,"%d%s%d%lf%lf%lf",&p,arb1,&q,&a.x,&a.y,&a.z)<6) continue;
      sprintf(name,"%s%d",arb1,p);
      arb1[ATM_LEN]=0;
      name[ATM_LEN]=0;
      n++;
      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,arb1);
      M->atoms->v=VequalV(a);
      M->atoms->fv=VequalV(a);
    }
    else if(strcmp(name,"CONECT")==0) Read_Steric_Bond(line+6,M);
    else if(strcmp(name,"ORIGX1")==0) sscanf(line+6,"%lf%lf%lf%lf",&O.M.x.x,&O.M.x.y,&O.M.x.z,&O.t.x);
    else if(strcmp(name,"ORIGX2")==0) sscanf(line+6,"%lf%lf%lf%lf",&O.M.y.x,&O.M.y.y,&O.M.y.z,&O.t.y);
    else if(strcmp(name,"ORIGX3")==0) sscanf(line+6,"%lf%lf%lf%lf",&O.M.z.x,&O.M.z.y,&O.M.z.z,&O.t.z);
    else if(strcmp(name,"SCALE1")==0) sscanf(line+6,"%lf%lf%lf%lf",&S.M.x.x,&S.M.x.y,&S.M.x.z,&S.t.x);
    else if(strcmp(name,"SCALE2")==0) sscanf(line+6,"%lf%lf%lf%lf",&S.M.y.x,&S.M.y.y,&S.M.y.z,&S.t.y);
    else if(strcmp(name,"SCALE3")==0) sscanf(line+6,"%lf%lf%lf%lf",&S.M.z.x,&S.M.z.y,&S.M.z.z,&S.t.z);
    else if(strcmp(name,"END")==0) break;
  }
  
  if(n!=num)
  {
    Error_Message(E_BDATOM,"Load PDB Molecule");
    M->num_atoms=n;
  }

  if(!Identity_Operator(&O))
  {
    Perform_Symmetry(M,&O);
    for(A=First_Atom(M->atoms);A!=NULL;A=A->next) A->v=VequalV(A->fv);
  }

  return(M);
}

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

Mol *Load_Schakal_Molecule(FILE *MF, Mol *M)
{
  char line[LINELEN],name[LINELEN];
  int num,n;
  char arb1[LINELEN];

/* test that file is really OK                                            */

  if((num=count_lines(MF,"AT"))==0)
  {
    Error_Message(E_NOATOM,"Load Schakal Molecule");
    return(NULL);
  }
  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  M->mode|=FRAC_BIT;              /* default to expect fractional coords. */ 

  if(get_next_line(MF,"TITL",line)==0)
  {
    Error_Message(E_NOTITL,"Load Schakal Molecule");
    n=Get_Molecule_Number(M);
    sprintf(M->name,"M%d",n);
  }
  else sscanf(line,"%s%s",arb1,M->name);
  M->num_atoms=num;
  sprintf(line,"Loading Schakal data %s ...",M->name);
  Out_Message(line,O_NEWLN);

/* read in unit cell information, if any                                  */

  if(get_next_line(MF,"CE",line)==0)
  {
    Error_Message(E_NOCELL,"Load Schakal Molecule");
    M->mode&=(FULL_BIT^FRAC_BIT);
  }
  else Get_Cell_Parameters(M,strchr(line,' '),F_SCHAKAL);

/* read in all other information (atomic, symmetry)                       */

  n=0;
  while((fgets(line,LINELEN,MF)!=NULL)&&(!feof(MF)))
  {
    if(sscanf(line,"%s",name)<1) continue;
    name[2]=0;
    strupr(name);
    if(strcmp(name,"AT")==0) n+=Get_Atom_Coordinates(M,strchr(line,' '),F_SCHAKAL);
    else if(strcmp(name,"SY")==0) Get_Symmetry_Operator(M,strchr(line,' '),F_SCHAKAL,S_NORM);
    else if(strcmp(name,"DU")==0) Get_Symmetry_Operator(M,strchr(line,' '),F_SCHAKAL,S_CENT);
  }

  if(n!=num)
  {
    Error_Message(E_BDATOM,"Load Schakal Molecule");
    M->num_atoms=n;
  }
  if(M->mode&CSSG_BIT) M->geneq*=2;

  return(M);
}

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

Mol *Load_Shelx_Molecule(FILE *MF, Mol *M)
{
  char line[LINELEN],name[LINELEN];
  int n;
  char arb1[LINELEN];

  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  M->mode|=FRAC_BIT;              /* default to expect fractional coords. */ 

  if(get_next_line(MF,"TITL",line)==0)
  {
    Error_Message(E_NOTITL,"Load Shelx Molecule");
    n=Get_Molecule_Number(M);
    sprintf(M->name,"M%d",n);
  }
  else sscanf(line,"%s%s",arb1,M->name);
  sprintf(line,"Loading shelx data %s ...",M->name);
  Out_Message(line,O_NEWLN);

/* read in all other information (atomic, symmetry)                       */

  n=0;
  while((n>=0)&&(fgets(line,LINELEN,MF)!=NULL)&&(!feof(MF)))
  {
    if((line[0]==' ')||(sscanf(line,"%s",name)!=1)) continue;
    strupr(name);
    switch(Shelx_Card_Type(name))
    {
      case END : n*=-1; break;
      case CEL : Get_Cell_Parameters(M,strchr(line,' '),F_SHELXL); break;
      case LAT : Get_Lattice(M,strchr(line,' '),F_SHELXL); break;
      case SYM : Get_Symmetry_Operator(M,strchr(line,' '),F_SHELXL,S_NORM); break;
      case ATM : n+=Get_Atom_Coordinates(M,line,F_SHELXL); break;
      default  : break;
    }
  }
  if(n<0) n*=-1;
  M->num_atoms=n;
  if(M->mode&CSSG_BIT) M->geneq*=2;

  return(M);
}

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

Mol *Load_Gstcor_Molecule(FILE *MF, Mol *M, Set *set)
{
  char line[LINELEN],name[LINELEN];
  int n;

  while(fgets(line,LINELEN,MF),!feof(MF))
  {
    if(strncmp(line+8,"**FRAG**",8)==0) break;
  }

  while(strncmp(line+8,"**FRAG**",8)==0)
  {
    if((M=New_Molecule(M))==NULL) return(NULL);
    Initialize_Molecule(M);
    M->mode|=FRAC_BIT;            /* default to expect fractional coords. */ 
    line[8]=0;
    n=strlen(line);
    while(n--,line[n]==' ') line[n]=0;
    strcpy(M->name,line);
    sprintf(line,"Loading gstat coordinate data %s ...",M->name);
    Out_Message(line,O_NEWLN);

/* read in unit cell information, if any                                  */

    n=0;
    while((fgets(line,LINELEN,MF)!=NULL)&&(!feof(MF)))
    {
      if(strncmp(line+8,"**FRAG**",8)==0) break;
      if(sscanf(line,"%s",name)<1) continue;
      strupr(name);
      if(strncmp(name,"SYMM",4)==0) Get_Symmetry_Operator(M,strchr(line,' '),F_GSTCOR,S_NORM);
      else if(strncmp(name,"CELL",4)==0) Get_Cell_Parameters(M,strchr(line,' '),F_GSTCOR);
      else n+=Get_Atom_Coordinates(M,line,F_GSTCOR);
    }
    M->num_atoms=n;
    if(M->mode&CSSG_BIT) M->geneq*=2;

/* create cartesian coordinate vectors                                    */

    Create_Unit_Cell_Atoms(M);
    Convert_to_Cartesian(M);
    Setup_Atomic_Parameters(M,set);
    Find_All_Bonds(M,set,0,0);
    Find_All_Bonded_Groups(M,0);

  }

  return(M);
}

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

Mol *Load_Xtal_Molecule(FILE *MF, Mol *M)
{
  char line[LINELEN],name[LINELEN];
  int num,n;
  char arb1[LINELEN];

/* test that file is really OK                                            */

  if((num=count_lines(MF,"ATOM"))==0)
  {
    Error_Message(E_NOATOM,"Load Xtal Molecule");
    return(NULL);
  }
  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  M->mode|=FRAC_BIT;              /* default to expect fractional coords. */ 

  if(get_next_line(MF,"TITL",line)==0)
  {
    Error_Message(E_NOTITL,"Load Xtal Molecule");
    n=Get_Molecule_Number(M);
    sprintf(M->name,"M%d",n);
  }
  else sscanf(line,"%s%s",arb1,M->name);
  M->num_atoms=num;
  sprintf(line,"Loading xtal data %s ...",M->name);
  Out_Message(line,O_NEWLN);

/* read in all other information (atomic, symmetry)                       */

  n=0;
  while((fgets(line,LINELEN,MF)!=NULL)&&(!feof(MF)))
  {
    if(sscanf(line,"%s",name)<1) continue;
    strupr(name);
    if(strcmp(name,"ATOM")==0) n+=Get_Atom_Coordinates(M,strchr(line,' '),F_XTAL);
    else if(strcmp(name,"SYMTRY")==0) Get_Symmetry_Operator(M,strchr(line,' '),F_XTAL,S_NORM);
    else if(strcmp(name,"LATICE")==0) Get_Lattice(M,strchr(line,' '),F_XTAL);
    else if(strcmp(name,"CELL")==0) Get_Cell_Parameters(M,strchr(line,' '),F_XTAL);
  }

  if(n!=num)
  {
    Error_Message(E_BDATOM,"Load Xtal Molecule");
    M->num_atoms=n;
  }
  if(M->mode&CSSG_BIT) M->geneq*=2;

  return(M);
}

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

Mol *Load_Acryst_Molecule(FILE *MF, Mol *M)
{
  char line[LINELEN];
  int num,n;

/* test that file is really OK                                            */

  if(fgets(line,LINELEN,MF)==NULL) return(NULL);
  if((M=New_Molecule(M))==NULL) return(NULL);
  Initialize_Molecule(M);
  M->mode|=FRAC_BIT;              /* default to expect fractional coords. */ 

  if(strlen(line)<1)
  {
    Error_Message(E_NOTITL,"Load Acryst Molecule");
    n=Get_Molecule_Number(M);
    sprintf(M->name,"M%d",n);
  }
  else sscanf(line,"%s",M->name);
  sprintf(line,"Loading alchemy crystal data %s ...",M->name);
  Out_Message(line,O_NEWLN);

  if(fgets(line,LINELEN,MF)==NULL) return(Close_Current_Molecule(M));

  if((sscanf(line,"%d",&num)!=1)||(num<1))
  {
    Error_Message(E_NOATOM,"Load Acryst Molecule");
    return(Close_Current_Molecule(M));
  }
  M->num_atoms=num;

  if(fgets(line,LINELEN,MF)==NULL)
  {
    Error_Message(E_NOCELL,"Load Acryst Molecule");
    return(Close_Current_Molecule(M));
  }
  if(!Get_Cell_Parameters(M,line,F_ACRYST)) Error_Message(E_BADCEL,"Load Acryst Molecule");

  for(fgets(line,LINELEN,MF),n=0;nnum_atoms=n;
  }
  if(M->mode&CSSG_BIT) M->geneq*=2;

  return(M);
}

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

void New_Extension(char *file, char *newext)
{
  char *ext;
  ext=strrchr(file,'.');
  if((ext!=NULL)&&(ext[-1]=='.')) ext=NULL;
  if(ext!=NULL) ext[0]=0;
  if(newext!=NULL) strcat(file,newext);
}

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

unsigned Get_File_Mode(FILE *in)
{
  char line[LINELEN];
  char line2[LINELEN];
  char line3[LINELEN];
  char f[6][20];
  int num=0;

  rewind(in);
  if(fgets(line,LINELEN,in)==NULL)
    if(feof(in)) return(0);
  if(fgets(line2,LINELEN,in)==NULL)
    if(feof(in)) return(0);
  if(fgets(line3,LINELEN,in)==NULL)
    if(feof(in)) return(0);
  rewind(in);
  strupr(line);
  strupr(line2);
  strupr(line3);
  sscanf(line,"%s%s%s%s%s%s",f[0],f[1],f[2],f[3],f[4],f[5]);

  if(strncmp(line,"#STERIC",7)==0) return(F_STERIN);
  if(strncmp(line,"#STERPAR",8)==0) return(F_STERPAR);
  if(strncmp(line,"STERIC",6)==0) return(F_STERIC);
  if(strncmp(line,"BIOGRF",6)==0) return(F_BIOGRF);
  if(strncmp(line,"!BIOSYM",7)==0) return(F_BIOSYM);
  if((strncmp(line ,"ORIGX1",6)==0)
   &&(strncmp(line2,"ORIGX2",6)==0)
   &&(strncmp(line3,"ORIGX3",6)==0)) return(F_BIOPDB);
  if((strncmp(line,"TITL",4)==0)&&(strncmp(line2,"CELL",4)==0))
  {
    if(strncmp(line3,"ZERR",4)==0) return(F_SHELXL);
    if(strncmp(line3,"LATT",4)==0) return(F_SHELXL);
    return(F_SCHAKAL);
  }
  if(strncmp(line+8,"**FRAG**",8)==0) return(F_GSTCOR);
  if((strcmp(f[1],"ATOMS,")==0)
   &&(strcmp(f[3],"BONDS,")==0)
   &&(strncmp(f[5],"CHARGES,",7)==0)) return(F_ALCHEM);
  if(strncmp(line,"HEADER:",7)==0) return(F_CONFOR);
  if(strncmp(line2,"COMPID",6)==0) return(F_XTAL);
  if((strncmp(line2,"   ",3)==0)&&(sscanf(line2,"%d",&num)==1)&&(num>0)) return(F_ACRYST);
  return(0);
}

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

FILE *Open_Input_File(char *file, unsigned *mode)
{
  FILE *in=NULL;

  if((in=fopen(file,"rt"))==NULL) {
   if(New_Extension(file,".inp"),(in=fopen(file,"rt"))==NULL) {
    if(New_Extension(file,".stc"),(in=fopen(file,"rt"))==NULL) {
     if(New_Extension(file,".bgf"),(in=fopen(file,"rt"))==NULL) {
      if(New_Extension(file,".mol"),(in=fopen(file,"rt"))==NULL) {
       if(New_Extension(file,".trj"),(in=fopen(file,"rt"))==NULL) {
        if(New_Extension(file,".dat"),(in=fopen(file,"rt"))==NULL) {
         if(New_Extension(file,".cor"),(in=fopen(file,"rt"))==NULL) {
          if(New_Extension(file,".cry"),(in=fopen(file,"rt"))==NULL) {
           if(New_Extension(file,".shl"),(in=fopen(file,"rt"))==NULL) {
            if(New_Extension(file,".res"),(in=fopen(file,"rt"))==NULL) {
             if(New_Extension(file,".car"),(in=fopen(file,"rt"))==NULL) {
              if(New_Extension(file,".pdb"),(in=fopen(file,"rt"))==NULL) {
               if(New_Extension(file,""),(in=fopen(file,"rt"))==NULL) {
                Error_Message(E_BDFILE,"Open Input File");
               }
              }
             }
            }
           }
          }
         }
        }
       }
      }
     }
    }
   }
  }
  Out_Message("Opening file ",O_BLANK);
  Out_Message(file,O_NEWLN);
  *mode=Get_File_Mode(in);
  return(in);
}

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

Mol *Load_New_Molecule(char *file, Mol *current, Set *set)
{
  FILE *in;
  unsigned mode=F_STERIC;
  Mol *new=NULL;

  if((in=Open_Input_File(file,&mode))==NULL) return(NULL);
  switch(mode)
  {
    case F_STERPAR: Load_Parameters(set,in,file); return(current); break;
    case F_STERIN : if(set->input!=stdin) fclose(set->input);
                    set->input=in;
                    return(new); break;
    case F_STERIC : new=Load_Steric_Molecule(in,current);
		            break;
    case F_BIOGRF : new=Load_Biograph_Molecule(in,current);
		    break;
    case F_ALCHEM : new=Load_Alchemy_Molecule(in,current);
		    break;
    case F_BIOSYM : new=Load_Biosym_Molecule(in,current,file,set);
		    break;
    case F_BIOPDB : new=Load_PDB_Molecule(in,current,file);
		    break;
    case F_SCHAKAL: new=Load_Schakal_Molecule(in,current);
		    break;
    case F_SHELXL : new=Load_Shelx_Molecule(in,current);
		    break;
    case F_GSTCOR : new=Load_Gstcor_Molecule(in,current,set);
		    break;
    case F_ACRYST : new=Load_Acryst_Molecule(in,current);
		    break;
    case F_XTAL   : new=Load_Xtal_Molecule(in,current);
		    break;
    case F_CONFOR : Error_Message(E_OPCONF,"Load New Molecule"); break;
    default       : Error_Message(E_FTYPE,"Load New Molecule"); break;
  }
  fclose(in);
  if(new==NULL) Error_Message(E_LOAD,"Load New Molecule");
  else
  {
    if((mode==F_SCHAKAL)||(mode==F_SHELXL)||(mode==F_ACRYST)||(mode==F_XTAL))
    {
      Create_Unit_Cell_Atoms(new);
      Convert_to_Cartesian(new);
      Setup_Atomic_Parameters(new,set);
      Find_All_Bonds(new,set,0,0);
      Find_All_Bonded_Groups(new,0);
    }
    else if(mode!=F_GSTCOR) Setup_Atomic_Parameters(new,set);
    New_Extension(file,"");
    strcpy(new->Fname,file);
  }
  return(new);
}

/**************************************************************************/
/***************************  The End ... *********************************/
/**************************************************************************/
Modified: Fri Dec 8 17:00:00 1995 GMT
Page accessed 1217 times since Sat Apr 17 22:00:05 1999 GMT