NAMD
ComputeImpropers.C
Go to the documentation of this file.
1 
7 #include "InfoStream.h"
8 #include "ComputeImpropers.h"
9 #include "Molecule.h"
10 #include "Parameters.h"
11 #include "Node.h"
12 #include "ReductionMgr.h"
13 #include "Lattice.h"
14 #include "PressureProfile.h"
15 #include "Debug.h"
16 
17 
18 // static initialization
23 
25  (Molecule* mol, int* count, int32*** byatom, Improper** structarray)
26 {
27 #ifdef MEM_OPT_VERSION
28  NAMD_die("Should not be called in ImproperElem::getMoleculePointers in memory optimized version!");
29 #else
30  *count = mol->numImpropers;
31  *byatom = mol->impropersByAtom;
32  *structarray = mol->impropers;
33 #endif
34 }
35 
37  *v = p->improper_array;
38 }
39 
40 void ImproperElem::computeForce(ImproperElem *tuples, int ntuple, BigReal *reduction,
41  BigReal *pressureProfileData)
42 {
43  const Lattice & lattice = tuples[0].p[0]->p->lattice;
44 
45  //fepb BKR
47  const int step = tuples[0].p[0]->p->flags.step;
48  const BigReal alchLambda = simParams->getCurrentLambda(step);
49  const BigReal alchLambda2 = simParams->getCurrentLambda2(step);
50  const BigReal bond_lambda_1 = simParams->getBondLambda(alchLambda);
51  const BigReal bond_lambda_2 = simParams->getBondLambda(1-alchLambda);
52  const BigReal bond_lambda_12 = simParams->getBondLambda(alchLambda2);
53  const BigReal bond_lambda_22 = simParams->getBondLambda(1-alchLambda2);
54  Molecule *const mol = Node::Object()->molecule;
55  //fepe
56 
57  for ( int ituple=0; ituple<ntuple; ++ituple ) {
58  const ImproperElem &tup = tuples[ituple];
59  enum { size = 4 };
60  const AtomID (&atomID)[size](tup.atomID);
61  const int (&localIndex)[size](tup.localIndex);
62  TuplePatchElem * const(&p)[size](tup.p);
63  const Real (&scale)(tup.scale);
64  const ImproperValue * const(&value)(tup.value);
65 
66 #if defined(DEBUG_PROTOCELL)
67  if ((PRMIN <= atomID[0] && atomID[0] <= PRMAX) &&
68  (PRMIN <= atomID[1] && atomID[1] <= PRMAX) &&
69  (PRMIN <= atomID[2] && atomID[2] <= PRMAX) &&
70  (PRMIN <= atomID[3] && atomID[3] <= PRMAX)) {
71  int i = atomID[0];
72  int j = atomID[1];
73  int k = atomID[2];
74  int l = atomID[3];
75  if (atomID[3] < atomID[0]) {
76  i = atomID[3];
77  j = atomID[2];
78  k = atomID[1];
79  l = atomID[0];
80  }
81  int mult = value->multiplicity;
82  CkPrintf("%11d %11d %11d %11d mult=%d", i, j, k, l, mult);
83  for (int m=0; m < mult; m++) {
84  double kdelta = value->values[m].k;
85  double delta = value->values[m].delta;
86  int n = value->values[m].n;
87  CkPrintf(" k=%g delta=%g n=%d\n", kdelta, delta, n);
88  }
89  }
90 #endif
91 
92  DebugM(3, "::computeForce() localIndex = " << localIndex[0] << " "
93  << localIndex[1] << " " << localIndex[2] << " " <<
94  localIndex[3] << std::endl);
95 
96  // Vector r12, r23, r34; // vector between atoms
97  Vector A,B,C; // cross products
98  BigReal rA, rB, rC; // length of vectors A, B, and C
99  BigReal energy=0; // energy from the angle
100  BigReal phi; // angle between the plans
101  double cos_phi; // cos(phi)
102  double sin_phi; // sin(phi)
103  Vector dcosdA; // Derivative d(cos(phi))/dA
104  Vector dcosdB; // Derivative d(cos(phi))/dB
105  Vector dsindC; // Derivative d(sin(phi))/dC
106  Vector dsindB; // Derivative d(sin(phi))/dB
107  BigReal K,K1; // energy constants
108  BigReal diff; // for periodicity
109  Force f1(0,0,0),f2(0,0,0),f3(0,0,0); // force components
110 
111  //DebugM(3, "::computeForce() -- starting with improper type " << improperType << std::endl);
112 
113  // get the improper information
114  int multiplicity = value->multiplicity;
115 
116  // Calculate the vectors between atoms
117  const Position & pos0 = p[0]->x[localIndex[0]].position;
118  const Position & pos1 = p[1]->x[localIndex[1]].position;
119  const Position & pos2 = p[2]->x[localIndex[2]].position;
120  const Position & pos3 = p[3]->x[localIndex[3]].position;
121  const Vector r12 = lattice.delta(pos0,pos1);
122  const Vector r23 = lattice.delta(pos1,pos2);
123  const Vector r34 = lattice.delta(pos2,pos3);
124 
125  // Calculate the cross products
126  A = cross(r12,r23);
127  B = cross(r23,r34);
128  C = cross(r23,A);
129 
130  // Calculate the distances
131  rA = A.length();
132  rB = B.length();
133  rC = C.length();
134 
135  // Calculate the sin and cos
136  cos_phi = A*B/(rA*rB);
137  sin_phi = C*B/(rC*rB);
138 
139  // Normalize B
140  rB = 1.0/rB;
141  B *= rB;
142 
143  phi= -atan2(sin_phi,cos_phi);
144 
145  if (fabs(sin_phi) > 0.1)
146  {
147  // Normalize A
148  rA = 1.0/rA;
149  A *= rA;
150  dcosdA = rA*(cos_phi*A-B);
151  dcosdB = rB*(cos_phi*B-A);
152  }
153  else
154  {
155  // Normalize C
156  rC = 1.0/rC;
157  C *= rC;
158  dsindC = rC*(sin_phi*C-B);
159  dsindB = rB*(sin_phi*B-C);
160  }
161 
162  // Loop through the multiple parameter sets for this
163  // bond. We will only loop more than once if this
164  // has multiple parameter sets from Charmm22
165  for (int mult_num=0; mult_num<multiplicity; mult_num++)
166  {
167  /* get angle information */
168  Real k = value->values[mult_num].k * scale;
169  Real delta = value->values[mult_num].delta;
170  int n = value->values[mult_num].n;
171 
172  // Calculate the energy
173  if (n)
174  {
175  // Periodicity is greater than 0, so use cos form
176  K = k*(1+cos(n*phi - delta));
177  K1 = -n*k*sin(n*phi - delta);
178  }
179  else
180  {
181  // Periodicity is 0, so just use the harmonic form
182  diff = phi-delta;
183  if (diff < -PI) diff += TWOPI;
184  else if (diff > PI) diff -= TWOPI;
185 
186  K = k*diff*diff;
187  K1 = 2.0*k*diff;
188  }
189 
190  // Add the energy from this improper to the total energy
191  energy += K;
192 
193  // Next, we want to calculate the forces. In order
194  // to do that, we first need to figure out whether the
195  // sin or cos form will be more stable. For this,
196  // just look at the value of phi
197  if (fabs(sin_phi) > 0.1)
198  {
199  // use the sin version to avoid 1/cos terms
200  K1 = K1/sin_phi;
201 
202  f1.x += K1*(r23.y*dcosdA.z - r23.z*dcosdA.y);
203  f1.y += K1*(r23.z*dcosdA.x - r23.x*dcosdA.z);
204  f1.z += K1*(r23.x*dcosdA.y - r23.y*dcosdA.x);
205 
206  f3.x += K1*(r23.z*dcosdB.y - r23.y*dcosdB.z);
207  f3.y += K1*(r23.x*dcosdB.z - r23.z*dcosdB.x);
208  f3.z += K1*(r23.y*dcosdB.x - r23.x*dcosdB.y);
209 
210  f2.x += K1*(r12.z*dcosdA.y - r12.y*dcosdA.z
211  + r34.y*dcosdB.z - r34.z*dcosdB.y);
212  f2.y += K1*(r12.x*dcosdA.z - r12.z*dcosdA.x
213  + r34.z*dcosdB.x - r34.x*dcosdB.z);
214  f2.z += K1*(r12.y*dcosdA.x - r12.x*dcosdA.y
215  + r34.x*dcosdB.y - r34.y*dcosdB.x);
216  }
217  else
218  {
219  // This angle is closer to 0 or 180 than it is to
220  // 90, so use the cos version to avoid 1/sin terms
221  K1 = -K1/cos_phi;
222 
223  f1.x += K1*((r23.y*r23.y + r23.z*r23.z)*dsindC.x
224  - r23.x*r23.y*dsindC.y
225  - r23.x*r23.z*dsindC.z);
226  f1.y += K1*((r23.z*r23.z + r23.x*r23.x)*dsindC.y
227  - r23.y*r23.z*dsindC.z
228  - r23.y*r23.x*dsindC.x);
229  f1.z += K1*((r23.x*r23.x + r23.y*r23.y)*dsindC.z
230  - r23.z*r23.x*dsindC.x
231  - r23.z*r23.y*dsindC.y);
232 
233  f3 += cross(K1,dsindB,r23);
234 
235  f2.x += K1*(-(r23.y*r12.y + r23.z*r12.z)*dsindC.x
236  +(2.0*r23.x*r12.y - r12.x*r23.y)*dsindC.y
237  +(2.0*r23.x*r12.z - r12.x*r23.z)*dsindC.z
238  +dsindB.z*r34.y - dsindB.y*r34.z);
239  f2.y += K1*(-(r23.z*r12.z + r23.x*r12.x)*dsindC.y
240  +(2.0*r23.y*r12.z - r12.y*r23.z)*dsindC.z
241  +(2.0*r23.y*r12.x - r12.y*r23.x)*dsindC.x
242  +dsindB.x*r34.z - dsindB.z*r34.x);
243  f2.z += K1*(-(r23.x*r12.x + r23.y*r12.y)*dsindC.z
244  +(2.0*r23.z*r12.x - r12.z*r23.x)*dsindC.x
245  +(2.0*r23.z*r12.y - r12.z*r23.y)*dsindC.y
246  +dsindB.y*r34.x - dsindB.x*r34.y);
247  }
248  } /* for multiplicity */
249 
250  //fepb - BKR scaling of alchemical bonded terms
251  // NB: TI derivative is the _unscaled_ energy.
252  if ( simParams->alchOn && !simParams->singleTopology) {
253  switch ( mol->get_fep_bonded_type(atomID, 4) ) {
254  case 1:
255  reduction[improperEnergyIndex_ti_1] += energy;
256  reduction[improperEnergyIndex_f] += (bond_lambda_12 - bond_lambda_1) *
257  energy;
258  energy *= bond_lambda_1;
259  f1 *= bond_lambda_1;
260  f2 *= bond_lambda_1;
261  f3 *= bond_lambda_1;
262  break;
263  case 2:
264  reduction[improperEnergyIndex_ti_2] += energy;
265  reduction[improperEnergyIndex_f] += (bond_lambda_22 - bond_lambda_2) *
266  energy;
267  energy *= bond_lambda_2;
268  f1 *= bond_lambda_2;
269  f2 *= bond_lambda_2;
270  f3 *= bond_lambda_2;
271  break;
272  }
273  }
274  //fepe
275 
276  /* store the forces */
277  p[0]->f[localIndex[0]] += f1;
278  p[1]->f[localIndex[1]] += f2 - f1;
279  p[2]->f[localIndex[2]] += f3 - f2;
280  p[3]->f[localIndex[3]] += -f3;
281 
282  DebugM(3, "::computeForce() -- ending with delta energy " << energy << std::endl);
283  reduction[improperEnergyIndex] += energy;
284  reduction[virialIndex_XX] += ( f1.x * r12.x + f2.x * r23.x + f3.x * r34.x );
285  reduction[virialIndex_XY] += ( f1.x * r12.y + f2.x * r23.y + f3.x * r34.y );
286  reduction[virialIndex_XZ] += ( f1.x * r12.z + f2.x * r23.z + f3.x * r34.z );
287  reduction[virialIndex_YX] += ( f1.y * r12.x + f2.y * r23.x + f3.y * r34.x );
288  reduction[virialIndex_YY] += ( f1.y * r12.y + f2.y * r23.y + f3.y * r34.y );
289  reduction[virialIndex_YZ] += ( f1.y * r12.z + f2.y * r23.z + f3.y * r34.z );
290  reduction[virialIndex_ZX] += ( f1.z * r12.x + f2.z * r23.x + f3.z * r34.x );
291  reduction[virialIndex_ZY] += ( f1.z * r12.y + f2.z * r23.y + f3.z * r34.y );
292  reduction[virialIndex_ZZ] += ( f1.z * r12.z + f2.z * r23.z + f3.z * r34.z );
293 
294  if (pressureProfileData) {
295  BigReal z1 = p[0]->x[localIndex[0]].position.z;
296  BigReal z2 = p[1]->x[localIndex[1]].position.z;
297  BigReal z3 = p[2]->x[localIndex[2]].position.z;
298  BigReal z4 = p[3]->x[localIndex[3]].position.z;
299  int n1 = (int)floor((z1-pressureProfileMin)/pressureProfileThickness);
300  int n2 = (int)floor((z2-pressureProfileMin)/pressureProfileThickness);
301  int n3 = (int)floor((z3-pressureProfileMin)/pressureProfileThickness);
302  int n4 = (int)floor((z4-pressureProfileMin)/pressureProfileThickness);
307  int p1 = p[0]->x[localIndex[0]].partition;
308  int p2 = p[1]->x[localIndex[1]].partition;
309  int p3 = p[2]->x[localIndex[2]].partition;
310  int p4 = p[3]->x[localIndex[3]].partition;
311  int pn = pressureProfileAtomTypes;
313  p1, p2, pn,
314  f1.x * r12.x, f1.y * r12.y, f1.z * r12.z,
315  pressureProfileData);
317  p2, p3, pn,
318  f2.x * r23.x, f2.y * r23.y, f2.z * r23.z,
319  pressureProfileData);
321  p3, p4, pn,
322  f3.x * r34.x, f3.y * r34.y, f3.z * r34.z,
323  pressureProfileData);
324  }
325 
326  }
327 }
328 
330 {
335  ADD_TENSOR(reduction,REDUCTION_VIRIAL_NORMAL,data,virialIndex);
336 }
337 
static Node * Object()
Definition: Node.h:86
static int pressureProfileAtomTypes
static void submitReductionData(BigReal *, SubmitReduction *)
static void getMoleculePointers(Molecule *, int *, int32 ***, Improper **)
TuplePatchElem * p[size]
const ImproperValue * value
Lattice & lattice
Definition: Patch.h:127
#define ADD_TENSOR(R, RL, D, DL)
Definition: ReductionMgr.h:33
void pp_reduction(int nslabs, int n1, int n2, int atype1, int atype2, int numtypes, BigReal vxx, BigReal vyy, BigReal vzz, BigReal *reduction)
Definition: Vector.h:72
SimParameters * simParameters
Definition: Node.h:181
float Real
Definition: common.h:118
int32_t int32
Definition: common.h:38
BigReal & item(int i)
Definition: ReductionMgr.h:313
#define DebugM(x, y)
Definition: Debug.h:75
AtomID atomID[size]
BigReal z
Definition: Vector.h:74
Position position
Definition: NamdTypes.h:77
static void getParameterPointers(Parameters *, const ImproperValue **)
Molecule stores the structural information for the system.
Definition: Molecule.h:175
static BigReal pressureProfileMin
Flags flags
Definition: Patch.h:128
#define PI
Definition: common.h:92
void pp_clamp(int &n, int nslabs)
static int pressureProfileSlabs
NAMD_HOST_DEVICE BigReal length(void) const
Definition: Vector.h:202
uint8 partition
Definition: NamdTypes.h:80
BigReal x
Definition: Vector.h:74
int get_fep_bonded_type(const int *atomID, unsigned int order) const
Definition: Molecule.h:1477
void NAMD_die(const char *err_msg)
Definition: common.C:147
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:134
#define TWOPI
Definition: common.h:96
int numImpropers
Definition: Molecule.h:595
#define simParams
Definition: Output.C:129
static void computeForce(ImproperElem *, int, BigReal *, BigReal *)
int localIndex[size]
int32 AtomID
Definition: NamdTypes.h:35
BigReal y
Definition: Vector.h:74
static BigReal pressureProfileThickness
Molecule * molecule
Definition: Node.h:179
double BigReal
Definition: common.h:123
NAMD_HOST_DEVICE Vector delta(const Position &pos1, const Position &pos2) const
Definition: Lattice.h:149
int step
Definition: PatchTypes.h:16