/* * File: build.c * ************************************************************************ * LEAP * * * * Copyright (c) 1992, 1995 * * Regents of the University of California * * All Rights Reserved. * * * * This software provided pursuant to a license agreement containing * * restrictions on its disclosure, duplication, and use. This software * * contains confidential and proprietary information, and may not be * * extracted or distributed, in whole or in part, for any purpose * * whatsoever, without the express written permission of the authors. * * This notice, and the associated author list, must be attached to * * all copies, or extracts, of this software. Any additional * * restrictions set forth in the license agreement also apply to this * * software. * ************************************************************************ * * * Designed by: Christian Schafmeister * * Author: Christian Schafmeister * * * * VERSION: 1.0 * * Programmers: * * Christian Schafmeister * * David Rivkin * * * * Principal Investigator: Peter A. Kollman * * * ************************************************************************ * * Description: * * This file contains routines which are used to * make changes to the coordinates of ATOMs. * * It contains code to generate internal coordinates * from externals, make changes to internals, and * then generate externals from internals. * */ #include "basics.h" #include "vector.h" #include "matrix.h" #include "zMatrix.h" #include "classes.h" #include "chirality.h" #include "minimizer.h" #include "parmLib.h" #include "model.h" #include "build.h" #include "sort.h" #include "graphUtil.h" #define MAXNEWTONSTEPS 20 /* ------------------------------------------------------------------ Private routines */ /* * zaBuildFindNextAtomWithNameButNot * * Author: Christian Schafmeister (1991) * * Look over all the neighbors of aA for an ATOM with * the name sName. Ignore an ATOM if it is the * same ATOM as aB. If you find one, return it, otherwise * return NULL. */ static ATOM zaBuildFindNextAtomWithNameButNot( ATOM aA, char *sName, ATOM aB ) { int i; ATOM aNeighbor; for ( i=0; i 1 ) return(FALSE); if ( !bAllSame ) return(FALSE); if ( i != 6 ) return(FALSE); /* If SP2 ring then create INTERNALs for a BENZENE skeleton */ if ( iHybridization == HSP2 ) { MESSAGE(( "Building BENZENE skeleton\n" )); iInternalTorsion( aaA[0], aaA[1], aaA[2], aaA[3], 0.0 ); iInternalTorsion( aaA[1], aaA[2], aaA[3], aaA[4], 0.0 ); iInternalTorsion( aaA[2], aaA[3], aaA[4], aaA[5], 0.0 ); iInternalTorsion( aaA[3], aaA[4], aaA[5], aaA[0], 0.0 ); iInternalTorsion( aaA[4], aaA[5], aaA[0], aaA[1], 0.0 ); iInternalTorsion( aaA[5], aaA[0], aaA[1], aaA[2], 0.0 ); return(TRUE); } /* If SP3 ring then create INTERNALs for a CYCLOHEXANE */ if ( iHybridization == HSP3 ) { MESSAGE(( "Building CYCLOHEXANE skeleton\n" )); iInternalTorsion( aaA[0], aaA[1], aaA[2], aaA[3], 60.0*DEGTORAD ); iInternalTorsion( aaA[1], aaA[2], aaA[3], aaA[4], -60.0*DEGTORAD ); iInternalTorsion( aaA[2], aaA[3], aaA[4], aaA[5], 60.0*DEGTORAD ); iInternalTorsion( aaA[3], aaA[4], aaA[5], aaA[0], -60.0*DEGTORAD ); iInternalTorsion( aaA[4], aaA[5], aaA[0], aaA[1], 60.0*DEGTORAD ); iInternalTorsion( aaA[5], aaA[0], aaA[1], aaA[2], -60.0*DEGTORAD ); return(TRUE); } return(FALSE); } /* *==================================================================== *==================================================================== *==================================================================== * * Public routines. * */ /* * BuildInternalsUsingFlags * * Author: Christian Schafmeister (1991) * * Build INTERNALs for all ATOMs defined by the LOOP. * Build INTERNALs only for ATOMs that have the flags * (fForSet) set and (fForReset) reset. Each ATOM that * has INTERNALs build will have (fSetFlags) set and (fResetFlags) * reset. */ void BuildInternalsUsingFlags( LOOP *lPAtoms, FLAGS fForSet, FLAGS fForReset, FLAGS fSetFlags, FLAGS fResetFlags ) { ATOM aAtom; LoopUseMemory(lPAtoms); while ( aAtom = (ATOM)oNext(lPAtoms) ) { if ( bAtomFlagsSet( aAtom, fForSet ) && bAtomFlagsReset( aAtom, fForReset ) ) { BuildInternalsForOneAtom( aAtom ); } } /* Change the flags */ LoopRewindMemory(lPAtoms); while ( aAtom=(ATOM)oNext(lPAtoms) ) { if ( bAtomFlagsSet( aAtom, fForSet ) && bAtomFlagsReset( aAtom, fForReset ) ) { AtomSetFlags( aAtom, fSetFlags ); AtomResetFlags( aAtom, fResetFlags ); } } LoopDestroyMemory(lPAtoms); } /* * BuildExternalsUsingFlags * * Author: Christian Schafmeister (1991) * * Build the external coordinates from the internal coordinates. * ALL internal coordinates must be specified, and reasonable, * and preferably internally consistant. * * The caller passes a LOOP structure that embodies * a spanning tree over the atoms that are to be built. * The spanning tree is passed instead of the atom to start * on so that the caller can set LOOP flags that make certian * types of ATOMs invisible to the builder, preventing coordinates * being built for those atoms. * * The builder works by generating a Z-Matrix for the atoms * defined in the LOOP. It traverses the spanning tree * and for each atom searches for a torsion/angle/bond that * contains other atoms whose positions are known. It * then uses these internal coordinates to build the external * coordinate for that atom. * * Only ATOMs that have flags (fForSet) set and (fForReset) reset * will have externals build. As each external is build, * (fSetFlags) will be set and (fResetFlags) will be reset. */ void BuildExternalsUsingFlags( LOOP *lPLoop, FLAGS fForSet, FLAGS fForReset, FLAGS fSetFlags, FLAGS fResetFlags, int *iPAddH, int *iPAddHeavy, int *iPAddUnk, BOOL bMsg ) { ATOM aAtom; STRING sTemp; /* Go through each atom and build its coordinates */ LoopUseMemory(lPLoop); while ( (aAtom=(ATOM)oNext(lPLoop))!= NULL ) { if ( bAtomFlagsSet( aAtom, fForSet ) && bAtomFlagsReset( aAtom, fForReset ) ) { BuildExternalForOneAtom( aAtom ); if ( iAtomElement( aAtom ) == NOELEMENT ) (*iPAddUnk)++; else if ( iAtomElement( aAtom ) <= HYDROGEN ) (*iPAddH)++; else { (*iPAddHeavy)++; if ( bMsg ) VP0((" Added missing heavy atom: %s\n", sContainerFullDescriptor( (CONTAINER)aAtom, sTemp ) )); } } } /* Change the flags */ LoopRewindMemory(lPLoop); while ( aAtom=(ATOM)oNext(lPLoop) ) { if ( bAtomFlagsSet( aAtom, fForSet ) && bAtomFlagsReset( aAtom, fForReset ) ) { MESSAGE(( "Updating flags for: %s\n", sContainerFullDescriptor((CONTAINER)aAtom,sTemp) )); AtomSetFlags( aAtom, fSetFlags ); AtomResetFlags( aAtom, fResetFlags ); } } LoopDestroyMemory(lPLoop); } /* * BuildInternalsForContainer * * Author: Christian Schafmeister (1991) * * Build INTERNALs for all internals within the container. * Set all of the (fSet) flags on all the ATOMs and reset all of * the (fReset) flags. * * This routine is much faster than BuildInternalsWithFlags * because it does not worry about duplicating INTERNALs * because it loops over all internals in the CONTAINER, * not all internals on each ATOM. */ void BuildInternalsForContainer( CONTAINER cCont, FLAGS fSet, FLAGS fReset ) { ATOM aTemp; ATOM a1, a2, a3; LOOP lTemp; STRING s1, s2, s3; double dValue; MESSAGE(( "Building internals for: %s\n", sContainerName(cCont) )); /* Build torsion angles */ /* These have to be built a special way, because */ /* torsion INTERNALs cannot be simply looked up in a table */ /* The model builder has code to add torsion INTERNALs */ /* around central pairs of ATOMs taking into account any */ /* external coordinates that may be defined already */ LOOPOVERALL( cCont, BONDS, aTemp, ATOM, lTemp ) { LoopGetBond( &lTemp, &a2, &a3 ); if ( iAtomCoordination(a2) <= 1 ) continue; if ( iAtomCoordination(a3) <= 1 ) continue; /* Assign INTERNALs for ALL torsions around (a2), (a3) */ MESSAGE(( "Building torsion INTERNALs around: %s - %s\n", sContainerFullDescriptor( (CONTAINER)a2, s2 ), sContainerFullDescriptor( (CONTAINER)a3, s3 ) )); ModelAssignTorsionsAround( a2, a3, NULL ); } /* Build bond angles */ LOOPOVERALL( cCont, ANGLES, aTemp, ATOM, lTemp ) { LoopGetAngle( &lTemp, &a1, &a2, &a3 ); MESSAGE(( "Building angle INTERNAL for: %s - %s - %s\n", sContainerFullDescriptor( (CONTAINER)a1, s1 ), sContainerFullDescriptor( (CONTAINER)a2, s2 ), sContainerFullDescriptor( (CONTAINER)a3, s3 ) )); if ( bAtomFlagsSet( a1, ATOMPOSITIONKNOWN ) && bAtomFlagsSet( a2, ATOMPOSITIONKNOWN ) && bAtomFlagsSet( a3, ATOMPOSITIONKNOWN ) ) { dValue = dVectorAtomAngle( &vAtomPosition(a1), &vAtomPosition(a2), &vAtomPosition(a3) ); MESSAGE(( "Got bond angle from externals\n" )); } else { dValue = dModelBondAngle( a1, a2, a3 ); MESSAGE(( "Got bond angle from model builder\n" )); } MESSAGE(( "++++Angle INTERNAL: %lf for %s - %s - %s\n", dValue/DEGTORAD, sContainerFullDescriptor((CONTAINER)a1,s1), sContainerFullDescriptor((CONTAINER)a2,s2), sContainerFullDescriptor((CONTAINER)a3,s3) )); iInternalAngle( a1, a2, a3, dValue ); } /* Build bond internals */ LOOPOVERALL( cCont, BONDS, aTemp, ATOM, lTemp ) { LoopGetBond( &lTemp, &a1, &a2 ); MESSAGE(( "Building bond INTERNAL for: %s - %s\n", sContainerFullDescriptor( (CONTAINER)a1, s1 ), sContainerFullDescriptor( (CONTAINER)a2, s2 ) )); if ( bAtomFlagsSet( a1, ATOMPOSITIONKNOWN ) && bAtomFlagsSet( a2, ATOMPOSITIONKNOWN ) ) { dValue = dVectorAtomLength( &vAtomPosition(a1), &vAtomPosition(a2) ); MESSAGE(( "Got bond length from externals\n" )); } else { dValue = dModelBondLength( a1, a2 ); MESSAGE(( "Got bond length from the model builder\n" )); } iInternalBond( a1, a2, dValue ); MESSAGE(( "++++Bond INTERNAL: %lf for %s - %s\n", dValue, sContainerFullDescriptor((CONTAINER)a1,s1), sContainerFullDescriptor((CONTAINER)a2,s2) )); } /* Build chirality */ /* Chirality is only defined for atoms with 3 or 4 bonds */ /* Chirality is the only INTERNAL that does not */ /* need to be specified */ LOOPOVERALL( cCont, ATOMS, aTemp, ATOM, lTemp ) { dValue = dChiralityForAtom(aTemp); AtomSetFlags( aTemp, fSet ); AtomResetFlags( aTemp, fReset ); if ( dValue != 0.0 ) { iInternalChirality( aTemp, dValue ); MESSAGE(( "Got chirality from external coordinates\n" )); MESSAGE(( "++++Chirality INTERNAL: %lf for %s\n", dValue, sContainerFullDescriptor((CONTAINER)aTemp,s1) )); } else { MESSAGE(( "Left chirality undefined\n" )); } } } /* * BuildDestroyInternals * * Author: Christian Schafmeister (1991) * * Destroy all of the INTERNALs on the ATOMs in the (lPLoop). * (lPLoop) must be a LOOP over ATOMs. * */ void BuildDestroyInternals( LOOP *lPLoop ) { LOOP lInternals; INTERNAL iInt; ATOM aAtom; #ifdef DEBUG STRING sTemp; #endif MESSAGE(( "Destroying all INTERNALs in the LOOP\n" )); while ( ( aAtom=(ATOM)oNext(lPLoop) ) != NULL ) { MESSAGE(( "Destroying INTERNALs on: %s\n", sContainerFullDescriptor((CONTAINER)aAtom,sTemp) )); lInternals = lLoop( (OBJEKT)aAtom, INTERNALS ); #ifdef DEBUG while ( ( iInt=(INTERNAL)oNext(&lInternals) ) != NULL ) { MESSAGE(( " Internal type = %c at: %lX\n", iInternalType(iInt), iInt )); } #endif lInternals = lLoop( (OBJEKT)aAtom, INTERNALS ); while ( ( iInt=(INTERNAL)oNext(&lInternals) ) != NULL ) { MESSAGE(( " destroying = %c at: %lX\n", iInternalType(iInt), iInt )); Destroy( (OBJEKT *)&iInt ); } } } /* * BuildFixInternals * * Author: Christian Schafmeister (1991) * * When external coordinates are imposed on a structure * that has internal coordinates defined, there will be * inconsistancies in the torsions between the internals * and externals. This routine attempts to resolve these * inconsistancies by changing the internal torsions to * match the externals. * * Loop through all bonds, looking for bonds that lie * at the center of torsions. Look at all of the torsions that * share the bond as a center and calculate the actual torsion * angle for each torsion. If any of the calculated torsion angles * is different than the value of the INTERNAL then choose one and * calculate the difference between the INTERNAL and the calculated * and add it to all of the INTERNAL torsions. */ void BuildFixInternals( UNIT uUnit ) { INTERNAL iaTorsions[MAXTORSIONSAROUNDBOND], iInt; int iNextTorsion; double dTorsion; BOOL bFoundOne; LOOP lBonds; ATOM aAtom2, aAtom3; int i; double dSub, dNew; STRING sAtom1, sAtom2, sAtom3, sAtom4; MESSAGE(( "In BuildFixInternals -----------\n" )); /* Loop over all bonds */ /* looking for torsions */ lBonds = lLoop( (OBJEKT)uUnit, BONDS ); while ( oNext(&lBonds) != NULL ) { LoopGetBond( &lBonds, &aAtom2, &aAtom3 ); MESSAGE(( "Looking at torsions around: %s - %s\n", sContainerFullDescriptor((CONTAINER)aAtom2,sAtom2), sContainerFullDescriptor((CONTAINER)aAtom3,sAtom3) )); /* Look at all the INTERNALs of aAtom2 */ /* looking for torsions which have aAtom2 and */ /* aAtom3 as the center of the torsion */ iNextTorsion = iInternalFindAllTorsionInternalsAround( aAtom2, aAtom3, iaTorsions ); /* Look at these torsions and if all of the coordinates */ /* are defined then calculate the angle. Compare the */ /* calculated with the IMPROPER and if they are different */ /* calculate the difference */ bFoundOne = FALSE; for ( i=0; i 0 ) { aTemp = aLoopLastCollisionAtom(&lSpan); rRes = (RESIDUE)cContainerWithin(aTemp); mMol = (MOLECULE)cContainerWithin(rRes); } else { /* Create a new MOLECULE */ mMol = (MOLECULE)oCreate(MOLECULEid); ContainerSetName( (CONTAINER)mMol, "???" ); ContainerAdd( (CONTAINER)uUnit, (OBJEKT)mMol ); } /* Search for a collision with an invisible atom */ /* which will be contained within a MOLECULE to which */ /* all of the residues should be added */ /* Remove all the the spanning tree ATOMs from the UNIT */ /* and put them in the RESIDUE */ lSpan = lLoop( (OBJEKT)aAtom, SPANNINGTREE ); LoopDefineInvisibleAtoms( &lSpan, ATOMTOUCHED ); while ( (aAtom2=(ATOM)oNext(&lSpan)) != NULL ) { rRes = (RESIDUE)cContainerWithin((CONTAINER)aAtom2); if ( iObjectType(cContainerWithin((CONTAINER)rRes))==UNITid ) { bContainerRemove( (CONTAINER)uUnit, (OBJEKT)rRes ); ContainerAdd( (CONTAINER)mMol, (OBJEKT)rRes ); } AtomSetFlags( aAtom2, ATOMTOUCHED ); } } } /* * bBuildChangeInternalBond * * Author: Christian Schafmeister (1991) * * Change the bond INTERNAL for the specified atoms within * the CONTAINER. * This routine assumes that the atoms within the CONTAINER * have all of their INTERNAL coordinates. * This function searches through the CONTAINER for the * atom with name sName, and then looks for the other atoms * that are bonded in a chain. If it doesn't find it, it * returns FALSE, otherwise it finds the INTERNAL that * contains all of the ATOMs and changes the value of * the INTERNAL to what the caller specified. */ BOOL bBuildChangeInternalBond( CONTAINER cCont, char *sAtom1, char *sAtom2, double dValue ) { ATOM aAtom1, aAtom2; INTERNAL iInt; /* Find the first named ATOM within the container */ aAtom1 = (ATOM)cContainerFindName( cCont, ATOMid, sAtom1 ); if ( aAtom1 == NULL ) return(FALSE); /* Find the bonded ATOM that has the required name */ aAtom2 = zaBuildFindNextAtomWithNameButNot( aAtom1, sAtom2, NULL ); if ( aAtom2 == NULL ) return(FALSE); /* Find the INTERNAL for the ATOMs */ iInt = iInternalFindBond( aAtom1, aAtom2 ); /* Change it's value */ InternalSetValue( iInt, dValue ); return(TRUE); } /* * bBuildChangeInternalAngle * * Author: Christian Schafmeister (1991) * * Change the angle INTERNAL for the specified atoms within * the CONTAINER. * The value dValue is in RADIANS. * This routine assumes that the atoms within the CONTAINER * have all of their INTERNAL coordinates. * This function searches through the CONTAINER for the * atom with name sName, and then looks for the other atoms * that are bonded in a chain. If it doesn't find it, it * returns FALSE, otherwise it finds the INTERNAL that * contains all of the ATOMs and changes the value of * the INTERNAL to what the caller specified. */ BOOL bBuildChangeInternalAngle( CONTAINER cCont, char *sAtom1, char *sAtom2, char *sAtom3, double dValue ) { ATOM aAtom1, aAtom2, aAtom3; INTERNAL iInt; /* Find the first named ATOM within the container */ aAtom1 = (ATOM)cContainerFindName( cCont, ATOMid, sAtom1 ); if ( aAtom1 == NULL ) return(FALSE); /* Find the bonded ATOM that has the required name */ aAtom2 = zaBuildFindNextAtomWithNameButNot( aAtom1, sAtom2, NULL ); if ( aAtom2 == NULL ) return(FALSE); aAtom3 = zaBuildFindNextAtomWithNameButNot( aAtom2, sAtom3, aAtom1 ); if ( aAtom3 == NULL ) return(FALSE); /* Find the INTERNAL for the ATOMs */ iInt = iInternalFindAngle( aAtom1, aAtom2, aAtom3 ); /* Change it's value */ InternalSetValue( iInt, dValue ); return(TRUE); } /* * bBuildChangeInternalTorsion * * Author: Christian Schafmeister (1991) * * Change the torsion INTERNAL for the specified atoms within * the CONTAINER. * The value dValue must be in RADIANS. * This routine assumes that the atoms within the CONTAINER * have all of their INTERNAL coordinates. * This function searches through the CONTAINER for the * atom with name sName, and then looks for the other atoms * that are bonded in a chain. If it doesn't find it, it * returns FALSE, otherwise it finds the INTERNAL that * contains all of the ATOMs and twists all torsions * around the central pair of atoms to make the torsion * the caller requested the correct value. */ BOOL bBuildChangeInternalTorsion( CONTAINER cCont, char *sAtom1, char *sAtom2, char *sAtom3, char *sAtom4, double dValue ) { ATOM aAtom1, aAtom2, aAtom3, aAtom4; INTERNAL iInt, iaTorsions[MAXTORSIONSAROUNDBOND]; double dAdd, dTorsion; int i, iTorsions; STRING s1, s2, s3, s4; /* Find the first named ATOM within the container */ aAtom1 = (ATOM)cContainerFindName( cCont, ATOMid, sAtom1 ); if ( aAtom1 == NULL ) return(FALSE); /* Find the bonded ATOM that has the required name */ aAtom2 = zaBuildFindNextAtomWithNameButNot( aAtom1, sAtom2, NULL ); if ( aAtom2 == NULL ) return(FALSE); aAtom3 = zaBuildFindNextAtomWithNameButNot( aAtom2, sAtom3, aAtom1 ); if ( aAtom3 == NULL ) return(FALSE); aAtom4 = zaBuildFindNextAtomWithNameButNot( aAtom3, sAtom4, aAtom2 ); if ( aAtom4 == NULL ) return(FALSE); /* Find the INTERNAL for the ATOMs */ iInt = iInternalFindTorsion( aAtom1, aAtom2, aAtom3, aAtom4 ); MESSAGE(( "Currently the internal between: %s-%s-%s-%s is: %lf\n", sContainerFullDescriptor((CONTAINER)aAtom1,s1), sContainerFullDescriptor((CONTAINER)aAtom2,s2), sContainerFullDescriptor((CONTAINER)aAtom3,s3), sContainerFullDescriptor((CONTAINER)aAtom4,s4), dInternalValue(iInt)/DEGTORAD )); /* Find the amount we have to twist all the other torsions */ dAdd = dValue - dInternalValue( iInt ); MESSAGE(( "Going to twist all torsions around: %s - %s by %lf\n", sContainerName(aAtom2), sContainerName(aAtom3), dAdd/DEGTORAD )); /* Get all of the torsions around the center pair of atoms */ iTorsions = iInternalFindAllTorsionInternalsAround( aAtom2, aAtom3, iaTorsions ); /* Change all of the torsions */ for ( i=0; i %s inRing: %s\n", sAtomName(aInv), sAtomName(aStart), sBOOL(bInRing) )); /* If the bond to be rotated around is not within a ring */ /* then just rotate, otherwise do something different */ if ( !bInRing ) { lSpan = lLoop( (OBJEKT)aStart, SPANNINGTREE ); LoopDefineInvisibleAtom( &lSpan, aInv ); while ( aAtom = (ATOM)oNext(&lSpan ) ) { vPos = vAtomPosition(aAtom); MatrixTimesVector( vNew, mTransform, vPos ); AtomSetPosition( aAtom, vNew ); } } else { for ( j=0; j 4 ) return; MESSAGE(( "The coordination of the ATOM to flip is: %d\n", iAtomCoordination(aFlip) )); MESSAGE(( "About to flip: %s\n", sAtomName(aFlip) )); /* Find the two side chains with the least number of ATOMs */ for ( i=0; i 1 ) { lAtoms = lLoop( (OBJEKT)cContainer, ATOMS ); BuildDestroyInternals( &lAtoms ); MESSAGE(( "Cannot flip! There is more than one ring\n" )); return; } /* If there is a ring then find the ATOMs that are */ /* bonded but not in the ring and put them in aA, aB */ /* And put the ATOMs that are in the ring in aFixA, aFixB */ if ( iCountRings == 1 ) { MESSAGE(( "Atom to flip is in a ring\n" )); aA = NULL; aB = NULL; aFixA = NULL; aFixB = NULL; for ( i=0; i