NAMD
ComputeDPME.C
Go to the documentation of this file.
1 
7 #include "InfoStream.h"
8 #include "Node.h"
9 #include "PatchMap.h"
10 #include "PatchMap.inl"
11 #include "AtomMap.h"
12 #include "ComputeDPME.h"
13 #include "ComputeDPMEMsgs.h"
14 #include "ComputeNonbondedUtil.h"
15 #include "PatchMgr.h"
16 #include "Molecule.h"
17 #include "ReductionMgr.h"
18 #include "SimParameters.h"
19 #include "ComputeMgr.h"
20 #include "ComputeMgr.decl.h"
21 // #define DEBUGM
22 #define MIN_DEBUG_LEVEL 3
23 #include "Debug.h"
24 
25 #ifdef DPME
26 #include "dpme2.h"
27 
28 class ComputeDPMEMaster {
29 private:
30  friend class ComputeDPME;
31  ComputeDPME *host;
32  ComputeDPMEMaster(ComputeDPME *);
33  ~ComputeDPMEMaster();
35  ResizeArray<int> homeNode;
36  ResizeArray<int> endForNode;
37  int numWorkingPes;
38  int numLocalAtoms;
39  Pme2Particle *localData;
40  SubmitReduction *reduction;
41  int runcount;
42 };
43 
44 ComputeDPME::ComputeDPME(ComputeID c, ComputeMgr *m) :
45  ComputeHomePatches(c), comm(m)
46 {
47  DebugM(4,"ComputeDPME created.\n");
48  useAvgPositions = 1;
49 
50  int numWorkingPes = (PatchMap::Object())->numNodesWithPatches();
51 
52  masterNode = numWorkingPes - 1;
53  if ( CkMyPe() == masterNode ) {
54  master = new ComputeDPMEMaster(this);
55  master->numWorkingPes = numWorkingPes;
56  }
57  else master = 0;
58 }
59 
60 ComputeDPME::~ComputeDPME()
61 {
62  delete master;
63 }
64 
65 // These are needed to fix up argument mismatches in DPME.
66 
67 extern "C" {
68  extern int cfftf(int *, double *, double *);
69  extern int cfftb(int *, double *, double *);
70  extern int cffti1(int *, double *, int *);
71  extern int cfftf1(int *n, double *c, double *ch, double *wa, int *ifac);
72  extern int cfftb1(int *n, double *c, double *ch, double *wa, int *ifac);
73 }
74 
75 int cfftf(int *n, doublecomplex *c, double *wsave) {
76  // Casting (doublecomplex*) to (double*) is probably OK.
77  return cfftf(n, (double *)c, wsave);
78 }
79 
80 int cfftb(int *n, doublecomplex *c, double *wsave) {
81  // Casting (doublecomplex*) to (double*) is probably OK.
82  return cfftb(n, (double *)c, wsave);
83 }
84 
85 int cffti1(int *n, double *wa, double *ifac) {
86  // Casting (double*) to (int*) is dangerous if sizes differ!!!
87  return cffti1(n, wa, (int *)ifac);
88 }
89 
90 int cfftf1(int *n, double *c, double *ch, double *wa, double *ifac) {
91  // Casting (double*) to (int*) is dangerous if sizes differ!!!
92  return cfftf1(n, c, ch, wa, (int *)ifac);
93 }
94 
95 int cfftb1(int *n, double *c, double *ch, double *wa, double *ifac) {
96  // Casting (double*) to (int*) is dangerous if sizes differ!!!
97  return cfftb1(n, c, ch, wa, (int *)ifac);
98 }
99 
100 void ComputeDPME::doWork()
101 {
102  DebugM(4,"Entering ComputeDPME::doWork().\n");
103 
104  Pme2Particle *localData;
105 
106  ResizeArrayIter<PatchElem> ap(patchList);
107 
108  // Skip computations if nothing to do.
109  if ( ! patchList[0].p->flags.doFullElectrostatics )
110  {
111  for (ap = ap.begin(); ap != ap.end(); ap++) {
112  CompAtom *x = (*ap).positionBox->open();
113  Results *r = (*ap).forceBox->open();
114  (*ap).positionBox->close(&x);
115  (*ap).forceBox->close(&r);
116  }
117  if ( master ) {
118  master->reduction->submit();
119  }
120  return;
121  }
122 
123  // allocate storage
124  numLocalAtoms = 0;
125  for (ap = ap.begin(); ap != ap.end(); ap++) {
126  numLocalAtoms += (*ap).p->getNumAtoms();
127  }
128 
129  Lattice lattice = patchList[0].p->flags.lattice;
130 
131  localData = new Pme2Particle[numLocalAtoms]; // given to message
132 
133  // get positions and charges
134  Pme2Particle * data_ptr = localData;
135  const BigReal coulomb_sqrt = sqrt( COULOMB * ComputeNonbondedUtil::scaling
137  for (ap = ap.begin(); ap != ap.end(); ap++) {
138  CompAtom *x = (*ap).positionBox->open();
139  if ( patchList[0].p->flags.doMolly ) {
140  (*ap).positionBox->close(&x);
141  x = (*ap).avgPositionBox->open();
142  }
143  int numAtoms = (*ap).p->getNumAtoms();
144 
145  for(int i=0; i<numAtoms; ++i)
146  {
147  Vector tmp = lattice.delta(x[i].position);
148  data_ptr->x = tmp.x;
149  data_ptr->y = tmp.y;
150  data_ptr->z = tmp.z;
151  data_ptr->cg = coulomb_sqrt * x[i].charge;
152  data_ptr->id = x[i].id;
153  ++data_ptr;
154  }
155 
156  if ( patchList[0].p->flags.doMolly ) { (*ap).avgPositionBox->close(&x); }
157  else { (*ap).positionBox->close(&x); }
158  }
159 
160  // send data to master
162  msg->node = CkMyPe();
163  msg->numParticles = numLocalAtoms;
164  msg->particles = localData;
165  comm->sendComputeDPMEData(msg);
166 }
167 
169 {
170  if ( master ) {
171  master->recvData(msg);
172  }
173  else NAMD_die("ComputeDPME::master is NULL!");
174 }
175 
176 ComputeDPMEMaster::ComputeDPMEMaster(ComputeDPME *h) :
177  host(h), numLocalAtoms(0), runcount(0)
178 {
180  Molecule * molecule = Node::Object()->molecule;
181  localData = new Pme2Particle[molecule->numAtoms];
182 }
183 
184 ComputeDPMEMaster::~ComputeDPMEMaster()
185 {
186  delete reduction;
187  delete [] localData;
188 }
189 
191 {
192  DebugM(4,"ComputeDPMEMaster::recvData() " << msg->numParticles
193  << " particles from node " << msg->node << "\n");
194 
195  {
196  homeNode.add(msg->node);
197  Pme2Particle *data_ptr = localData + numLocalAtoms;
198  for ( int j = 0; j < msg->numParticles; ++j, ++data_ptr ) {
199  *data_ptr = msg->particles[j];
200  }
201  numLocalAtoms += msg->numParticles;
202  endForNode.add(numLocalAtoms);
203  delete msg;
204  }
205 
206  if ( homeNode.size() < numWorkingPes ) return; // messages outstanding
207 
208  DebugM(4,"ComputeDPMEMaster::recvData() running serial code.\n");
209 
210  // single processor version
211 
212  Lattice lattice = host->getFlags()->lattice;
214  int i;
215 
216  AtomInfo atom_info;
217  atom_info.numatoms = numLocalAtoms;
218  atom_info.atompnt = 0; // not used
219  atom_info.freepnt = 0; // not used
220  atom_info.nlocal = numLocalAtoms;
221  atom_info.nother = 0;
222 
223  if ( ! lattice.orthogonal() ) {
224  NAMD_die("DPME only supports orthogonal PBC's.");
225  }
226 
227  BoxInfo box_info;
228  box_info.box.x = lattice.a().x;
229  box_info.box.y = lattice.b().y;
230  box_info.box.z = lattice.c().z;
231  box_info.box.origin = 0.; // why only one number?
232  box_info.prd.x = box_info.box.x;
233  box_info.prd.y = box_info.box.y;
234  box_info.prd.z = box_info.box.z;
235  box_info.prd2.x = 0.5 * box_info.box.x;
236  box_info.prd2.y = 0.5 * box_info.box.y;
237  box_info.prd2.z = 0.5 * box_info.box.z;
238  box_info.cutoff = simParams->cutoff;
239  box_info.rs = simParams->cutoff;
240  box_info.mc2.x = 2. * ( box_info.prd.x - box_info.cutoff );
241  box_info.mc2.y = 2. * ( box_info.prd.y - box_info.cutoff );
242  box_info.mc2.z = 2. * ( box_info.prd.z - box_info.cutoff );
243  box_info.ewaldcof = ComputeNonbondedUtil::ewaldcof;
244  box_info.dtol = simParams->PMETolerance;
245  for (i = 0; i <= 8; i++) {
246  box_info.recip[i] = 0.; /* assume orthogonal box */
247  }
248  box_info.recip[0] = 1.0/box_info.box.x;
249  box_info.recip[4] = 1.0/box_info.box.y;
250  box_info.recip[8] = 1.0/box_info.box.z;
251 
252  GridInfo grid_info;
253  grid_info.order = simParams->PMEInterpOrder;
254  grid_info.nfftgrd.x = simParams->PMEGridSizeX;
255  grid_info.nfftgrd.y = simParams->PMEGridSizeY;
256  grid_info.nfftgrd.z = simParams->PMEGridSizeZ;
257  grid_info.nfft = 0;
258  grid_info.volume = lattice.volume();
259 
260  PeInfo pe_info; // hopefully this isn't used for anything
261  pe_info.myproc.node = 0;
262  pe_info.myproc.nprocs = 1;
263  pe_info.myproc.ncube = 0;
264  pe_info.inst_node[0] = 0;
265  pe_info.igrid = 0;
266 
267  PmeVector *localResults;
268  double recip_vir[6];
269  int time_count = 0;
270  int tsteps = 1;
271  double mytime = 0.;
272 
273  // perform calculations
274  BigReal electEnergy = 0;
275 
276  // calculate self energy
277  Pme2Particle *data_ptr = localData;
278  for(i=0; i<numLocalAtoms; ++i)
279  {
280  electEnergy += data_ptr->cg * data_ptr->cg;
281  ++data_ptr;
282  }
283  electEnergy *= -1. * box_info.ewaldcof / SQRT_PI;
284 
285  DebugM(4,"Ewald self energy: " << electEnergy << "\n");
286 
287  DebugM(4,"Calling dpme_eval_recip().\n");
288 
289  double pme_start_time = 0;
290  if ( runcount == 1 ) pme_start_time = CmiTimer();
291 
292  electEnergy += dpme_eval_recip( atom_info, localData - 1, &localResults,
293  recip_vir, grid_info, box_info, pe_info,
294  time_count, tsteps, &mytime );
295 
296  if ( runcount == 1 ) {
297  iout << iINFO << "PME reciprocal sum CPU time per evaluation: "
298  << (CmiTimer() - pme_start_time) << "\n" << endi;
299  }
300 
301  DebugM(4,"Returned from dpme_eval_recip().\n");
302 
303  // REVERSE SIGN OF VIRIAL RETURNED BY DPME
304  for(i=0; i<6; ++i) recip_vir[i] *= -1.;
305 
306  // send out reductions
307  DebugM(4,"Timestep : " << host->getFlags()->step << "\n");
308  DebugM(4,"Reciprocal sum energy: " << electEnergy << "\n");
309  DebugM(4,"Reciprocal sum virial: " << recip_vir[0] << " " <<
310  recip_vir[1] << " " << recip_vir[2] << " " << recip_vir[3] << " " <<
311  recip_vir[4] << " " << recip_vir[5] << "\n");
312  reduction->item(REDUCTION_ELECT_ENERGY_SLOW) += electEnergy;
313  reduction->item(REDUCTION_VIRIAL_SLOW_XX) += (BigReal)(recip_vir[0]);
314  reduction->item(REDUCTION_VIRIAL_SLOW_XY) += (BigReal)(recip_vir[1]);
315  reduction->item(REDUCTION_VIRIAL_SLOW_XZ) += (BigReal)(recip_vir[2]);
316  reduction->item(REDUCTION_VIRIAL_SLOW_YX) += (BigReal)(recip_vir[1]);
317  reduction->item(REDUCTION_VIRIAL_SLOW_YY) += (BigReal)(recip_vir[3]);
318  reduction->item(REDUCTION_VIRIAL_SLOW_YZ) += (BigReal)(recip_vir[4]);
319  reduction->item(REDUCTION_VIRIAL_SLOW_ZX) += (BigReal)(recip_vir[2]);
320  reduction->item(REDUCTION_VIRIAL_SLOW_ZY) += (BigReal)(recip_vir[4]);
321  reduction->item(REDUCTION_VIRIAL_SLOW_ZZ) += (BigReal)(recip_vir[5]);
322  reduction->submit();
323 
324  PmeVector *results_ptr = localResults + 1;
325 
326  numLocalAtoms = 0;
327  for ( i = 0; i < homeNode.size(); ++i ) {
329  msg->node = homeNode[i];
330  msg->numParticles = endForNode[i] - numLocalAtoms;
331  msg->forces = new PmeVector[msg->numParticles];
332  for ( int j = 0; j < msg->numParticles; ++j, ++results_ptr ) {
333  msg->forces[j] = *results_ptr;
334  }
335  numLocalAtoms = endForNode[i];
336  host->comm->sendComputeDPMEResults(msg,homeNode[i]);
337  }
338 
339  // reset
340  runcount += 1;
341  numLocalAtoms = 0;
342  homeNode.resize(0);
343  endForNode.resize(0);
344 
345 }
346 
347 void ComputeDPME::recvResults(ComputeDPMEResultsMsg *msg)
348 {
349  if ( CkMyPe() != msg->node ) {
350  NAMD_die("ComputeDPME results sent to wrong node!\n");
351  return;
352  }
353  if ( numLocalAtoms != msg->numParticles ) {
354  NAMD_die("ComputeDPME sent wrong number of results!\n");
355  return;
356  }
357 
358  PmeVector *results_ptr = msg->forces;
359  ResizeArrayIter<PatchElem> ap(patchList);
360 
361  // add in forces
362  for (ap = ap.begin(); ap != ap.end(); ap++) {
363  Results *r = (*ap).forceBox->open();
364  Force *f = r->f[Results::slow];
365  int numAtoms = (*ap).p->getNumAtoms();
366 
367  for(int i=0; i<numAtoms; ++i)
368  {
369  f[i].x += results_ptr->x;
370  f[i].y += results_ptr->y;
371  f[i].z += results_ptr->z;
372  ++results_ptr;
373  }
374 
375  (*ap).forceBox->close(&r);
376  }
377 
378  delete msg;
379 
380 }
381 
382 #endif // DPME
383 
static Node * Object()
Definition: Node.h:86
std::ostream & iINFO(std::ostream &s)
Definition: InfoStream.C:81
int ComputeID
Definition: NamdTypes.h:183
int cfftb(int *n, double *c, double *wsave)
Definition: pub3dfft.C:1401
static PatchMap * Object()
Definition: PatchMap.h:27
Definition: Vector.h:64
SimParameters * simParameters
Definition: Node.h:178
register BigReal electEnergy
#define COULOMB
Definition: common.h:46
#define DebugM(x, y)
Definition: Debug.h:59
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
BigReal z
Definition: Vector.h:66
SubmitReduction * willSubmit(int setID, int size=-1)
Definition: ReductionMgr.C:365
#define Pme2Particle
int orthogonal() const
Definition: Lattice.h:257
static ReductionMgr * Object(void)
Definition: ReductionMgr.h:278
#define iout
Definition: InfoStream.h:51
int cfftf1(int *n, double *c, double *ch, double *wa, int *ifac)
Definition: pub3dfft.C:1420
void recvData(DataMessage *dmsg)
Definition: DataExchanger.C:93
#define SQRT_PI
Definition: ComputeExt.C:30
Charge charge
Definition: NamdTypes.h:54
int cffti1(int *n, double *wa, int *ifac)
Definition: pub3dfft.C:1563
Force * f[maxNumForces]
Definition: PatchTypes.h:67
int cfftf(int *n, double *c, double *wsave)
Definition: pub3dfft.C:1544
Vector delta(const Position &pos1, const Position &pos2) const
Definition: Lattice.h:144
BigReal x
Definition: Vector.h:66
int numAtoms
Definition: Molecule.h:557
#define PmeVector
int cfftb1(int *n, double *c, double *ch, double *wa, int *ifac)
Definition: pub3dfft.C:1277
void NAMD_die(const char *err_msg)
Definition: common.C:85
BigReal volume(void) const
Definition: Lattice.h:277
#define simParams
Definition: Output.C:127
Pme2Particle * particles
BigReal y
Definition: Vector.h:66
Vector b() const
Definition: Lattice.h:253
BigReal PMETolerance
gridSize x
Molecule * molecule
Definition: Node.h:176
Vector a() const
Definition: Lattice.h:252
Vector c() const
Definition: Lattice.h:254
double BigReal
Definition: common.h:114