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

ComputeImpropers.C

Go to the documentation of this file.
00001 
00007 #include "InfoStream.h"
00008 #include "ComputeImpropers.h"
00009 #include "Molecule.h"
00010 #include "Parameters.h"
00011 #include "Node.h"
00012 #include "ReductionMgr.h"
00013 #include "Lattice.h"
00014 #include "PressureProfile.h"
00015 #include "Debug.h"
00016 
00017 
00018 // static initialization
00019 int ImproperElem::pressureProfileSlabs = 0;
00020 int ImproperElem::pressureProfileAtomTypes = 1;
00021 BigReal ImproperElem::pressureProfileThickness = 0;
00022 BigReal ImproperElem::pressureProfileMin = 0;
00023 
00024 void ImproperElem::getMoleculePointers
00025     (Molecule* mol, int* count, int32*** byatom, Improper** structarray)
00026 {
00027 #ifdef MEM_OPT_VERSION
00028   NAMD_die("Should not be called in ImproperElem::getMoleculePointers in memory optimized version!");
00029 #else
00030   *count = mol->numImpropers;
00031   *byatom = mol->impropersByAtom;
00032   *structarray = mol->impropers;
00033 #endif
00034 }
00035 
00036 void ImproperElem::getParameterPointers(Parameters *p, const ImproperValue **v) {
00037   *v = p->improper_array;
00038 }
00039 
00040 void ImproperElem::computeForce(BigReal *reduction,
00041                                 BigReal *pressureProfileData)
00042 {
00043   DebugM(3, "::computeForce() localIndex = " << localIndex[0] << " "
00044                << localIndex[1] << " " << localIndex[2] << " " <<
00045                localIndex[3] << std::endl);
00046 
00047   // Vector r12, r23, r34;      // vector between atoms
00048   Vector A,B,C;         // cross products
00049   BigReal rA, rB, rC;   // length of vectors A, B, and C
00050   BigReal energy=0;     // energy from the angle
00051   BigReal phi;          // angle between the plans
00052   double cos_phi;       // cos(phi)
00053   double sin_phi;       // sin(phi)
00054   Vector dcosdA;        // Derivative d(cos(phi))/dA
00055   Vector dcosdB;        // Derivative d(cos(phi))/dB
00056   Vector dsindC;        // Derivative d(sin(phi))/dC
00057   Vector dsindB;        // Derivative d(sin(phi))/dB
00058   BigReal K,K1;         // energy constants
00059   BigReal diff;         // for periodicity
00060   Force f1(0,0,0),f2(0,0,0),f3(0,0,0);  // force components
00061 
00062   //DebugM(3, "::computeForce() -- starting with improper type " << improperType << std::endl);
00063 
00064   // get the improper information
00065   int multiplicity = value->multiplicity;
00066 
00067   //  Calculate the vectors between atoms
00068   const Position & pos0 = p[0]->x[localIndex[0]].position;
00069   const Position & pos1 = p[1]->x[localIndex[1]].position;
00070   const Position & pos2 = p[2]->x[localIndex[2]].position;
00071   const Position & pos3 = p[3]->x[localIndex[3]].position;
00072   const Lattice & lattice = p[0]->p->lattice;
00073   const Vector r12 = lattice.delta(pos0,pos1);
00074   const Vector r23 = lattice.delta(pos1,pos2);
00075   const Vector r34 = lattice.delta(pos2,pos3);
00076 
00077   //  Calculate the cross products
00078   A = cross(r12,r23);
00079   B = cross(r23,r34);
00080   C = cross(r23,A);
00081 
00082   //  Calculate the distances
00083   rA = A.length();
00084   rB = B.length();
00085   rC = C.length();
00086 
00087   //  Calculate the sin and cos
00088   cos_phi = A*B/(rA*rB);
00089   sin_phi = C*B/(rC*rB);
00090 
00091   //  Normalize B
00092   rB = 1.0/rB;
00093   B *= rB;
00094 
00095   phi= -atan2(sin_phi,cos_phi);
00096 
00097   if (fabs(sin_phi) > 0.1)
00098   {
00099     //  Normalize A
00100     rA = 1.0/rA;
00101     A *= rA;
00102     dcosdA = rA*(cos_phi*A-B);
00103     dcosdB = rB*(cos_phi*B-A);
00104   }
00105   else
00106   {
00107     //  Normalize C
00108     rC = 1.0/rC;
00109     C *= rC;
00110     dsindC = rC*(sin_phi*C-B);
00111     dsindB = rB*(sin_phi*B-C);
00112   }
00113 
00114   //  Loop through the multiple parameter sets for this
00115   //  bond.  We will only loop more than once if this
00116   //  has multiple parameter sets from Charmm22
00117   for (int mult_num=0; mult_num<multiplicity; mult_num++)
00118   {
00119     /* get angle information */
00120     Real k = value->values[mult_num].k * scale;
00121     Real delta = value->values[mult_num].delta;
00122     int n = value->values[mult_num].n;
00123 
00124     //  Calculate the energy
00125     if (n)
00126     {
00127       //  Periodicity is greater than 0, so use cos form
00128       K = k*(1+cos(n*phi - delta));
00129       K1 = -n*k*sin(n*phi - delta);
00130     }
00131     else
00132     {
00133       //  Periodicity is 0, so just use the harmonic form
00134       diff = phi-delta;
00135       if (diff < -PI)           diff += TWOPI;
00136       else if (diff > PI)       diff -= TWOPI;
00137 
00138       K = k*diff*diff;
00139       K1 = 2.0*k*diff;
00140     }
00141 
00142     //  Add the energy from this improper to the total energy
00143     energy += K;
00144 
00145     //  Next, we want to calculate the forces.  In order
00146     //  to do that, we first need to figure out whether the
00147     //  sin or cos form will be more stable.  For this,
00148     //  just look at the value of phi
00149     if (fabs(sin_phi) > 0.1)
00150     {
00151       //  use the sin version to avoid 1/cos terms
00152       K1 = K1/sin_phi;
00153 
00154       f1.x += K1*(r23.y*dcosdA.z - r23.z*dcosdA.y);
00155       f1.y += K1*(r23.z*dcosdA.x - r23.x*dcosdA.z);
00156       f1.z += K1*(r23.x*dcosdA.y - r23.y*dcosdA.x);
00157 
00158       f3.x += K1*(r23.z*dcosdB.y - r23.y*dcosdB.z);
00159       f3.y += K1*(r23.x*dcosdB.z - r23.z*dcosdB.x);
00160       f3.z += K1*(r23.y*dcosdB.x - r23.x*dcosdB.y);
00161 
00162       f2.x += K1*(r12.z*dcosdA.y - r12.y*dcosdA.z
00163                + r34.y*dcosdB.z - r34.z*dcosdB.y);
00164       f2.y += K1*(r12.x*dcosdA.z - r12.z*dcosdA.x
00165                + r34.z*dcosdB.x - r34.x*dcosdB.z);
00166       f2.z += K1*(r12.y*dcosdA.x - r12.x*dcosdA.y
00167              + r34.x*dcosdB.y - r34.y*dcosdB.x);
00168     }
00169     else
00170     {
00171       //  This angle is closer to 0 or 180 than it is to
00172       //  90, so use the cos version to avoid 1/sin terms
00173       K1 = -K1/cos_phi;
00174 
00175       f1.x += K1*((r23.y*r23.y + r23.z*r23.z)*dsindC.x
00176                 - r23.x*r23.y*dsindC.y
00177                 - r23.x*r23.z*dsindC.z);
00178       f1.y += K1*((r23.z*r23.z + r23.x*r23.x)*dsindC.y
00179                 - r23.y*r23.z*dsindC.z
00180                 - r23.y*r23.x*dsindC.x);
00181       f1.z += K1*((r23.x*r23.x + r23.y*r23.y)*dsindC.z
00182                 - r23.z*r23.x*dsindC.x
00183                 - r23.z*r23.y*dsindC.y);
00184 
00185       f3 += cross(K1,dsindB,r23);
00186 
00187       f2.x += K1*(-(r23.y*r12.y + r23.z*r12.z)*dsindC.x
00188              +(2.0*r23.x*r12.y - r12.x*r23.y)*dsindC.y
00189              +(2.0*r23.x*r12.z - r12.x*r23.z)*dsindC.z
00190              +dsindB.z*r34.y - dsindB.y*r34.z);
00191       f2.y += K1*(-(r23.z*r12.z + r23.x*r12.x)*dsindC.y
00192              +(2.0*r23.y*r12.z - r12.y*r23.z)*dsindC.z
00193              +(2.0*r23.y*r12.x - r12.y*r23.x)*dsindC.x
00194              +dsindB.x*r34.z - dsindB.z*r34.x);
00195       f2.z += K1*(-(r23.x*r12.x + r23.y*r12.y)*dsindC.z
00196              +(2.0*r23.z*r12.x - r12.z*r23.x)*dsindC.x
00197              +(2.0*r23.z*r12.y - r12.z*r23.y)*dsindC.y
00198              +dsindB.y*r34.x - dsindB.x*r34.y);
00199     }
00200   } /* for multiplicity */
00201 
00202   /* store the forces */
00203   p[0]->f[localIndex[0]] += f1;
00204   p[1]->f[localIndex[1]] += f2 - f1;
00205   p[2]->f[localIndex[2]] += f3 - f2;
00206   p[3]->f[localIndex[3]] += -f3;
00207 
00208   DebugM(3, "::computeForce() -- ending with delta energy " << energy << std::endl);
00209   reduction[improperEnergyIndex] += energy;
00210   reduction[virialIndex_XX] += ( f1.x * r12.x + f2.x * r23.x + f3.x * r34.x );
00211   reduction[virialIndex_XY] += ( f1.x * r12.y + f2.x * r23.y + f3.x * r34.y );
00212   reduction[virialIndex_XZ] += ( f1.x * r12.z + f2.x * r23.z + f3.x * r34.z );
00213   reduction[virialIndex_YX] += ( f1.y * r12.x + f2.y * r23.x + f3.y * r34.x );
00214   reduction[virialIndex_YY] += ( f1.y * r12.y + f2.y * r23.y + f3.y * r34.y );
00215   reduction[virialIndex_YZ] += ( f1.y * r12.z + f2.y * r23.z + f3.y * r34.z );
00216   reduction[virialIndex_ZX] += ( f1.z * r12.x + f2.z * r23.x + f3.z * r34.x );
00217   reduction[virialIndex_ZY] += ( f1.z * r12.y + f2.z * r23.y + f3.z * r34.y );
00218   reduction[virialIndex_ZZ] += ( f1.z * r12.z + f2.z * r23.z + f3.z * r34.z );
00219 
00220   if (pressureProfileData) {
00221     BigReal z1 = p[0]->x[localIndex[0]].position.z;
00222     BigReal z2 = p[1]->x[localIndex[1]].position.z;
00223     BigReal z3 = p[2]->x[localIndex[2]].position.z;
00224     BigReal z4 = p[3]->x[localIndex[3]].position.z;
00225     int n1 = (int)floor((z1-pressureProfileMin)/pressureProfileThickness);
00226     int n2 = (int)floor((z2-pressureProfileMin)/pressureProfileThickness);
00227     int n3 = (int)floor((z3-pressureProfileMin)/pressureProfileThickness);
00228     int n4 = (int)floor((z4-pressureProfileMin)/pressureProfileThickness);
00229     pp_clamp(n1, pressureProfileSlabs);
00230     pp_clamp(n2, pressureProfileSlabs);
00231     pp_clamp(n3, pressureProfileSlabs);
00232     pp_clamp(n4, pressureProfileSlabs);
00233     int p1 = p[0]->x[localIndex[0]].partition;
00234     int p2 = p[1]->x[localIndex[1]].partition;
00235     int p3 = p[2]->x[localIndex[2]].partition;
00236     int p4 = p[3]->x[localIndex[3]].partition;
00237     int pn = pressureProfileAtomTypes;
00238     pp_reduction(pressureProfileSlabs, n1, n2,
00239                 p1, p2, pn,
00240                 f1.x * r12.x, f1.y * r12.y, f1.z * r12.z,
00241                 pressureProfileData);
00242     pp_reduction(pressureProfileSlabs, n2, n3,
00243                 p2, p3, pn,
00244                 f2.x * r23.x, f2.y * r23.y, f2.z * r23.z,
00245                 pressureProfileData);
00246     pp_reduction(pressureProfileSlabs, n3, n4,
00247                 p3, p4, pn,
00248                 f3.x * r34.x, f3.y * r34.y, f3.z * r34.z,
00249                 pressureProfileData);
00250   }
00251 }
00252 
00253 void ImproperElem::submitReductionData(BigReal *data, SubmitReduction *reduction)
00254 {
00255   reduction->item(REDUCTION_IMPROPER_ENERGY) += data[improperEnergyIndex];
00256   ADD_TENSOR(reduction,REDUCTION_VIRIAL_NORMAL,data,virialIndex);
00257 }
00258 

Generated on Fri May 25 04:07:14 2012 for NAMD by  doxygen 1.3.9.1