00001
00007
00008
00009
00010
00011
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
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
00064
00065
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
00073 BigReal theta = acos(cos_theta);
00074
00075
00076 BigReal diff;
00077
00078 if (normal == 1) {
00079 diff = theta - theta0;
00080 } else {
00081 diff = cos_theta - cos(theta0);
00082 }
00083
00084
00085 BigReal energy = k *diff*diff;
00086
00087
00088
00089
00090
00091
00092
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
00098
00099
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
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
00115 if (value->k_ub)
00116 {
00117
00118
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