NAMD
ComputeDPMTA.C
Go to the documentation of this file.
1 
7 #include "common.h"
8 #include "InfoStream.h"
9 #include "Node.h"
10 #include "SimParameters.h"
11 #include "ComputeNonbondedUtil.h"
12 #include "PatchMap.inl"
13 #include "AtomMap.h"
14 #include "ComputeDPMTA.h"
15 #include "PatchMgr.h"
16 #include "Molecule.h"
17 #include "ReductionMgr.h"
18 #include "Lattice.h"
19 #include "Communicate.h"
20 #include "InfoStream.h"
21 #include "ProcessorPrivate.h"
22 
23 #define MIN_DEBUG_LEVEL 2
24 // #define DEBUGM
25 #include "Debug.h"
26 
27 #ifdef DPMTA
28 
29 #include <pvmc.h>
30 
31 // #define DUMP_DPMTA
32 
33 void ComputeDPMTA::get_FMA_cube(int resize)
34 {
35  Vector boxSize,boxCenter; // used to see if things change
36  PatchMap *patchMap = PatchMap::Object();
37 
38  if (usePBC == FALSE)
39  {
40  // From these extremes, figure out how many patches we will
41  // have to have in each direction
43  int dim_x = patchMap->gridsize_a();
44  int dim_y = patchMap->gridsize_b();
45  int dim_z = patchMap->gridsize_c();
46 
47  boxSize.x = dim_x*simParams->patchDimension;
48  boxSize.y = dim_y*simParams->patchDimension;
49  boxSize.z = dim_z*simParams->patchDimension;
50  BigReal skirt = 2*simParams->patchDimension;
51 
52  boxCenter = patchMap->origin();
53  boxCenter.x += boxSize.x/2.0;
54  boxCenter.y += boxSize.y/2.0;
55  boxCenter.z += boxSize.z/2.0;
56 
57  // add the skirt of empty patches by adding 2 patches in every direction
58  boxSize.x += skirt;
59  boxSize.y += skirt;
60  boxSize.z += skirt;
61  }
62  else
63  {
64  DebugM(2,"getting patch info for FMA box\n");
65 
66  // determine boxSize from the PBC lattice
67  // lattice is the same on all patches, so choose first patch
68  ResizeArrayIter<PatchElem> ap(patchList);
69  DebugM(2,"getting first patch info for FMA box\n");
70  ap = ap.begin();
71  DebugM(2,"getting lattice from patch for FMA box\n");
72  Lattice lattice = (*ap).p->lattice;
73  if ( ! lattice.orthogonal() ) {
74  NAMD_die("DPMTA (FMA) only supports orthogonal PBC's.");
75  }
76  DebugM(2,"getting patch dimension for FMA box\n");
77  boxSize.x = lattice.a().x;
78  boxSize.y = lattice.b().y;
79  boxSize.z = lattice.c().z;
80  DebugM(2,"boxSize is " << boxSize << "\n");
81  boxCenter = lattice.origin();
82  }
83 
84  // don't bother checking if the center has moved since it depends on the size.
85  if (boxsize != boxSize)
86  {
87  DebugM(2,"resetting FMA box\n");
88  // reset the size and center
89  boxsize = boxSize;
90  boxcenter = boxCenter;
91 
92  // reset DPMTA (only reset it after it has been initialized!)
93  if (resize && usePBC)
94  {
95  PmtaVector center,v1,v2,v3;
96  center.x = boxcenter.x;
97  center.y = boxcenter.y;
98  center.z = boxcenter.z;
99  v1.x = boxsize.x;
100  v2.y = boxsize.y;
101  v3.z = boxsize.z;
102  iout << iINFO << "DPMTA box resized:\n";
103  iout << iINFO << "BOX DIMENSIONS = (" << v1.x << ","
104  << v2.y << "," << v3.z << ")\n";
105  iout << iINFO << "BOX CENTER = (" << center.x << ","
106  << center.y << "," << center.z << ")\n";
107  iout << endi;
108  DebugM(2,"calling PMTAresize()\n");
109  PMTAresize(&v1,&v2,&v3,&center);
110  DebugM(2,"called PMTAresize()\n");
111  }
112  }
113  DebugM(2,"cube center: " << boxcenter << " size=" << boxsize << "\n");
114 }
115 
116 ComputeDPMTA::ComputeDPMTA(ComputeID c) : ComputeHomePatches(c)
117 {
118  useAvgPositions = 1;
119 }
120 
121 void ComputeDPMTA::initialize()
122 {
124 
125  DebugM(2,"ComputeDPMTA creating\n");
126  // comm should always be initialized by this point...
127  // In the (bug) case that it isn't, then initialize it.
128  if (CkpvAccess(comm) == NULL)
129  {
130  NAMD_die("Communication protocol (Converse, PVM, etc.) not initialized.");
131  }
132 
133  // **** NOTE: node 0 must initialized before any other nodes register.
134 
135  // Set everything to 0
136  totalAtoms = 0;
137  fmaResults = NULL;
138  ljResults = NULL;
139  boxcenter = 1; // reset the array (no divide by zero)
140  boxsize = 1; // reset the array (no divide by zero)
141  usePBC = FALSE; // assume not...
142 
143  // all nodes should init
145 
146  // Don't need any more initialization -JCP
147  ResizeArrayIter<PatchElem> ap(patchList);
148  DebugM(2,"init() getting first patch info for FMA box\n");
149  ap = ap.begin();
150  DebugM(2,"init() getting lattice from patch for FMA box\n");
151  initLattice.x = (*ap).p->lattice.a().x;
152  initLattice.y = (*ap).p->lattice.b().y;
153  initLattice.z = (*ap).p->lattice.c().z;
154  DebugM(2,"init() initLattice is " << initLattice << "\n");
155 
156  // NOTE that the theta value is hardwired to the value of 0.715
157  // as per the recommendation of the Duke developers
158 
159  // NOTE 2: Theta is now an optional config parameter,
160  // but it defaults to 0.715
161 
162  // check for PBC
163  usePBC = ( patchMap->periodic_a() ? 1 : 0 )
164  + ( patchMap->periodic_b() ? 1 : 0 )
165  + ( patchMap->periodic_c() ? 1 : 0 );
166  if ((usePBC != 0) && (usePBC != 3))
167  {
168  NAMD_die("DPMTA (FMA) does not support 1 or 2 dimensional PBC's.");
169  }
170  DebugM(2,"Use PBC = " << usePBC << "\n");
171  usePBC = (usePBC == 3); // either PBC "3D" or no PBC
172  if ( usePBC ) {
173  iout << iWARN << "DPMTA (FMA) pressure tensor is incorrect.\n"
174  << iWARN << "Do not use DPMTA with anisotropic pressure control.\n"
175  << endi;
176  }
177 
178  // Get the size of the FMA cube
179  DebugM(2,"DPMTA getting FMA cube\n");
180  get_FMA_cube(FALSE);
181  DebugM(2,"DPMTA got FMA cube\n");
182 
183  if (CkMyPe() != 0)
184  {
185  DebugM(2,"waiting for Init go-ahead\n");
186  MIStream *msg2 = CkpvAccess(comm)->newInputStream(ANY, DPMTATAG);
187  int dummy;
188  msg2->get(dummy);
189  delete msg2;
190  slavetids=NULL;
191  if (PMTAregister() < 0)
192  {
193  NAMD_die("PMTARegister failed!!");
194  }
195  DebugM(2,"DPMTA done PMTAinit.\n");
196  return;
197  }
198  DebugM(2,"DPMTA configuring\n");
199 
200  // *****************************************
201  // ONLY THE MASTER (NODE 0) NEEDS TO DO THIS:
202 
203  int numProcs = (PatchMap::Object())->numNodesWithPatches();
204 
205  slavetids = new int[numProcs];
206  if (slavetids == NULL)
207  {
208  NAMD_die("Memory allocation failed in FMAInterface::FMAInterface");
209  }
210 
211  // pvm_spawn is a dummy function under Converse. Just the array is required.
212  pvm_spawn(NULL,NULL,0,NULL,numProcs,slavetids);
213  DebugM(2,"DPMTA slavetids allocated\n");
214 
215  // reduce function calling time
217 
218  // initialize DPMTA
219  PmtaInitData pmta_data;
220  memset(&pmta_data,0,sizeof(pmta_data));
221  pmta_data.nprocs = numProcs;
222  pmta_data.nlevels = simParams->FMALevels;
223  pmta_data.mp = simParams->FMAMp;
224  pmta_data.mp_lj = 4;
225  pmta_data.fft = simParams->FMAFFTOn;
226  pmta_data.fftblock = simParams->FMAFFTBlock;
227  pmta_data.pbc = usePBC; // use Periodic boundary condition
228  pmta_data.kterm = 0;
229  pmta_data.theta = simParams->fmaTheta;
230  pmta_data.v1.x = boxsize.x;
231  pmta_data.v1.y = 0.;
232  pmta_data.v1.z = 0.;
233  pmta_data.v2.x = 0.;
234  pmta_data.v2.y = boxsize.y;
235  pmta_data.v2.z = 0.;
236  pmta_data.v3.x = 0.;
237  pmta_data.v3.y = 0.;
238  pmta_data.v3.z = boxsize.z;
239  pmta_data.cellctr.x = boxcenter.x;
240  pmta_data.cellctr.y = boxcenter.y;
241  pmta_data.cellctr.z = boxcenter.z;
242  pmta_data.calling_num = pmta_data.nprocs;
243  pmta_data.calling_tids = slavetids;
244 
245  iout << iINFO << "DPMTA parameters are:\n";
246  iout << iINFO << " LEVELS = " << pmta_data.nlevels << "\n";
247  iout << iINFO << " NUMBER OF MULTIPOLE TERMS = " << pmta_data.mp << "\n";
248  iout << iINFO << " FFT FLAG = " << pmta_data.fft << "\n";
249  iout << iINFO << " FFT BLOCKING FACTOR = " << pmta_data.fftblock << "\n";
250  if ( usePBC ) iout << iINFO << " SYSTEM IS PERIODIC\n" << endi;
251  iout << iINFO << " BOX DIMENSIONS = (" << pmta_data.v1.x << ","
252  << pmta_data.v2.y << "," << pmta_data.v3.z << ")\n";
253  iout << iINFO << " BOX CENTER = (" << pmta_data.cellctr.x << ","
254  << pmta_data.cellctr.y << "," << pmta_data.cellctr.z << ")\n";
255  iout << endi;
256 
257  if ( usePBC )
258  {
259  pmta_data.cellctr.x = 0.;
260  pmta_data.cellctr.y = 0.;
261  pmta_data.cellctr.z = 0.;
262  }
263 
264 #ifdef DUMP_DPMTA
265  FILE *fp;
266  fp = fopen("DUMP_DPMTA.init","w");
267  fwrite(&pmta_data,sizeof(PmtaInitData),1,fp);
268  fclose(fp);
269 #endif
270 
271  DebugM(2,"DPMTA calling PMTAinit.\n");
272  if (PMTAinit(&pmta_data,slavetids) >= 0)
273  {
274  iout << iINFO << "SUCCESSFULLY STARTED DPMTA\n" << endi;
275  }
276  else
277  {
278  NAMD_die("Unable to start DPMTA!");
279  }
280 
281  // tell all nodes that it is OK to register
282  MOStream *msg = CkpvAccess(comm)->newOutputStream(ALL, DPMTATAG, BUFSIZE);
283  // don't actually put in data... Nodes just need it as a flag.
284  msg->put(TRUE);
285  msg->end();
286  delete msg;
287  DebugM(2,"Init go-ahead\n");
288  MIStream *msg1 = CkpvAccess(comm)->newInputStream(ANY, DPMTATAG);
289  int dummy1;
290  msg1->get(dummy1);
291  delete msg1;
292  DebugM(2,"got Init go-ahead\n");
293 
294  // Register this master with the other DPMTA processes
295  if (PMTAregister() < 0)
296  {
297  NAMD_die("PMTARegister failed!!");
298  }
299  DebugM(2,"DPMTA done PMTAinit.\n");
300  DebugM(2,"DPMTA configured\n");
301 }
302 
303 ComputeDPMTA::~ComputeDPMTA()
304 {
305  DebugM(2,"DPMTA exiting\n");
306  // If this is the master node, then call PMTAexit()
307  if (CkMyPe() == 0) PMTAexit();
308 
309  if (fmaResults)
310  {
311  free(fmaResults);
312  fmaResults = NULL;
313  }
314  delete [] ljResults;
315  delete [] slavetids;
316  DebugM(2,"DPMTA exited\n");
317 
318  delete reduction;
319 }
320 
321 
322 void ComputeDPMTA::doWork()
323 {
324  ResizeArrayIter<PatchElem> ap(patchList);
325  PmtaParticle *particle_list = NULL;
326 
327  // 0. only run when necessary
328  // Skip computations if nothing to do.
329  if (!patchList[0].p->flags.doFullElectrostatics)
330  {
331  for (ap = ap.begin(); ap != ap.end(); ap++) {
332  CompAtom *x = (*ap).positionBox->open();
333  Results *r = (*ap).forceBox->open();
334  (*ap).forceBox->close(&r);
335  (*ap).positionBox->close(&x);
336  }
337  reduction->submit();
338  return;
339  }
340 
341  // setup
342  // 1. get totalAtoms
343  for (totalAtoms=0, ap = ap.begin(); ap != ap.end(); ap++)
344  totalAtoms += (*ap).p->getNumAtoms();
345 
346  Vector newLattice;
347  Vector rescaleFactor;
348  if (usePBC)
349  {
350  ap = ap.begin();
351  Lattice lattice = (*ap).p->lattice;
352  if ( ! lattice.orthogonal() ) {
353  NAMD_die("DPMTA (FMA) only supports orthogonal PBC's.");
354  }
355  newLattice.x = lattice.a().x;
356  newLattice.y = lattice.b().y;
357  newLattice.z = lattice.c().z;
358  rescaleFactor.x = initLattice.x / newLattice.x;
359  rescaleFactor.y = initLattice.y / newLattice.y;
360  rescaleFactor.z = initLattice.z / newLattice.z;
361  DebugM(2,"Rescale factor = " << initLattice << "/" << newLattice
362  << " = " << rescaleFactor << "\n");
363  DebugM(2,"boxcenter = " << boxcenter << "\n");
364  }
365  else
366  {
367  rescaleFactor.x = 1;
368  rescaleFactor.y = 1;
369  rescaleFactor.z = 1;
370  }
371 
372  // 2. setup atom list
373  int i,j;
374  particle_list = (PmtaParticle *)calloc(totalAtoms,sizeof(PmtaParticle));
375  fmaResults = (PmtaPartInfo *)calloc(totalAtoms,sizeof(PmtaPartInfo));
376  if (!particle_list || !fmaResults)
377  {
378  NAMD_die("DPMTA Failed to allocate memory.");
379  }
380 
381  BigReal unitFactor = sqrt(COULOMB * ComputeNonbondedUtil::scaling
383  DebugM(2,"Charge unit factor = " << unitFactor << "\n");
384  for (i=0, ap = ap.begin(); ap != ap.end(); ap++)
385  {
386  CompAtom *x = (*ap).positionBox->open();
387  if ( patchList[0].p->flags.doMolly ) {
388  (*ap).positionBox->close(&x);
389  x = (*ap).avgPositionBox->open();
390  }
391 
392  // store each atom in the particle_list
393  Vector pos;
394  for(j=0; j<(*ap).p->getNumAtoms(); j++)
395  {
396  // explicitly copy -- two different data structures
397  if (usePBC)
398  {
399  particle_list[i].p.x = rescaleFactor.x * (x[j].position.x-boxcenter.x);
400  particle_list[i].p.y = rescaleFactor.y * (x[j].position.y-boxcenter.y);
401  particle_list[i].p.z = rescaleFactor.z * (x[j].position.z-boxcenter.z);
402  }
403  else
404  {
405  particle_list[i].p.x = x[j].position.x;
406  particle_list[i].p.y = x[j].position.y;
407  particle_list[i].p.z = x[j].position.z;
408  }
409  particle_list[i].q = x[j].charge * unitFactor;
410  DebugM(1,"atom[" << i << "]=" << x[j] << " "
411  << x[j].charge*unitFactor << "\n");
412  i++;
413  if (i > totalAtoms)
414  {
415  iout << iERRORF << iPE << " totalAtoms=" << totalAtoms
416  << " but " << i << " atoms are seen!\n" << endi;
417  NAMD_die("FMA: atom counts unequal!");
418  }
419  }
420 
421  if ( patchList[0].p->flags.doMolly ) { (*ap).avgPositionBox->close(&x); }
422  else { (*ap).positionBox->close(&x); }
423  }
424 
425  if (i != totalAtoms)
426  {
427  iout << iERRORF << iPE << " totalAtoms=" << totalAtoms
428  << " but " << i << " atoms are seen!\n" << endi;
429  NAMD_die("FMA: atom counts unequal!");
430  }
431 
432  DebugM(2,"DPMTA doWork() there are " << totalAtoms << " atoms in this node.\n");
433 
434 #ifdef DUMP_DPMTA
435  FILE *fp;
436  char dump_file[32];
437  sprintf(dump_file,"DUMP_DPMTA.%d",(int)CkMyPe());
438  fp = fopen(dump_file,"w");
439  int32 n32 = i;
440  fwrite(&n32,sizeof(int32),1,fp);
441  fwrite(particle_list,sizeof(PmtaParticle),i,fp);
442  fclose(fp);
443 #endif
444 
445  // 3. (run DPMTA) compute the forces
446  if ( PMTAforce(i, particle_list, fmaResults, NULL) < 0 )
447  {
448  NAMD_die("PMTAforce failed!!");
449  }
450  DebugM(2,"DPMTA forces done. Now depositing.\n");
451 
452  // 4. deposit
453  BigReal potential=0;
454  for (i=0, ap = ap.begin(); ap != ap.end(); ap++)
455  {
456  Results *r = (*ap).forceBox->open();
457  Force *f = r->f[Results::slow];
458 
459  // deposit here
460  for(j=0; j<(*ap).p->getNumAtoms(); j++)
461  {
462  if (usePBC)
463  {
464  f[j].x += fmaResults[i].f.x * rescaleFactor.x * rescaleFactor.x;
465  f[j].y += fmaResults[i].f.y * rescaleFactor.y * rescaleFactor.y;
466  f[j].z += fmaResults[i].f.z * rescaleFactor.z * rescaleFactor.z;
467  potential += fmaResults[i].v * rescaleFactor.x;
468  }
469  else
470  {
471  f[j].x += fmaResults[i].f.x;
472  f[j].y += fmaResults[i].f.y;
473  f[j].z += fmaResults[i].f.z;
474  potential += fmaResults[i].v;
475  }
476  i++;
477  }
478 
479  (*ap).forceBox->close(&r);
480  }
481 
482  potential *= 0.5;
483  DebugM(4,"Full-electrostatics energy: " << potential << "\n");
484  reduction->item(REDUCTION_ELECT_ENERGY_SLOW) += potential;
485  // DPMTA won't work correctly if scaled anisotropically anyway. -JCP
486  reduction->item(REDUCTION_VIRIAL_SLOW_XX) += potential / 3.;
487  reduction->item(REDUCTION_VIRIAL_SLOW_YY) += potential / 3.;
488  reduction->item(REDUCTION_VIRIAL_SLOW_ZZ) += potential / 3.;
489  reduction->submit();
490 
491  // 5. clean-up
492  if (totalAtoms > 0)
493  {
494  free(particle_list);
495  free(fmaResults);
496  }
497 
498  DebugM(2,"DPMTA doWork() done\n");
499 }
500 
501 #endif
502 
static Node * Object()
Definition: Node.h:86
std::ostream & iINFO(std::ostream &s)
Definition: InfoStream.C:81
void end(void)
Definition: MStream.C:176
#define ANY
Definition: Communicate.h:16
short int32
Definition: dumpdcd.c:24
int ComputeID
Definition: NamdTypes.h:183
int gridsize_c(void) const
Definition: PatchMap.h:66
static PatchMap * Object()
Definition: PatchMap.h:27
Definition: Vector.h:64
SimParameters * simParameters
Definition: Node.h:178
std::ostream & iPE(std::ostream &s)
Definition: InfoStream.C:61
#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
#define FALSE
Definition: common.h:118
Position position
Definition: NamdTypes.h:53
std::ostream & iWARN(std::ostream &s)
Definition: InfoStream.C:82
SubmitReduction * willSubmit(int setID, int size=-1)
Definition: ReductionMgr.C:365
int orthogonal() const
Definition: Lattice.h:257
MIStream * get(char &data)
Definition: MStream.h:29
static ReductionMgr * Object(void)
Definition: ReductionMgr.h:278
#define iout
Definition: InfoStream.h:51
Vector origin() const
Definition: Lattice.h:262
Charge charge
Definition: NamdTypes.h:54
#define ALL
Definition: Communicate.h:13
int gridsize_a(void) const
Definition: PatchMap.h:64
Force * f[maxNumForces]
Definition: PatchTypes.h:67
BigReal x
Definition: Vector.h:66
#define DPMTATAG
Definition: common.h:157
BigReal fmaTheta
void NAMD_die(const char *err_msg)
Definition: common.C:85
#define BUFSIZE
Definition: Communicate.h:15
#define iERRORF
Definition: DataStream.h:62
#define simParams
Definition: Output.C:127
void dummy()
virtual void initialize()
ScaledPosition origin(void) const
Definition: PatchMap.h:78
BigReal y
Definition: Vector.h:66
Vector b() const
Definition: Lattice.h:253
k< npairi;++k){TABENERGY(const int numtypes=simParams->tableNumTypes;const float table_spacing=simParams->tableSpacing;const int npertype=(int)(namdnearbyint(simParams->tableMaxDist/simParams->tableSpacing)+1);) int table_i=(r2iilist[2 *k] >> 14)+r2_delta_expc;const int j=pairlisti[k];#define p_j BigReal diffa=r2list[k]-r2_table[table_i];#define table_four_i TABENERGY(register const int tabtype=-1-(lj_pars->A< 0?lj_pars->A:0);) BigReal kqq=kq_i *p_j-> charge
BigReal patchDimension
MOStream * put(char data)
Definition: MStream.h:112
gridSize x
Vector a() const
Definition: Lattice.h:252
int gridsize_b(void) const
Definition: PatchMap.h:65
#define TRUE
Definition: common.h:119
ResizeArrayIter< T > begin(void) const
Vector c() const
Definition: Lattice.h:254
double BigReal
Definition: common.h:114