Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

ComputeAngles.C

Go to the documentation of this file.
00001 
00007 /*
00008    Methods for ComputeAngles.  Main code is for
00009    loading in the AngleElem information and
00010    for computing forces and energies for all angles on node's.
00011    HomePatch(es)
00012 */
00013 
00014 #include "InfoStream.h"
00015 #include "ComputeAngles.h"
00016 #include "Molecule.h"
00017 #include "Parameters.h"
00018 #include "Node.h"
00019 #include "ReductionMgr.h"
00020 #include "Lattice.h"
00021 #include "PressureProfile.h"
00022 #include "Debug.h"
00023 
00024 
00025 // static initialization
00026 int AngleElem::pressureProfileSlabs = 0;
00027 int AngleElem::pressureProfileAtomTypes = 1;
00028 BigReal AngleElem::pressureProfileThickness = 0;
00029 BigReal AngleElem::pressureProfileMin = 0;
00030 
00031 void AngleElem::getMoleculePointers
00032     (Molecule* mol, int* count, int32*** byatom, Angle** structarray)
00033 {
00034 #ifdef MEM_OPT_VERSION
00035   NAMD_die("Should not be called in AngleElem::getMoleculePointers in memory optimized version!");
00036 #else
00037   *count = mol->numAngles;
00038   *byatom = mol->anglesByAtom;
00039   *structarray = mol->angles;
00040 #endif
00041 }
00042 
00043 void AngleElem::getParameterPointers(Parameters *p, const AngleValue **v) {
00044   *v = p->angle_array;
00045 }
00046 
00047 void AngleElem::computeForce(BigReal *reduction, BigReal *pressureProfileData)
00048 {
00049   DebugM(3, "::computeForce() localIndex = " << localIndex[0] << " "
00050                << localIndex[1] << " " << localIndex[2] << std::endl);
00051 
00052   const Position & pos1 = p[0]->x[localIndex[0]].position;
00053   const Lattice & lattice = p[0]->p->lattice;
00054   const Position & pos2 = p[1]->x[localIndex[1]].position;
00055   Vector r12 = lattice.delta(pos1,pos2);
00056   register BigReal d12inv = r12.rlength();
00057   const Position & pos3 = p[2]->x[localIndex[2]].position;
00058   Vector r32 = lattice.delta(pos3,pos2);
00059   register BigReal d32inv = r32.rlength();
00060   int normal = value->normal;
00061 
00062   BigReal cos_theta = (r12*r32)*(d12inv*d32inv);
00063   //  Make sure that the cosine value is acceptable.  With roundoff, you
00064   //  can get values like 1.0+2e-16, which makes acos puke.  So instead,
00065   //  just set these kinds of values to exactly 1.0
00066   if (cos_theta > 1.0) cos_theta = 1.0;
00067   else if (cos_theta < -1.0) cos_theta = -1.0;
00068 
00069   BigReal k = value->k * scale;
00070   BigReal theta0 = value->theta0;
00071 
00072   //  Get theta
00073   BigReal theta = acos(cos_theta);
00074 
00075   //  Compare it to the rest angle
00076   BigReal diff;
00077 
00078   if (normal == 1) {
00079     diff = theta - theta0;
00080   } else {
00081     diff = cos_theta - cos(theta0);
00082   }
00083   
00084   //  Add the energy from this angle to the total energy
00085   BigReal energy = k *diff*diff;
00086 
00087   //  Normalize vector r12 and r32
00088   //BigReal d12inv = 1. / d12;
00089   //BigReal d32inv = 1. / d32;
00090 
00091 
00092   //  Calculate constant factor 2k(theta-theta0)/sin(theta)
00093   BigReal sin_theta = sqrt(1.0 - cos_theta*cos_theta);
00094   if (normal != 1) {
00095     diff *= (2.0* k);
00096   } else if ( sin_theta < 1.e-6 ) {
00097     // catch case where bonds are parallel
00098     // this gets the force approximately right for theta0 of 0 or pi
00099     // and at least avoids small division for other values
00100     if ( diff < 0. ) diff = 2.0 * k;
00101     else diff = -2.0 * k;
00102   } else { 
00103     diff *= (-2.0* k) / sin_theta; 
00104   }
00105   BigReal c1 = diff * d12inv;
00106   BigReal c2 = diff * d32inv;
00107 
00108   //  Calculate the actual forces
00109   Force force1 = c1*(r12*(d12inv*cos_theta) - r32*d32inv);
00110   Force force2 = force1;
00111   Force force3 = c2*(r32*(d32inv*cos_theta) - r12*d12inv);
00112   force2 += force3;  force2 *= -1;
00113 
00114   //  Check to see if we need to do the Urey-Bradley term
00115   if (value->k_ub)
00116   {
00117         //  Non-zero k_ub value, so calculate the harmonic
00118         //  potential between the 1-3 atoms
00119 
00120   if (normal != 1) {
00121     NAMD_die("ERROR: Can't use cosAngles with Urey-Bradley angles");
00122   }
00123         BigReal k_ub = value->k_ub;
00124         BigReal r_ub = value->r_ub;
00125         Vector r13 = r12 - r32;
00126         BigReal d13 = r13.length();
00127         diff = d13- r_ub;
00128 
00129         energy += k_ub *diff*diff;
00130 
00131         diff *= -2.0*k_ub / d13;
00132         r13 *= diff;
00133 
00134         force1 += r13;
00135         force3 -= r13;
00136   }
00137 
00138   p[0]->f[localIndex[0]].x += force1.x;
00139   p[0]->f[localIndex[0]].y += force1.y;
00140   p[0]->f[localIndex[0]].z += force1.z;
00141 
00142   p[1]->f[localIndex[1]].x += force2.x;
00143   p[1]->f[localIndex[1]].y += force2.y;
00144   p[1]->f[localIndex[1]].z += force2.z;
00145 
00146   p[2]->f[localIndex[2]].x += force3.x;
00147   p[2]->f[localIndex[2]].y += force3.y;
00148   p[2]->f[localIndex[2]].z += force3.z;
00149 
00150   DebugM(3, "::computeForce() -- ending with delta energy " << energy << std::endl);
00151 
00152   reduction[angleEnergyIndex] += energy;
00153   reduction[virialIndex_XX] += ( force1.x * r12.x + force3.x * r32.x );
00154   reduction[virialIndex_XY] += ( force1.x * r12.y + force3.x * r32.y );
00155   reduction[virialIndex_XZ] += ( force1.x * r12.z + force3.x * r32.z );
00156   reduction[virialIndex_YX] += ( force1.y * r12.x + force3.y * r32.x );
00157   reduction[virialIndex_YY] += ( force1.y * r12.y + force3.y * r32.y );
00158   reduction[virialIndex_YZ] += ( force1.y * r12.z + force3.y * r32.z );
00159   reduction[virialIndex_ZX] += ( force1.z * r12.x + force3.z * r32.x );
00160   reduction[virialIndex_ZY] += ( force1.z * r12.y + force3.z * r32.y );
00161   reduction[virialIndex_ZZ] += ( force1.z * r12.z + force3.z * r32.z );
00162 
00163   if (pressureProfileData) {
00164     BigReal z1 = p[0]->x[localIndex[0]].position.z;
00165     BigReal z2 = p[1]->x[localIndex[1]].position.z;
00166     BigReal z3 = p[2]->x[localIndex[2]].position.z;
00167     int n1 = (int)floor((z1-pressureProfileMin)/pressureProfileThickness);
00168     int n2 = (int)floor((z2-pressureProfileMin)/pressureProfileThickness);
00169     int n3 = (int)floor((z3-pressureProfileMin)/pressureProfileThickness);
00170     pp_clamp(n1, pressureProfileSlabs);
00171     pp_clamp(n2, pressureProfileSlabs);
00172     pp_clamp(n3, pressureProfileSlabs);
00173     int p1 = p[0]->x[localIndex[0]].partition;
00174     int p2 = p[1]->x[localIndex[1]].partition;
00175     int p3 = p[2]->x[localIndex[2]].partition;
00176     int pn = pressureProfileAtomTypes;
00177     pp_reduction(pressureProfileSlabs, n1, n2, 
00178                 p1, p2, pn,
00179                 force1.x * r12.x, force1.y * r12.y, force1.z * r12.z,
00180                 pressureProfileData);
00181     pp_reduction(pressureProfileSlabs, n3, n2, 
00182                 p3, p2, pn,
00183                 force3.x * r32.x, force3.y * r32.y, force3.z * r32.z,
00184                 pressureProfileData);
00185   }
00186 }
00187 
00188 
00189 void AngleElem::submitReductionData(BigReal *data, SubmitReduction *reduction)
00190 {
00191   reduction->item(REDUCTION_ANGLE_ENERGY) += data[angleEnergyIndex];
00192   ADD_TENSOR(reduction,REDUCTION_VIRIAL_NORMAL,data,virialIndex);
00193 }
00194 

Generated on Sat May 25 04:07:15 2013 for NAMD by  doxygen 1.3.9.1